]> granicus.if.org Git - icinga2/blob - plugins/check_memory.cpp
Merge pull request #6527 from Icinga/feature/acknowledgment-notifications-6047
[icinga2] / plugins / check_memory.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/)  *
4  *                                                                            *
5  * This program is free software; you can redistribute it and/or              *
6  * modify it under the terms of the GNU General Public License                *
7  * as published by the Free Software Foundation; either version 2             *
8  * of the License, or (at your option) any later version.                     *
9  *                                                                            *
10  * This program is distributed in the hope that it will be useful,            *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
13  * GNU General Public License for more details.                               *
14  *                                                                            *
15  * You should have received a copy of the GNU General Public License          *
16  * along with this program; if not, write to the Free Software Foundation     *
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
18  ******************************************************************************/
19
20 #include "plugins/thresholds.hpp"
21 #include <boost/program_options.hpp>
22 #include <iostream>
23 #include <shlwapi.h>
24 #include <winbase.h>
25
26 #define VERSION 1.0
27
28 namespace po = boost::program_options;
29
30 struct printInfoStruct
31 {
32         threshold warn;
33         threshold crit;
34         double tRam;
35         double aRam;
36         double percentFree;
37         Bunit unit = BunitMB;
38         bool showUsed;
39 };
40
41 static bool l_Debug;
42
43 static int parseArguments(int ac, WCHAR ** av, po::variables_map& vm, printInfoStruct& printInfo)
44 {
45         WCHAR namePath[MAX_PATH];
46         GetModuleFileName(NULL, namePath, MAX_PATH);
47         WCHAR *progName = PathFindFileName(namePath);
48
49         po::options_description desc;
50
51         desc.add_options()
52                 ("help,h", "Print help message and exit")
53                 ("version,V", "Print version and exit")
54                 ("debug,d", "Verbose/Debug output")
55                 ("warning,w", po::wvalue<std::wstring>(), "Warning threshold")
56                 ("critical,c", po::wvalue<std::wstring>(), "Critical threshold")
57                 ("unit,u", po::wvalue<std::wstring>(), "The unit to use for display (default MB)")
58                 ("show-used,U", "Show used memory instead of the free memory")
59                 ;
60
61         po::wcommand_line_parser parser(ac, av);
62
63         try {
64                 po::store(
65                         parser
66                         .options(desc)
67                         .style(
68                                 po::command_line_style::unix_style |
69                                 po::command_line_style::allow_long_disguise)
70                         .run(),
71                         vm);
72                 vm.notify();
73         } catch (const std::exception& e) {
74                 std::cout << e.what() << '\n' << desc << '\n';
75                 return 3;
76         }
77
78         if (vm.count("help")) {
79                 std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n';
80                 wprintf(
81                         L"%s is a simple program to check a machines physical memory.\n"
82                         L"You can use the following options to define its behaviour:\n\n", progName);
83                 std::cout << desc;
84                 wprintf(
85                         L"\nIt will then output a string looking something like this:\n\n"
86                         L"\tMEMORY WARNING - 50%% free | memory=2024MB;3000;500;0;4096\n\n"
87                         L"\"MEMORY\" being the type of the check, \"WARNING\" the returned status\n"
88                         L"and \"50%%\" is the returned value.\n"
89                         L"The performance data is found behind the \"|\", in order:\n"
90                         L"returned value, warning threshold, critical threshold, minimal value and,\n"
91                         L"if applicable, the maximal value. Performance data will only be displayed when\n"
92                         L"you set at least one threshold\n\n"
93                         L"%s' exit codes denote the following:\n"
94                         L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n"
95                         L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
96                         L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
97                         L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n"
98                         L"Threshold syntax:\n\n"
99                         L"-w THRESHOLD\n"
100                         L"warn if threshold is broken, which means VALUE > THRESHOLD\n"
101                         L"(unless stated differently)\n\n"
102                         L"-w !THRESHOLD\n"
103                         L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n"
104                         L"-w [THR1-THR2]\n"
105                         L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n"
106                         L"-w ![THR1-THR2]\n"
107                         L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n"
108                         L"-w THRESHOLD%%\n"
109                         L"if the plugin accepts percentage based thresholds those will be used.\n"
110                         L"Does nothing if the plugin does not accept percentages, or only uses\n"
111                         L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n"
112                         L"to end with a percentage sign.\n\n"
113                         L"All of these options work with the critical threshold \"-c\" too.\n"
114                         , progName);
115                 std::cout << '\n';
116                 return 0;
117         }
118
119         if (vm.count("version"))
120                 std::wcout << L"Version: " << VERSION << '\n';
121
122         if (vm.count("warning")) {
123                 try {
124                         printInfo.warn = threshold(vm["warning"].as<std::wstring>());
125                 } catch (const std::invalid_argument& e) {
126                         std::cout << e.what() << '\n';
127                         return 3;
128                 }
129                 printInfo.warn.legal = !printInfo.warn.legal;
130         }
131
132         if (vm.count("critical")) {
133                 try {
134                         printInfo.crit = threshold(vm["critical"].as<std::wstring>());
135                 } catch (const std::invalid_argument& e) {
136                         std::cout << e.what() << '\n';
137                         return 3;
138                 }
139                 printInfo.crit.legal = !printInfo.crit.legal;
140         }
141
142         l_Debug = vm.count("debug") > 0;
143
144         if (vm.count("unit")) {
145                 try {
146                         printInfo.unit = parseBUnit(vm["unit"].as<std::wstring>());
147                 } catch (const std::invalid_argument& e) {
148                         std::cout << e.what() << '\n';
149                         return 3;
150                 }
151         }
152
153         printInfo.showUsed = vm.count("show-used") > 0;
154
155         return -1;
156 }
157
158 static int printOutput(printInfoStruct& printInfo)
159 {
160         if (l_Debug)
161                 std::wcout << L"Constructing output string" << '\n';
162
163         state state;
164
165         std::wcout << L"MEMORY ";
166
167         double currentValue;
168
169         if (!printInfo.showUsed)
170                 currentValue = printInfo.aRam;
171         else
172                 currentValue = printInfo.tRam - printInfo.aRam;
173
174         if (printInfo.warn.rend(currentValue, printInfo.tRam)) {
175                 state = WARNING;
176                 std::wcout << L"WARNING";
177         } else if (printInfo.crit.rend(currentValue, printInfo.tRam)) {
178                 state = CRITICAL;
179                 std::wcout << L"CRITICAL";
180         } else {
181                 state = OK;
182                 std::wcout << L"OK";
183         }
184
185         if (!printInfo.showUsed)
186                 std::wcout << " - " << printInfo.percentFree << L"% free";
187         else
188                 std::wcout << " - " << 100 - printInfo.percentFree << L"% used";
189
190         std::wcout << "| 'memory'=" << currentValue << BunitStr(printInfo.unit) << L";"
191                 << printInfo.warn.pString(printInfo.tRam) << L";" << printInfo.crit.pString(printInfo.tRam)
192                 << L";0;" << printInfo.tRam << '\n';
193
194         return state;
195 }
196
197 static int check_memory(printInfoStruct& printInfo)
198 {
199         if (l_Debug)
200                 std::wcout << L"Accessing memory statistics via MemoryStatus" << '\n';
201
202         MEMORYSTATUSEX memBuf;
203         memBuf.dwLength = sizeof(memBuf);
204         GlobalMemoryStatusEx(&memBuf);
205
206         printInfo.tRam = round((memBuf.ullTotalPhys / pow(1024.0, printInfo.unit) * pow(10.0, printInfo.unit))) / pow(10.0, printInfo.unit);
207         printInfo.aRam = round((memBuf.ullAvailPhys / pow(1024.0, printInfo.unit) * pow(10.0, printInfo.unit))) / pow(10.0, printInfo.unit);
208         printInfo.percentFree = 100.0 * memBuf.ullAvailPhys / memBuf.ullTotalPhys;
209
210         if (l_Debug)
211                 std::wcout << L"Found memBuf.dwTotalPhys: " << memBuf.ullTotalPhys << '\n'
212                 << L"Found memBuf.dwAvailPhys: " << memBuf.ullAvailPhys << '\n';
213
214         return -1;
215 }
216
217 int wmain(int argc, WCHAR **argv)
218 {
219         printInfoStruct printInfo = {};
220         po::variables_map vm;
221
222         int ret = parseArguments(argc, argv, vm, printInfo);
223         if (ret != -1)
224                 return ret;
225
226         ret = check_memory(printInfo);
227         if (ret != -1)
228                 return ret;
229
230         return printOutput(printInfo);
231 }