]> granicus.if.org Git - icinga2/blob - plugins/check_memory.cpp
Merge pull request #6857 from Icinga/bugfix/check_nscp_api-query-sorted-6536
[icinga2] / plugins / check_memory.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012-2018 Icinga Development Team (https://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         if (vm.count("show-used")) {
154                 printInfo.showUsed = true;
155                 printInfo.warn.legal = true;
156                 printInfo.crit.legal = true;
157         }
158
159         return -1;
160 }
161
162 static int printOutput(printInfoStruct& printInfo)
163 {
164         if (l_Debug)
165                 std::wcout << L"Constructing output string" << '\n';
166
167         state state = OK;
168
169         std::wcout << L"MEMORY ";
170
171         double currentValue;
172
173         if (!printInfo.showUsed)
174                 currentValue = printInfo.aRam;
175         else
176                 currentValue = printInfo.tRam - printInfo.aRam;
177
178         if (printInfo.warn.rend(currentValue, printInfo.tRam))
179                 state = WARNING;
180
181         if (printInfo.crit.rend(currentValue, printInfo.tRam))
182                 state = CRITICAL;
183
184         std::wcout << stateToString(state);
185
186         if (!printInfo.showUsed)
187                 std::wcout << " - " << printInfo.percentFree << L"% free";
188         else
189                 std::wcout << " - " << 100 - printInfo.percentFree << L"% used";
190
191         std::wcout << "| 'memory'=" << currentValue << BunitStr(printInfo.unit) << L";"
192                 << printInfo.warn.pString(printInfo.tRam) << L";" << printInfo.crit.pString(printInfo.tRam)
193                 << L";0;" << printInfo.tRam << '\n';
194
195         return state;
196 }
197
198 static int check_memory(printInfoStruct& printInfo)
199 {
200         if (l_Debug)
201                 std::wcout << L"Accessing memory statistics via MemoryStatus" << '\n';
202
203         MEMORYSTATUSEX memBuf;
204         memBuf.dwLength = sizeof(memBuf);
205         GlobalMemoryStatusEx(&memBuf);
206
207         printInfo.tRam = round((memBuf.ullTotalPhys / pow(1024.0, printInfo.unit) * pow(10.0, printInfo.unit))) / pow(10.0, printInfo.unit);
208         printInfo.aRam = round((memBuf.ullAvailPhys / pow(1024.0, printInfo.unit) * pow(10.0, printInfo.unit))) / pow(10.0, printInfo.unit);
209         printInfo.percentFree = 100.0 * memBuf.ullAvailPhys / memBuf.ullTotalPhys;
210
211         if (l_Debug)
212                 std::wcout << L"Found memBuf.dwTotalPhys: " << memBuf.ullTotalPhys << '\n'
213                 << L"Found memBuf.dwAvailPhys: " << memBuf.ullAvailPhys << '\n';
214
215         return -1;
216 }
217
218 int wmain(int argc, WCHAR **argv)
219 {
220         printInfoStruct printInfo = {};
221         po::variables_map vm;
222
223         int ret = parseArguments(argc, argv, vm, printInfo);
224         if (ret != -1)
225                 return ret;
226
227         ret = check_memory(printInfo);
228         if (ret != -1)
229                 return ret;
230
231         return printOutput(printInfo);
232 }