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