1 /******************************************************************************
3 * Copyright (C) 2012-2016 Icinga Development Team (https://www.icinga.org/) *
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")
72 po::basic_command_line_parser<wchar_t> parser(ac, av);
79 po::command_line_style::unix_style |
80 po::command_line_style::allow_long_disguise)
84 } catch (std::exception& e) {
85 std::cout << e.what() << '\n' << desc << '\n';
89 if (vm.count("version")) {
90 std::wcout << "Version: " << VERSION << '\n';
94 if (vm.count("help")) {
95 std::wcout << szProgName << " Help\n\tVersion: " << VERSION << '\n';
97 L"%s runs a check against a performance counter.\n"
98 L"You can use the following options to define its behaviour:\n\n", szProgName);
101 L"\nIt will then output a string looking something like this:\n\n"
102 L"\tPERFMON CRITICAL \"\\Processor(_Total)\\%% Idle Time\" = 40.34 | "
103 L"perfmon=40.34;20;40;; \"\\Processor(_Total)\\%% Idle Time\"=40.34\n\n"
104 L"\"tPERFMON\" being the type of the check, \"CRITICAL\" the returned status\n"
105 L"and \"40.34\" is the performance counters value.\n"
106 L"%s' exit codes denote the following:\n"
107 L" 0\tOK,\n\tNo Thresholds were exceeded\n"
108 L" 1\tWARNING,\n\tThe warning was broken, but not the critical threshold\n"
109 L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
110 L" 3\tUNKNOWN, \n\tNo check could be performed\n\n"
115 if (vm.count("warning")) {
117 printInfo.tWarn = threshold(vm["warning"].as<std::wstring>());
118 } catch (std::invalid_argument& e) {
119 std::wcout << e.what() << '\n';
124 if (vm.count("critical")) {
126 printInfo.tCrit = threshold(vm["critical"].as<std::wstring>());
127 } catch (std::invalid_argument& e) {
128 std::wcout << e.what() << '\n';
133 if (vm.count("fmt-countertype")) {
134 if (!vm["fmt-countertype"].as<std::wstring>().compare(L"int64"))
135 printInfo.dwRequestedType = PDH_FMT_LARGE;
136 else if (!vm["fmt-countertype"].as<std::wstring>().compare(L"long"))
137 printInfo.dwRequestedType = PDH_FMT_LONG;
138 else if (vm["fmt-countertype"].as<std::wstring>().compare(L"double")) {
139 std::wcout << "Unknown value type " << vm["fmt-countertype"].as<std::wstring>() << '\n';
144 if (vm.count("performance-counter"))
145 printInfo.wsFullPath = vm["performance-counter"].as<std::wstring>();
147 if (vm.count("performance-wait"))
148 printInfo.dwPerformanceWait = vm["performance-wait"].as<DWORD>();
153 BOOL GetIntstancesAndCountersOfObject(CONST std::wstring wsObject,
154 std::vector<std::wstring>& vecInstances,
155 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,
327 &dwBufferSize, &dwItemCount, pDisplayValues);
328 if (status != PDH_MORE_DATA)
331 pDisplayValues = reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(new BYTE[dwBufferSize]);
332 status = PdhGetFormattedCounterArray(hCounter, pI.dwRequestedType,
333 &dwBufferSize, &dwItemCount, pDisplayValues);
338 switch (pI.dwRequestedType)
341 pI.dValue = pDisplayValues[0].FmtValue.longValue;
343 case (PDH_FMT_LARGE):
344 pI.dValue = pDisplayValues[0].FmtValue.largeValue;
347 pI.dValue = pDisplayValues[0].FmtValue.doubleValue;
351 delete[]pDisplayValues;
356 FormatPDHError(status);
357 delete[]pDisplayValues;
361 INT PrintOutput(CONST po::variables_map& vm, printInfoStruct& pi)
363 std::wstringstream wssPerfData;
364 wssPerfData << "\"" << pi.wsFullPath << "\"=" << pi.dValue << ';'
365 << pi.tWarn.pString() << ';' << pi.tCrit.pString() << ";;";
367 if (pi.tCrit.rend(pi.dValue)) {
368 std::wcout << "PERFMON CRITICAL \"" << pi.wsFullPath << "\" = "
369 << pi.dValue << " | " << wssPerfData.str() << '\n';
373 if (pi.tWarn.rend(pi.dValue)) {
374 std::wcout << "PERFMON WARNING \"" << pi.wsFullPath << "\" = "
375 << pi.dValue << " | " << wssPerfData.str() << '\n';
379 std::wcout << "PERFMON OK \"" << pi.wsFullPath << "\" = "
380 << pi.dValue << " | " << wssPerfData.str() << '\n';
384 VOID FormatPDHError(PDH_STATUS status)
386 HANDLE hPdhLibrary = NULL;
387 LPWSTR pMessage = NULL;
389 hPdhLibrary = LoadLibrary(L"pdh.dll");
390 if (NULL == hPdhLibrary) {
391 std::wcout << "LoadLibrary failed with " << GetLastError() << '\n';
395 if (!FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY,
396 hPdhLibrary, status, 0, (LPWSTR)&pMessage, 0, NULL)) {
397 std::wcout << "Format message failed with " << std::hex << GetLastError() << '\n';
401 std::wcout << pMessage << '\n';