1 /******************************************************************************
3 * Copyright (C) 2012-2018 Icinga Development Team (https://icinga.com/) *
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. *
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. *
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 ******************************************************************************/
20 #include "plugins/thresholds.hpp"
21 #include <boost/program_options.hpp>
31 namespace po = boost::program_options;
33 struct printInfoStruct
37 std::wstring wsFullPath;
39 DWORD dwPerformanceWait = 1000;
40 DWORD dwRequestedType = PDH_FMT_DOUBLE;
43 static bool parseArguments(const int ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo)
45 WCHAR szNamePath[MAX_PATH + 1];
46 GetModuleFileName(NULL, szNamePath, MAX_PATH);
47 WCHAR *szProgName = PathFindFileName(szNamePath);
49 po::options_description desc("Options");
51 ("help,h", "Print help page and exit")
52 ("version,V", "Print version and exit")
53 ("warning,w", po::wvalue<std::wstring>(), "Warning thershold")
54 ("critical,c", po::wvalue<std::wstring>(), "Critical threshold")
55 ("performance-counter,P", po::wvalue<std::wstring>(), "The performance counter string to use")
56 ("performance-wait", po::value<DWORD>(), "Sleep in milliseconds between the two perfomance querries (Default: 1000ms)")
57 ("fmt-countertype", po::wvalue<std::wstring>(), "Value type of counter: 'double'(default), 'long', 'int64'")
58 ("print-objects", "Prints all available objects to console")
59 ("print-object-info", "Prints all available instances and counters of --performance-counter, do not use a full perfomance counter string here")
60 ("perf-syntax", po::wvalue<std::wstring>(), "Use this string as name for the performance counter (graphite compatibility)")
63 po::wcommand_line_parser parser(ac, av);
70 po::command_line_style::unix_style |
71 po::command_line_style::allow_long_disguise)
75 } catch (const std::exception& e) {
76 std::cout << e.what() << '\n' << desc << '\n';
80 if (vm.count("version")) {
81 std::wcout << "Version: " << VERSION << '\n';
85 if (vm.count("help")) {
86 std::wcout << szProgName << " Help\n\tVersion: " << VERSION << '\n';
88 L"%s runs a check against a performance counter.\n"
89 L"You can use the following options to define its behaviour:\n\n", szProgName);
92 L"\nIt will then output a string looking something like this:\n\n"
93 L"\tPERFMON CRITICAL \"\\Processor(_Total)\\%% Idle Time\" = 40.34 | "
94 L"perfmon=40.34;20;40;; \"\\Processor(_Total)\\%% Idle Time\"=40.34\n\n"
95 L"\"tPERFMON\" being the type of the check, \"CRITICAL\" the returned status\n"
96 L"and \"40.34\" is the performance counters value.\n"
97 L"%s' exit codes denote the following:\n"
98 L" 0\tOK,\n\tNo Thresholds were exceeded\n"
99 L" 1\tWARNING,\n\tThe warning was broken, but not the critical threshold\n"
100 L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
101 L" 3\tUNKNOWN, \n\tNo check could be performed\n\n"
106 if (vm.count("warning")) {
108 printInfo.tWarn = threshold(vm["warning"].as<std::wstring>());
109 } catch (const std::invalid_argument& e) {
110 std::wcout << e.what() << '\n';
115 if (vm.count("critical")) {
117 printInfo.tCrit = threshold(vm["critical"].as<std::wstring>());
118 } catch (const std::invalid_argument& e) {
119 std::wcout << e.what() << '\n';
124 if (vm.count("fmt-countertype")) {
125 if (!vm["fmt-countertype"].as<std::wstring>().compare(L"int64"))
126 printInfo.dwRequestedType = PDH_FMT_LARGE;
127 else if (!vm["fmt-countertype"].as<std::wstring>().compare(L"long"))
128 printInfo.dwRequestedType = PDH_FMT_LONG;
129 else if (vm["fmt-countertype"].as<std::wstring>().compare(L"double")) {
130 std::wcout << "Unknown value type " << vm["fmt-countertype"].as<std::wstring>() << '\n';
135 if (vm.count("performance-counter"))
136 printInfo.wsFullPath = vm["performance-counter"].as<std::wstring>();
138 if (vm.count("performance-wait"))
139 printInfo.dwPerformanceWait = vm["performance-wait"].as<DWORD>();
144 static bool getInstancesAndCountersOfObject(const std::wstring& wsObject,
145 std::vector<std::wstring>& vecInstances, std::vector<std::wstring>& vecCounters)
147 DWORD dwCounterListLength = 0, dwInstanceListLength = 0;
149 if (PdhEnumObjectItems(NULL, NULL, wsObject.c_str(),
150 NULL, &dwCounterListLength, NULL,
151 &dwInstanceListLength, PERF_DETAIL_WIZARD, 0) != PDH_MORE_DATA)
154 std::vector<WCHAR> mszCounterList(dwCounterListLength + 1);
155 std::vector<WCHAR> mszInstanceList(dwInstanceListLength + 1);
157 if (FAILED(PdhEnumObjectItems(NULL, NULL, wsObject.c_str(),
158 mszCounterList.data(), &dwCounterListLength, mszInstanceList.data(),
159 &dwInstanceListLength, PERF_DETAIL_WIZARD, 0))) {
163 if (dwInstanceListLength) {
164 std::wstringstream wssInstanceName;
166 // XXX: is the "- 1" correct?
167 for (DWORD c = 0; c < dwInstanceListLength - 1; ++c) {
168 if (mszInstanceList[c])
169 wssInstanceName << mszInstanceList[c];
171 vecInstances.push_back(wssInstanceName.str());
172 wssInstanceName.str(L"");
177 if (dwCounterListLength) {
178 std::wstringstream wssCounterName;
180 // XXX: is the "- 1" correct?
181 for (DWORD c = 0; c < dwCounterListLength - 1; ++c) {
182 if (mszCounterList[c])
183 wssCounterName << mszCounterList[c];
185 vecCounters.push_back(wssCounterName.str());
186 wssCounterName.str(L"");
194 static void printPDHError(PDH_STATUS status)
196 HMODULE hPdhLibrary = NULL;
197 LPWSTR pMessage = NULL;
199 hPdhLibrary = LoadLibrary(L"pdh.dll");
201 std::wcout << "LoadLibrary failed with " << GetLastError() << '\n';
205 if (!FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY,
206 hPdhLibrary, status, 0, (LPWSTR)&pMessage, 0, NULL)) {
207 FreeLibrary(hPdhLibrary);
208 std::wcout << "Format message failed with " << std::hex << GetLastError() << '\n';
212 FreeLibrary(hPdhLibrary);
214 std::wcout << pMessage << '\n';
218 static void printObjects()
220 DWORD dwBufferLength = 0;
221 PDH_STATUS status = PdhEnumObjects(NULL, NULL, NULL,
222 &dwBufferLength, PERF_DETAIL_WIZARD, FALSE);
223 //HEX HEX! Only a Magicians gets all the info he wants, and only Microsoft knows what that means
225 if (status != PDH_MORE_DATA) {
226 printPDHError(status);
230 std::vector<WCHAR> mszObjectList(dwBufferLength + 2);
231 status = PdhEnumObjects(NULL, NULL, mszObjectList.data(),
232 &dwBufferLength, PERF_DETAIL_WIZARD, FALSE);
234 if (FAILED(status)) {
235 printPDHError(status);
241 while (++c < dwBufferLength) {
242 if (mszObjectList[c] == '\0')
245 std::wcout << mszObjectList[c];
249 static void printObjectInfo(const printInfoStruct& pI)
251 if (pI.wsFullPath.empty()) {
252 std::wcout << "No object given!\n";
256 std::vector<std::wstring> vecInstances, vecCounters;
258 if (!getInstancesAndCountersOfObject(pI.wsFullPath, vecInstances, vecCounters)) {
259 std::wcout << "Could not enumerate instances and counters of " << pI.wsFullPath << '\n'
260 << "Make sure it exists!\n";
264 std::wcout << "Instances of " << pI.wsFullPath << ":\n";
265 if (vecInstances.empty())
266 std::wcout << "> Has no instances\n";
268 for (const auto& instance : vecInstances)
269 std::wcout << "> " << instance << '\n';
271 std::wcout << std::endl;
273 std::wcout << "Performance Counters of " << pI.wsFullPath << ":\n";
274 if (vecCounters.empty())
275 std::wcout << "> Has no counters\n";
277 for (const auto& counter : vecCounters)
278 std::wcout << "> " << counter << "\n";
280 std::wcout << std::endl;
283 bool QueryPerfData(printInfoStruct& pI)
285 PDH_HQUERY hQuery = NULL;
286 PDH_HCOUNTER hCounter = NULL;
287 DWORD dwBufferSize = 0, dwItemCount = 0;
289 if (pI.wsFullPath.empty()) {
290 std::wcout << "No performance counter path given!\n";
294 PDH_FMT_COUNTERVALUE_ITEM *pDisplayValues = NULL;
296 PDH_STATUS status = PdhOpenQuery(NULL, NULL, &hQuery);
300 status = PdhAddEnglishCounter(hQuery, pI.wsFullPath.c_str(), NULL, &hCounter);
303 status = PdhAddCounter(hQuery, pI.wsFullPath.c_str(), NULL, &hCounter);
308 status = PdhCollectQueryData(hQuery);
313 * Most counters need two queries to provide a value.
314 * Those which need only one will return the second.
316 Sleep(pI.dwPerformanceWait);
318 status = PdhCollectQueryData(hQuery);
322 status = PdhGetFormattedCounterArray(hCounter, pI.dwRequestedType, &dwBufferSize, &dwItemCount, NULL);
323 if (status != PDH_MORE_DATA)
326 pDisplayValues = reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(new BYTE[dwBufferSize]);
327 status = PdhGetFormattedCounterArray(hCounter, pI.dwRequestedType, &dwBufferSize, &dwItemCount, pDisplayValues);
332 switch (pI.dwRequestedType) {
334 pI.dValue = pDisplayValues[0].FmtValue.longValue;
336 case (PDH_FMT_LARGE):
337 pI.dValue = pDisplayValues[0].FmtValue.largeValue;
340 pI.dValue = pDisplayValues[0].FmtValue.doubleValue;
344 delete[]pDisplayValues;
349 printPDHError(status);
350 delete[]pDisplayValues;
354 static int printOutput(const po::variables_map& vm, printInfoStruct& pi)
356 std::wstringstream wssPerfData;
358 if (vm.count("perf-syntax"))
359 wssPerfData << "'" << vm["perf-syntax"].as<std::wstring>() << "'=";
361 wssPerfData << "'" << pi.wsFullPath << "'=";
363 wssPerfData << pi.dValue << ';' << pi.tWarn.pString() << ';' << pi.tCrit.pString() << ";;";
365 if (pi.tCrit.rend(pi.dValue)) {
366 std::wcout << "PERFMON CRITICAL for '" << (vm.count("perf-syntax") ? vm["perf-syntax"].as<std::wstring>() : pi.wsFullPath)
367 << "' = " << pi.dValue << " | " << wssPerfData.str() << "\n";
371 if (pi.tWarn.rend(pi.dValue)) {
372 std::wcout << "PERFMON WARNING for '" << (vm.count("perf-syntax") ? vm["perf-syntax"].as<std::wstring>() : pi.wsFullPath)
373 << "' = " << pi.dValue << " | " << wssPerfData.str() << "\n";
377 std::wcout << "PERFMON OK for '" << (vm.count("perf-syntax") ? vm["perf-syntax"].as<std::wstring>() : pi.wsFullPath)
378 << "' = " << pi.dValue << " | " << wssPerfData.str() << "\n";
383 int wmain(int argc, WCHAR **argv)
385 po::variables_map variables_map;
386 printInfoStruct stPrintInfo;
387 if (!parseArguments(argc, argv, variables_map, stPrintInfo))
390 if (variables_map.count("print-objects")) {
395 if (variables_map.count("print-object-info")) {
396 printObjectInfo(stPrintInfo);
400 if (QueryPerfData(stPrintInfo))
401 return printOutput(variables_map, stPrintInfo);