1 /******************************************************************************
3 * Copyright (C) 2012-2018 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, std::vector<std::wstring>& vecCounters)
157 LPWSTR szDataSource = NULL, szMachineName = NULL,
158 mszCounterList = NULL, mszInstanceList = NULL;
159 DWORD dwCounterListLength = 0, dwInstanceListLength = 0;
161 std::wstringstream wssInstanceName, wssCounterName;
162 LPWSTR szObjectName = new WCHAR[wsObject.length() + 1];
163 StrCpyW(szObjectName, wsObject.c_str());
166 PdhEnumObjectItems(szDataSource, szMachineName, szObjectName,
167 mszCounterList, &dwCounterListLength, mszInstanceList,
168 &dwInstanceListLength, PERF_DETAIL_WIZARD, 0);
170 if (status != PDH_MORE_DATA) {
171 delete[]szObjectName;
175 mszCounterList = new WCHAR[dwCounterListLength + 1];
176 mszInstanceList = new WCHAR[dwInstanceListLength + 1];
178 status = PdhEnumObjectItems(szDataSource, szMachineName, szObjectName,
179 mszCounterList, &dwCounterListLength, mszInstanceList,
180 &dwInstanceListLength, PERF_DETAIL_WIZARD, 0);
182 if (FAILED(status)) {
183 delete[]mszCounterList;
184 delete[]mszInstanceList;
185 delete[]szObjectName;
189 if (dwInstanceListLength) {
190 for (DWORD c = 0; c < dwInstanceListLength-1; ++c) {
191 if (mszInstanceList[c])
192 wssInstanceName << mszInstanceList[c];
194 vecInstances.push_back(wssInstanceName.str());
195 wssInstanceName.str(L"");
200 if (dwCounterListLength) {
201 for (DWORD c = 0; c < dwCounterListLength-1; ++c) {
202 if (mszCounterList[c]) {
203 wssCounterName << mszCounterList[c];
205 vecCounters.push_back(wssCounterName.str());
206 wssCounterName.str(L"");
211 delete[]mszCounterList;
212 delete[]mszInstanceList;
213 delete[]szObjectName;
220 LPWSTR szDataSource = NULL, szMachineName = NULL, mszObjectList = NULL;
221 DWORD dwBufferLength = 0;
223 PdhEnumObjects(szDataSource, szMachineName, mszObjectList,
224 &dwBufferLength, PERF_DETAIL_WIZARD, FALSE);
225 //HEX HEX! Only a Magicians gets all the info he wants, and only Microsoft knows what that means
227 if (status != PDH_MORE_DATA)
230 mszObjectList = new WCHAR[dwBufferLength + 2];
231 status = PdhEnumObjects(szDataSource, szMachineName, mszObjectList,
232 &dwBufferLength, PERF_DETAIL_WIZARD, FALSE);
239 while (++c < dwBufferLength) {
240 if (mszObjectList[c] == '\0')
243 std::wcout << mszObjectList[c];
246 delete[]mszObjectList;
250 FormatPDHError(status);
251 delete[]mszObjectList;
254 VOID PrintObjectInfo(CONST printInfoStruct& pI)
256 if (pI.wsFullPath.empty()) {
257 std::wcout << "No object given!\n";
261 std::vector<std::wstring> vecInstances, vecCounters;
263 if (!GetIntstancesAndCountersOfObject(pI.wsFullPath, vecInstances, vecCounters)) {
264 std::wcout << "Could not enumerate instances and counters of " << pI.wsFullPath << '\n'
265 << "Make sure it exists!\n";
269 std::wcout << "Instances of " << pI.wsFullPath << ":\n";
270 if (vecInstances.empty())
271 std::wcout << "> Has no instances\n";
273 for (std::vector<std::wstring>::iterator it = vecInstances.begin();
274 it != vecInstances.end(); ++it) {
275 std::wcout << "> " << *it << '\n';
278 std::wcout << std::endl;
280 std::wcout << "Performance Counters of " << pI.wsFullPath << ":\n";
281 if (vecCounters.empty())
282 std::wcout << "> Has no counters\n";
284 for (std::vector<std::wstring>::iterator it = vecCounters.begin();
285 it != vecCounters.end(); ++it) {
286 std::wcout << "> " << *it << '\n';
289 std::wcout << std::endl;
292 BOOL QueryPerfData(printInfoStruct& pI)
294 PDH_HQUERY hQuery = NULL;
295 PDH_HCOUNTER hCounter = NULL;
296 PDH_FMT_COUNTERVALUE_ITEM *pDisplayValues = NULL;
297 DWORD dwBufferSize = 0, dwItemCount = 0;
299 if (pI.wsFullPath.empty()) {
300 std::wcout << "No performance counter path given!\n";
304 PDH_STATUS status = PdhOpenQuery(NULL, NULL, &hQuery);
308 status = PdhAddCounter(hQuery, pI.wsFullPath.c_str(), NULL, &hCounter);
312 status = PdhCollectQueryData(hQuery);
317 * Most counters need two queries to provide a value.
318 * Those which need only one will return the second.
320 Sleep(pI.dwPerformanceWait);
322 status = PdhCollectQueryData(hQuery);
326 status = PdhGetFormattedCounterArray(hCounter, pI.dwRequestedType, &dwBufferSize, &dwItemCount, pDisplayValues);
327 if (status != PDH_MORE_DATA)
330 pDisplayValues = reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(new BYTE[dwBufferSize]);
331 status = PdhGetFormattedCounterArray(hCounter, pI.dwRequestedType, &dwBufferSize, &dwItemCount, pDisplayValues);
336 switch (pI.dwRequestedType)
339 pI.dValue = pDisplayValues[0].FmtValue.longValue;
341 case (PDH_FMT_LARGE):
342 pI.dValue = pDisplayValues[0].FmtValue.largeValue;
345 pI.dValue = pDisplayValues[0].FmtValue.doubleValue;
349 delete[]pDisplayValues;
354 FormatPDHError(status);
355 delete[]pDisplayValues;
359 INT PrintOutput(CONST po::variables_map& vm, printInfoStruct& pi)
361 std::wstringstream wssPerfData;
363 if (vm.count("perf-syntax")) {
364 wssPerfData << "\"" << vm["perf-syntax"].as<std::wstring>() << "\"=";
366 wssPerfData << "\"" << pi.wsFullPath << "\"=";
369 wssPerfData << pi.dValue << ';' << pi.tWarn.pString() << ';' << pi.tCrit.pString() << ";;";
371 if (pi.tCrit.rend(pi.dValue)) {
372 std::wcout << "PERFMON CRITICAL \"" << (vm.count("perf-syntax") ? vm["perf-syntax"].as<std::wstring>() : pi.wsFullPath)
373 << "\" = " << pi.dValue << " | " << wssPerfData.str() << '\n';
377 if (pi.tWarn.rend(pi.dValue)) {
378 std::wcout << "PERFMON WARNING \"" << (vm.count("perf-syntax") ? vm["perf-syntax"].as<std::wstring>() : pi.wsFullPath)
379 << "\" = " << pi.dValue << " | " << wssPerfData.str() << '\n';
383 std::wcout << "PERFMON OK \"" << (vm.count("perf-syntax") ? vm["perf-syntax"].as<std::wstring>() : pi.wsFullPath)
384 << "\" = " << pi.dValue << " | " << wssPerfData.str() << '\n';
388 VOID FormatPDHError(PDH_STATUS status)
390 HANDLE hPdhLibrary = NULL;
391 LPWSTR pMessage = NULL;
393 hPdhLibrary = LoadLibrary(L"pdh.dll");
394 if (NULL == hPdhLibrary) {
395 std::wcout << "LoadLibrary failed with " << GetLastError() << '\n';
399 if (!FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY,
400 hPdhLibrary, status, 0, (LPWSTR)&pMessage, 0, NULL)) {
401 std::wcout << "Format message failed with " << std::hex << GetLastError() << '\n';
405 std::wcout << pMessage << '\n';