]> granicus.if.org Git - icinga2/blob - plugins/check_load.cpp
Make check plugins decent
[icinga2] / plugins / check_load.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org)    *
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 #include <Pdh.h>
20 #include <Shlwapi.h>
21 #include <pdhmsg.h>
22 #include <iostream>
23
24 #include "thresholds.h"
25
26 #include "boost\program_options.hpp"
27
28 #define VERSION 1.0
29
30 namespace po = boost::program_options;
31
32 using std::endl; using std::cout; using std::wstring;
33 using std::wcout;
34
35 struct printInfoStruct 
36 {
37         threshold warn, crit;
38         double load;
39 };
40
41 static int parseArguments(int, wchar_t **, po::variables_map&, printInfoStruct&);
42 static int printOutput(printInfoStruct&);
43 static int check_load(printInfoStruct&);
44
45 int wmain(int argc, wchar_t **argv) 
46 {
47         printInfoStruct printInfo{ };
48         po::variables_map vm;
49
50         int ret = parseArguments(argc, argv, vm, printInfo);
51         if (ret != -1)
52                 return ret;
53
54         ret = check_load(printInfo);
55         if (ret != -1)
56                 return ret;
57
58         printOutput(printInfo);
59         return 1;
60 }
61
62 int parseArguments(int ac, wchar_t **av, po::variables_map& vm, printInfoStruct& printInfo) {
63         wchar_t namePath[MAX_PATH];
64         GetModuleFileName(NULL, namePath, MAX_PATH);
65         wchar_t *progName = PathFindFileName(namePath);
66
67         po::options_description desc;
68
69         desc.add_options()
70                 (",h", "print usage message and exit")
71                 ("help", "print help message and exit")
72                 ("version,v", "print version and exit")
73                 ("warning,w", po::wvalue<wstring>(), "warning value (in percent)")
74                 ("critical,c", po::wvalue<wstring>(), "critical value (in percent)")
75                 ;
76
77         po::basic_command_line_parser<wchar_t> parser(ac, av);
78
79         try {
80                 po::store(
81                         parser
82                         .options(desc)
83                         .style(
84                         po::command_line_style::unix_style |
85                         po::command_line_style::allow_long_disguise)
86                         .run(),
87                         vm);
88                 vm.notify();
89         } catch (std::exception& e) {
90                 cout << e.what() << endl << desc << endl;
91                 return 3;
92         }
93
94         if (vm.count("h")) {
95                 cout << desc << endl;
96                 return 0;
97         }
98
99         if (vm.count("help")) {
100                 wcout << progName << " Help\n\tVersion: " << VERSION << endl;
101                 wprintf(
102                         L"%s is a simple program to check a machines CPU load.\n"
103                         L"You can use the following options to define its behaviour:\n\n", progName);
104                 cout << desc;
105                 wprintf(
106                         L"\nIt will then output a string looking something like this:\n\n"
107                         L"\tLOAD WARNING 67%%|load=67%%;50%%;90%%;0;100\n\n"
108                         L"\"LOAD\" being the type of the check, \"WARNING\" the returned status\n"
109                         L"and \"67%%\" is the returned value.\n"
110                         L"The performance data is found behind the \"|\", in order:\n"
111                         L"returned value, warning threshold, critical threshold, minimal value and,\n"
112                         L"if applicable, the maximal value. Performance data will only be displayed when\n"
113                         L"you set at least one threshold\n\n"
114                         L"%s' exit codes denote the following:\n"
115                         L" 0\tOK,\n\tNo Thresholds were broken or the programs check part was not executed\n"
116                         L" 1\tWARNING,\n\tThe warning, but not the critical threshold was broken\n"
117                         L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
118                         L" 3\tUNKNOWN, \n\tThe program experienced an internal or input error\n\n"
119                         L"Threshold syntax:\n\n"
120                         L"-w THRESHOLD\n"
121                         L"warn if threshold is broken, which means VALUE > THRESHOLD\n"
122                         L"(unless stated differently)\n\n"
123                         L"-w !THRESHOLD\n"
124                         L"inverts threshold check, VALUE < THRESHOLD (analogous to above)\n\n"
125                         L"-w [THR1-THR2]\n"
126                         L"warn is VALUE is inside the range spanned by THR1 and THR2\n\n"
127                         L"-w ![THR1-THR2]\n"
128                         L"warn if VALUE is outside the range spanned by THR1 and THR2\n\n"
129                         L"-w THRESHOLD%%\n"
130                         L"if the plugin accepts percentage based thresholds those will be used.\n"
131                         L"Does nothing if the plugin does not accept percentages, or only uses\n"
132                         L"percentage thresholds. Ranges can be used with \"%%\", but both range values need\n"
133                         L"to end with a percentage sign.\n\n"
134                         L"All of these options work with the critical threshold \"-c\" too."
135                         , progName);
136                 cout << endl;
137                 return 0;
138         }
139
140         if (vm.count("version"))
141                 cout << "Version: " << VERSION << endl;
142
143         if (vm.count("warning")) 
144                 printInfo.warn = parse(vm["warning"].as<wstring>());
145
146         if (vm.count("critical"))
147                 printInfo.crit = parse(vm["critical"].as<wstring>());
148
149         return -1;
150 }
151
152 int printOutput(printInfoStruct& printInfo) 
153 {
154         state state = OK;
155         
156         if (!printInfo.warn.set && !printInfo.crit.set) {
157                 wcout << L"LOAD OK " << printInfo.load << L"%" << endl;
158         }
159
160         if (printInfo.warn.rend(printInfo.load))
161                 state = WARNING;
162
163         if (printInfo.crit.rend(printInfo.load))
164                 state = CRITICAL;
165
166         std::wstringstream perf;
167         perf << L"%|load=" << printInfo.load << L"%;" << printInfo.warn.pString() << L";" 
168                 << printInfo.crit.pString() << L";0;100" << endl;
169
170         switch (state) {
171         case OK:
172                 wcout << L"LOAD OK " << printInfo.load << perf.str();
173                 break;
174         case WARNING:
175                 wcout << L"LOAD WARNING " << printInfo.load << perf.str();
176                 break;
177         case CRITICAL:
178                 wcout << L"LOAD CRITICAL " << printInfo.load << perf.str();
179                 break;
180         }
181
182         return state;
183 }
184
185 int check_load(printInfoStruct& printInfo) 
186 {
187         PDH_HQUERY phQuery;
188         PDH_HCOUNTER phCounter;
189         DWORD dwBufferSize = 0;
190         DWORD CounterType;
191         PDH_FMT_COUNTERVALUE DisplayValue;
192
193         LPCWSTR path = L"\\Processor(_Total)\\% Idle Time";
194
195         if (PdhOpenQuery(NULL, NULL, &phQuery) != ERROR_SUCCESS)
196                 goto cleanup;
197
198         if (PdhAddEnglishCounter(phQuery, path, NULL, &phCounter) != ERROR_SUCCESS)
199                 goto cleanup;
200
201         if (PdhCollectQueryData(phQuery) != ERROR_SUCCESS)
202                 goto cleanup;
203
204         Sleep(1000);
205
206         if (PdhCollectQueryData(phQuery) != ERROR_SUCCESS)
207                 goto cleanup;
208
209         if (PdhGetFormattedCounterValue(phCounter, PDH_FMT_DOUBLE, &CounterType, &DisplayValue) == ERROR_SUCCESS) {
210                 if (DisplayValue.CStatus == PDH_CSTATUS_VALID_DATA)
211                         printInfo.load = 100.0 - DisplayValue.doubleValue;
212                 PdhCloseQuery(phQuery);
213                 return -1;
214         }
215
216 cleanup:
217         if (phQuery)
218                 PdhCloseQuery(phQuery);
219         return 3;
220 }