]> granicus.if.org Git - icinga2/blob - plugins/check_load.cpp
Merge pull request #6527 from Icinga/feature/acknowledgment-notifications-6047
[icinga2] / plugins / check_load.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 <boost/algorithm/string/split.hpp>
23 #include <boost/algorithm/string/classification.hpp>
24 #include <iostream>
25 #include <pdh.h>
26 #include <shlwapi.h>
27 #include <pdhmsg.h>
28
29 #define VERSION 1.0
30
31 namespace po = boost::program_options;
32
33 struct printInfoStruct
34 {
35         threshold warn;
36         threshold crit;
37         double load;
38 };
39
40 static bool l_Debug;
41
42 static int parseArguments(int ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo)
43 {
44         wchar_t namePath[MAX_PATH];
45         GetModuleFileName(NULL, namePath, MAX_PATH);
46         wchar_t *progName = PathFindFileName(namePath);
47
48         po::options_description desc;
49
50         desc.add_options()
51                 ("help,h", "Print usage message and exit")
52                 ("version,V", "Print version and exit")
53                 ("debug,d", "Verbose/Debug output")
54                 ("warning,w", po::wvalue<std::wstring>(), "Warning value (in percent)")
55                 ("critical,c", po::wvalue<std::wstring>(), "Critical value (in percent)")
56                 ;
57
58         po::wcommand_line_parser parser(ac, av);
59
60         try {
61                 po::store(
62                         parser
63                         .options(desc)
64                         .style(
65                                 po::command_line_style::unix_style |
66                                 po::command_line_style::allow_long_disguise)
67                         .run(),
68                         vm);
69                 vm.notify();
70         } catch (const std::exception& e) {
71                 std::cout << e.what() << '\n' << desc << '\n';
72                 return 3;
73         }
74
75         if (vm.count("help")) {
76                 std::wcout << progName << " Help\n\tVersion: " << VERSION << '\n';
77                 wprintf(
78                         L"%s is a simple program to check a machines CPU load.\n"
79                         L"You can use the following options to define its behaviour:\n\n", progName);
80                 std::cout << desc;
81                 wprintf(
82                         L"\nIt will then output a string looking something like this:\n\n"
83                         L"\tLOAD WARNING 67%% | load=67%%;50%%;90%%;0;100\n\n"
84                         L"\"LOAD\" being the type of the check, \"WARNING\" the returned status\n"
85                         L"and \"67%%\" is the returned value.\n"
86                         L"The performance data is found behind the \"|\", in order:\n"
87                         L"returned value, warning threshold, critical threshold, minimal value and,\n"
88                         L"if applicable, the maximal value.\n\n"
89                         L"%s' exit codes denote the following:\n"
90                         L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n"
91                         L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
92                         L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
93                         L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n"
94                         L"Threshold syntax:\n\n"
95                         L"-w THRESHOLD\n"
96                         L"warn if threshold is broken, which means VALUE > THRESHOLD\n"
97                         L"(unless stated differently)\n\n"
98                         L"-w !THRESHOLD\n"
99                         L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n"
100                         L"-w [THR1-THR2]\n"
101                         L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n"
102                         L"-w ![THR1-THR2]\n"
103                         L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n"
104                         L"-w THRESHOLD%%\n"
105                         L"if the plugin accepts percentage based thresholds those will be used.\n"
106                         L"Does nothing if the plugin does not accept percentages, or only uses\n"
107                         L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n"
108                         L"to end with a percentage sign.\n\n"
109                         L"All of these options work with the critical threshold \"-c\" too."
110                         , progName);
111                 std::cout << '\n';
112                 return 0;
113         }
114
115         if (vm.count("version"))
116                 std::cout << "Version: " << VERSION << '\n';
117
118         if (vm.count("warning")) {
119                 try {
120                         std::wstring wthreshold = vm["warning"].as<std::wstring>();
121                         std::vector<std::wstring> tokens;
122                         boost::algorithm::split(tokens, wthreshold, boost::algorithm::is_any_of(","));
123                         printInfo.warn = threshold(tokens[0]);
124                 } catch (const std::invalid_argument& e) {
125                         std::cout << e.what() << '\n';
126                         return 3;
127                 }
128         }
129
130         if (vm.count("critical")) {
131                 try {
132                         std::wstring cthreshold = vm["critical"].as<std::wstring>();
133                         std::vector<std::wstring> tokens;
134                         boost::algorithm::split(tokens, cthreshold, boost::algorithm::is_any_of(","));
135                         printInfo.crit = threshold(tokens[0]);
136                 } catch (const std::invalid_argument& e) {
137                         std::cout << e.what() << '\n';
138                         return 3;
139                 }
140         }
141
142         l_Debug = vm.count("debug") > 0;
143
144         return -1;
145 }
146
147 static int printOutput(printInfoStruct& printInfo)
148 {
149         if (l_Debug)
150                 std::wcout << L"Constructing output string" << '\n';
151
152         state state = OK;
153
154         if (printInfo.warn.rend(printInfo.load))
155                 state = WARNING;
156
157         if (printInfo.crit.rend(printInfo.load))
158                 state = CRITICAL;
159
160         std::wcout << L"LOAD ";
161
162         switch (state) {
163         case OK:
164                 std::wcout << L"OK";
165                 break;
166         case WARNING:
167                 std::wcout << L"WARNING";
168                 break;
169         case CRITICAL:
170                 std::wcout << L"CRITICAL";
171                 break;
172         }
173
174         std::wcout << " " << printInfo.load << L"% | 'load'=" << printInfo.load << L"%;"
175                 << printInfo.warn.pString() << L";"
176                 << printInfo.crit.pString() << L";0;100" << '\n';
177
178         return state;
179 }
180
181 static int check_load(printInfoStruct& printInfo)
182 {
183         if (l_Debug)
184                 std::wcout << L"Creating query and adding counter" << '\n';
185
186         PDH_HQUERY phQuery;
187         PDH_STATUS err = PdhOpenQuery(NULL, NULL, &phQuery);
188         if (!SUCCEEDED(err))
189                 goto die;
190
191         PDH_HCOUNTER phCounter;
192         err = PdhAddEnglishCounter(phQuery, L"\\Processor(_Total)\\% Idle Time", NULL, &phCounter);
193         if (!SUCCEEDED(err))
194                 goto die;
195
196         if (l_Debug)
197                 std::wcout << L"Collecting first batch of query data" << '\n';
198
199         err = PdhCollectQueryData(phQuery);
200         if (!SUCCEEDED(err))
201                 goto die;
202
203         if (l_Debug)
204                 std::wcout << L"Sleep for one second" << '\n';
205
206         Sleep(1000);
207
208         if (l_Debug)
209                 std::wcout << L"Collecting second batch of query data" << '\n';
210
211         err = PdhCollectQueryData(phQuery);
212         if (!SUCCEEDED(err))
213                 goto die;
214
215         if (l_Debug)
216                 std::wcout << L"Creating formatted counter array" << '\n';
217
218         DWORD CounterType;
219         PDH_FMT_COUNTERVALUE DisplayValue;
220         err = PdhGetFormattedCounterValue(phCounter, PDH_FMT_DOUBLE, &CounterType, &DisplayValue);
221         if (SUCCEEDED(err)) {
222                 if (DisplayValue.CStatus == PDH_CSTATUS_VALID_DATA) {
223                         if (l_Debug)
224                                 std::wcout << L"Recieved Value of " << DisplayValue.doubleValue << L" (idle)" << '\n';
225                         printInfo.load = 100.0 - DisplayValue.doubleValue;
226                 }
227                 else {
228                         if (l_Debug)
229                                 std::wcout << L"Received data was not valid\n";
230                         goto die;
231                 }
232
233                 if (l_Debug)
234                         std::wcout << L"Finished collection. Cleaning up and returning" << '\n';
235
236                 PdhCloseQuery(phQuery);
237                 return -1;
238         }
239
240 die:
241         printErrorInfo();
242         if (phQuery)
243                 PdhCloseQuery(phQuery);
244         return 3;
245 }
246
247 int wmain(int argc, WCHAR **argv)
248 {
249         printInfoStruct printInfo;
250         po::variables_map vm;
251
252         int ret = parseArguments(argc, argv, vm, printInfo);
253         if (ret != -1)
254                 return ret;
255
256         ret = check_load(printInfo);
257         if (ret != -1)
258                 return ret;
259
260         return printOutput(printInfo);
261 }