1 /******************************************************************************
3 * Copyright (C) 2012-2017 Icinga Development Team (https://www.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 ******************************************************************************/
24 #include "check_perfmon.h"
28 namespace po = boost::program_options;
30 INT wmain(INT argc, WCHAR **argv)
32 po::variables_map variables_map;
33 printInfoStruct stPrintInfo;
34 if (!ParseArguments(argc, argv, variables_map, stPrintInfo))
37 if (variables_map.count("print-objects")) {
42 if (variables_map.count("print-object-info")) {
43 PrintObjectInfo(stPrintInfo);
47 if (QueryPerfData(stPrintInfo))
48 return PrintOutput(variables_map, stPrintInfo);
53 BOOL ParseArguments(CONST INT ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo)
55 WCHAR szNamePath[MAX_PATH + 1];
56 GetModuleFileName(NULL, szNamePath, MAX_PATH);
57 WCHAR *szProgName = PathFindFileName(szNamePath);
59 po::options_description desc("Options");
61 ("help,h", "Print help page and exit")
62 ("version,V", "Print version and exit")
63 ("warning,w", po::wvalue<std::wstring>(), "Warning thershold")
64 ("critical,c", po::wvalue<std::wstring>(), "Critical threshold")
65 ("performance-counter,P", po::wvalue<std::wstring>(), "The performance counter string to use")
66 ("performance-wait", po::value<DWORD>(), "Sleep in milliseconds between the two perfomance querries (Default: 1000ms)")
67 ("fmt-countertype", po::wvalue<std::wstring>(), "Value type of counter: 'double'(default), 'long', 'int64'")
68 ("print-objects", "Prints all available objects to console")
69 ("print-object-info", "Prints all available instances and counters of --performance-counter, do not use a full perfomance counter string here")
70 ("perf-syntax", po::wvalue<std::wstring>(), "Use this string as name for the performance counter (graphite compatibility)")
73 po::basic_command_line_parser<wchar_t> parser(ac, av);
80 po::command_line_style::unix_style |
81 po::command_line_style::allow_long_disguise)
85 } catch (std::exception& e) {
86 std::cout << e.what() << '\n' << desc << '\n';
90 if (vm.count("version")) {
91 std::wcout << "Version: " << VERSION << '\n';
95 if (vm.count("help")) {
96 std::wcout << szProgName << " Help\n\tVersion: " << VERSION << '\n';
98 L"%s runs a check against a performance counter.\n"
99 L"You can use the following options to define its behaviour:\n\n", szProgName);
102 L"\nIt will then output a string looking something like this:\n\n"
103 L"\tPERFMON CRITICAL \"\\Processor(_Total)\\%% Idle Time\" = 40.34 | "
104 L"perfmon=40.34;20;40;; \"\\Processor(_Total)\\%% Idle Time\"=40.34\n\n"
105 L"\"tPERFMON\" being the type of the check, \"CRITICAL\" the returned status\n"
106 L"and \"40.34\" is the performance counters value.\n"
107 L"%s' exit codes denote the following:\n"
108 L" 0\tOK,\n\tNo Thresholds were exceeded\n"
109 L" 1\tWARNING,\n\tThe warning was broken, but not the critical threshold\n"
110 L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
111 L" 3\tUNKNOWN, \n\tNo check could be performed\n\n"
116 if (vm.count("warning")) {
118 printInfo.tWarn = threshold(vm["warning"].as<std::wstring>());
119 } catch (std::invalid_argument& e) {
120 std::wcout << e.what() << '\n';
125 if (vm.count("critical")) {
127 printInfo.tCrit = threshold(vm["critical"].as<std::wstring>());
128 } catch (std::invalid_argument& e) {
129 std::wcout << e.what() << '\n';
134 if (vm.count("fmt-countertype")) {
135 if (!vm["fmt-countertype"].as<std::wstring>().compare(L"int64"))
136 printInfo.dwRequestedType = PDH_FMT_LARGE;
137 else if (!vm["fmt-countertype"].as<std::wstring>().compare(L"long"))
138 printInfo.dwRequestedType = PDH_FMT_LONG;
139 else if (vm["fmt-countertype"].as<std::wstring>().compare(L"double")) {
140 std::wcout << "Unknown value type " << vm["fmt-countertype"].as<std::wstring>() << '\n';
145 if (vm.count("performance-counter"))
146 printInfo.wsFullPath = vm["performance-counter"].as<std::wstring>();
148 if (vm.count("performance-wait"))
149 printInfo.dwPerformanceWait = vm["performance-wait"].as<DWORD>();
154 BOOL GetIntstancesAndCountersOfObject(CONST std::wstring wsObject,
155 std::vector<std::wstring>& vecInstances,
156 std::vector<std::wstring>& vecCounters)
158 LPWSTR szDataSource = NULL, szMachineName = NULL,
159 mszCounterList = NULL, mszInstanceList = NULL;
160 DWORD dwCounterListLength = 0, dwInstanceListLength = 0;
162 std::wstringstream wssInstanceName, wssCounterName;
163 LPWSTR szObjectName = new WCHAR[wsObject.length() + 1];
164 StrCpyW(szObjectName, wsObject.c_str());
167 PdhEnumObjectItems(szDataSource, szMachineName, szObjectName,
168 mszCounterList, &dwCounterListLength, mszInstanceList,
169 &dwInstanceListLength, PERF_DETAIL_WIZARD, 0);
171 if (status != PDH_MORE_DATA) {
172 delete[]szObjectName;
176 mszCounterList = new WCHAR[dwCounterListLength + 1];
177 mszInstanceList = new WCHAR[dwInstanceListLength + 1];
179 status = PdhEnumObjectItems(szDataSource, szMachineName, szObjectName,
180 mszCounterList, &dwCounterListLength, mszInstanceList,
181 &dwInstanceListLength, PERF_DETAIL_WIZARD, 0);
183 if (FAILED(status)) {
184 delete[]mszCounterList;
185 delete[]mszInstanceList;
186 delete[]szObjectName;
190 if (dwInstanceListLength) {
191 for (DWORD c = 0; c < dwInstanceListLength-1; ++c) {
192 if (mszInstanceList[c])
193 wssInstanceName << mszInstanceList[c];
195 vecInstances.push_back(wssInstanceName.str());
196 wssInstanceName.str(L"");
201 if (dwCounterListLength) {
202 for (DWORD c = 0; c < dwCounterListLength-1; ++c) {
203 if (mszCounterList[c]) {
204 wssCounterName << mszCounterList[c];
206 vecCounters.push_back(wssCounterName.str());
207 wssCounterName.str(L"");
212 delete[]mszCounterList;
213 delete[]mszInstanceList;
214 delete[]szObjectName;
221 LPWSTR szDataSource = NULL, szMachineName = NULL, mszObjectList = NULL;
222 DWORD dwBufferLength = 0;
224 PdhEnumObjects(szDataSource, szMachineName, mszObjectList,
225 &dwBufferLength, PERF_DETAIL_WIZARD, FALSE);
226 //HEX HEX! Only a Magicians gets all the info he wants, and only Microsoft knows what that means
228 if (status != PDH_MORE_DATA)
231 mszObjectList = new WCHAR[dwBufferLength + 2];
232 status = PdhEnumObjects(szDataSource, szMachineName, mszObjectList,
233 &dwBufferLength, PERF_DETAIL_WIZARD, FALSE);
240 while (++c < dwBufferLength) {
241 if (mszObjectList[c] == '\0')
244 std::wcout << mszObjectList[c];
247 delete[]mszObjectList;
251 FormatPDHError(status);
252 delete[]mszObjectList;
255 VOID PrintObjectInfo(CONST printInfoStruct& pI)
257 if (pI.wsFullPath.empty()) {
258 std::wcout << "No object given!\n";
262 std::vector<std::wstring> vecInstances, vecCounters;
264 if (!GetIntstancesAndCountersOfObject(pI.wsFullPath, vecInstances, vecCounters)) {
265 std::wcout << "Could not enumerate instances and counters of " << pI.wsFullPath << '\n'
266 << "Make sure it exists!\n";
270 std::wcout << "Instances of " << pI.wsFullPath << ":\n";
271 if (vecInstances.empty())
272 std::wcout << "> Has no instances\n";
274 for (std::vector<std::wstring>::iterator it = vecInstances.begin();
275 it != vecInstances.end(); ++it) {
276 std::wcout << "> " << *it << '\n';
279 std::wcout << std::endl;
281 std::wcout << "Performance Counters of " << pI.wsFullPath << ":\n";
282 if (vecCounters.empty())
283 std::wcout << "> Has no counters\n";
285 for (std::vector<std::wstring>::iterator it = vecCounters.begin();
286 it != vecCounters.end(); ++it) {
287 std::wcout << "> " << *it << '\n';
290 std::wcout << std::endl;
293 BOOL QueryPerfData(printInfoStruct& pI)
295 PDH_HQUERY hQuery = NULL;
296 PDH_HCOUNTER hCounter = NULL;
297 PDH_FMT_COUNTERVALUE_ITEM *pDisplayValues = NULL;
298 DWORD dwBufferSize = 0, dwItemCount = 0;
300 if (pI.wsFullPath.empty()) {
301 std::wcout << "No performance counter path given!\n";
305 PDH_STATUS status = PdhOpenQuery(NULL, NULL, &hQuery);
309 status = PdhAddCounter(hQuery, pI.wsFullPath.c_str(), NULL, &hCounter);
313 status = PdhCollectQueryData(hQuery);
318 /* Most counters need two queries to provide a value.
319 /* Those which need only one will return the second.
321 Sleep(pI.dwPerformanceWait);
323 status = PdhCollectQueryData(hQuery);
327 status = PdhGetFormattedCounterArray(hCounter, pI.dwRequestedType,
328 &dwBufferSize, &dwItemCount, pDisplayValues);
329 if (status != PDH_MORE_DATA)
332 pDisplayValues = reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(new BYTE[dwBufferSize]);
333 status = PdhGetFormattedCounterArray(hCounter, pI.dwRequestedType,
334 &dwBufferSize, &dwItemCount, pDisplayValues);
339 switch (pI.dwRequestedType)
342 pI.dValue = pDisplayValues[0].FmtValue.longValue;
344 case (PDH_FMT_LARGE):
345 pI.dValue = pDisplayValues[0].FmtValue.largeValue;
348 pI.dValue = pDisplayValues[0].FmtValue.doubleValue;
352 delete[]pDisplayValues;
357 FormatPDHError(status);
358 delete[]pDisplayValues;
362 INT PrintOutput(CONST po::variables_map& vm, printInfoStruct& pi)
364 std::wstringstream wssPerfData;
366 if (vm.count("perf-syntax")) {
367 wssPerfData << "\"" << vm["perf-syntax"].as<std::wstring>() << "\"=";
369 wssPerfData << "\"" << pi.wsFullPath << "\"=";
372 wssPerfData << pi.dValue << ';' << pi.tWarn.pString() << ';' << pi.tCrit.pString() << ";;";
374 if (pi.tCrit.rend(pi.dValue)) {
375 std::wcout << "PERFMON CRITICAL \"" << (vm.count("perf-syntax") ? vm["perf-syntax"].as<std::wstring>() : pi.wsFullPath)
376 << "\" = " << pi.dValue << " | " << wssPerfData.str() << '\n';
380 if (pi.tWarn.rend(pi.dValue)) {
381 std::wcout << "PERFMON WARNING \"" << (vm.count("perf-syntax") ? vm["perf-syntax"].as<std::wstring>() : pi.wsFullPath)
382 << "\" = " << pi.dValue << " | " << wssPerfData.str() << '\n';
386 std::wcout << "PERFMON OK \"" << (vm.count("perf-syntax") ? vm["perf-syntax"].as<std::wstring>() : pi.wsFullPath)
387 << "\" = " << pi.dValue << " | " << wssPerfData.str() << '\n';
391 VOID FormatPDHError(PDH_STATUS status)
393 HANDLE hPdhLibrary = NULL;
394 LPWSTR pMessage = NULL;
396 hPdhLibrary = LoadLibrary(L"pdh.dll");
397 if (NULL == hPdhLibrary) {
398 std::wcout << "LoadLibrary failed with " << GetLastError() << '\n';
402 if (!FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY,
403 hPdhLibrary, status, 0, (LPWSTR)&pMessage, 0, NULL)) {
404 std::wcout << "Format message failed with " << std::hex << GetLastError() << '\n';
408 std::wcout << pMessage << '\n';