1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
3 #include "plugins/thresholds.hpp"
4 #include <boost/program_options.hpp>
14 namespace po = boost::program_options;
16 struct printInfoStruct
20 std::wstring wsFullPath;
22 DWORD dwPerformanceWait = 1000;
23 DWORD dwRequestedType = PDH_FMT_DOUBLE;
26 static bool parseArguments(const int ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo)
28 WCHAR szNamePath[MAX_PATH + 1];
29 GetModuleFileName(NULL, szNamePath, MAX_PATH);
30 WCHAR *szProgName = PathFindFileName(szNamePath);
32 po::options_description desc("Options");
34 ("help,h", "Print help page and exit")
35 ("version,V", "Print version and exit")
36 ("warning,w", po::wvalue<std::wstring>(), "Warning thershold")
37 ("critical,c", po::wvalue<std::wstring>(), "Critical threshold")
38 ("performance-counter,P", po::wvalue<std::wstring>(), "The performance counter string to use")
39 ("performance-wait", po::value<DWORD>(), "Sleep in milliseconds between the two perfomance querries (Default: 1000ms)")
40 ("fmt-countertype", po::wvalue<std::wstring>(), "Value type of counter: 'double'(default), 'long', 'int64'")
41 ("print-objects", "Prints all available objects to console")
42 ("print-object-info", "Prints all available instances and counters of --performance-counter, do not use a full perfomance counter string here")
43 ("perf-syntax", po::wvalue<std::wstring>(), "Use this string as name for the performance counter (graphite compatibility)")
46 po::wcommand_line_parser parser(ac, av);
53 po::command_line_style::unix_style |
54 po::command_line_style::allow_long_disguise)
58 } catch (const std::exception& e) {
59 std::cout << e.what() << '\n' << desc << '\n';
63 if (vm.count("version")) {
64 std::wcout << "Version: " << VERSION << '\n';
68 if (vm.count("help")) {
69 std::wcout << szProgName << " Help\n\tVersion: " << VERSION << '\n';
71 L"%s runs a check against a performance counter.\n"
72 L"You can use the following options to define its behaviour:\n\n", szProgName);
75 L"\nIt will then output a string looking something like this:\n\n"
76 L"\tPERFMON CRITICAL \"\\Processor(_Total)\\%% Idle Time\" = 40.34 | "
77 L"perfmon=40.34;20;40;; \"\\Processor(_Total)\\%% Idle Time\"=40.34\n\n"
78 L"\"tPERFMON\" being the type of the check, \"CRITICAL\" the returned status\n"
79 L"and \"40.34\" is the performance counters value.\n"
80 L"%s' exit codes denote the following:\n"
81 L" 0\tOK,\n\tNo Thresholds were exceeded\n"
82 L" 1\tWARNING,\n\tThe warning was broken, but not the critical threshold\n"
83 L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
84 L" 3\tUNKNOWN, \n\tNo check could be performed\n\n"
89 if (vm.count("warning")) {
91 printInfo.tWarn = threshold(vm["warning"].as<std::wstring>());
92 } catch (const std::invalid_argument& e) {
93 std::wcout << e.what() << '\n';
98 if (vm.count("critical")) {
100 printInfo.tCrit = threshold(vm["critical"].as<std::wstring>());
101 } catch (const std::invalid_argument& e) {
102 std::wcout << e.what() << '\n';
107 if (vm.count("fmt-countertype")) {
108 if (!vm["fmt-countertype"].as<std::wstring>().compare(L"int64"))
109 printInfo.dwRequestedType = PDH_FMT_LARGE;
110 else if (!vm["fmt-countertype"].as<std::wstring>().compare(L"long"))
111 printInfo.dwRequestedType = PDH_FMT_LONG;
112 else if (vm["fmt-countertype"].as<std::wstring>().compare(L"double")) {
113 std::wcout << "Unknown value type " << vm["fmt-countertype"].as<std::wstring>() << '\n';
118 if (vm.count("performance-counter"))
119 printInfo.wsFullPath = vm["performance-counter"].as<std::wstring>();
121 if (vm.count("performance-wait"))
122 printInfo.dwPerformanceWait = vm["performance-wait"].as<DWORD>();
127 static bool getInstancesAndCountersOfObject(const std::wstring& wsObject,
128 std::vector<std::wstring>& vecInstances, std::vector<std::wstring>& vecCounters)
130 DWORD dwCounterListLength = 0, dwInstanceListLength = 0;
132 if (PdhEnumObjectItems(NULL, NULL, wsObject.c_str(),
133 NULL, &dwCounterListLength, NULL,
134 &dwInstanceListLength, PERF_DETAIL_WIZARD, 0) != PDH_MORE_DATA)
137 std::vector<WCHAR> mszCounterList(dwCounterListLength + 1);
138 std::vector<WCHAR> mszInstanceList(dwInstanceListLength + 1);
140 if (FAILED(PdhEnumObjectItems(NULL, NULL, wsObject.c_str(),
141 mszCounterList.data(), &dwCounterListLength, mszInstanceList.data(),
142 &dwInstanceListLength, PERF_DETAIL_WIZARD, 0))) {
146 if (dwInstanceListLength) {
147 std::wstringstream wssInstanceName;
149 // XXX: is the "- 1" correct?
150 for (DWORD c = 0; c < dwInstanceListLength - 1; ++c) {
151 if (mszInstanceList[c])
152 wssInstanceName << mszInstanceList[c];
154 vecInstances.push_back(wssInstanceName.str());
155 wssInstanceName.str(L"");
160 if (dwCounterListLength) {
161 std::wstringstream wssCounterName;
163 // XXX: is the "- 1" correct?
164 for (DWORD c = 0; c < dwCounterListLength - 1; ++c) {
165 if (mszCounterList[c])
166 wssCounterName << mszCounterList[c];
168 vecCounters.push_back(wssCounterName.str());
169 wssCounterName.str(L"");
177 static void printPDHError(PDH_STATUS status)
179 HMODULE hPdhLibrary = NULL;
180 LPWSTR pMessage = NULL;
182 hPdhLibrary = LoadLibrary(L"pdh.dll");
184 std::wcout << "LoadLibrary failed with " << GetLastError() << '\n';
188 if (!FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY,
189 hPdhLibrary, status, 0, (LPWSTR)&pMessage, 0, NULL)) {
190 FreeLibrary(hPdhLibrary);
191 std::wcout << "Format message failed with " << std::hex << GetLastError() << '\n';
195 FreeLibrary(hPdhLibrary);
197 std::wcout << pMessage << '\n';
201 static void printObjects()
203 DWORD dwBufferLength = 0;
204 PDH_STATUS status = PdhEnumObjects(NULL, NULL, NULL,
205 &dwBufferLength, PERF_DETAIL_WIZARD, FALSE);
206 //HEX HEX! Only a Magicians gets all the info he wants, and only Microsoft knows what that means
208 if (status != PDH_MORE_DATA) {
209 printPDHError(status);
213 std::vector<WCHAR> mszObjectList(dwBufferLength + 2);
214 status = PdhEnumObjects(NULL, NULL, mszObjectList.data(),
215 &dwBufferLength, PERF_DETAIL_WIZARD, FALSE);
217 if (FAILED(status)) {
218 printPDHError(status);
224 while (++c < dwBufferLength) {
225 if (mszObjectList[c] == '\0')
228 std::wcout << mszObjectList[c];
232 static void printObjectInfo(const printInfoStruct& pI)
234 if (pI.wsFullPath.empty()) {
235 std::wcout << "No object given!\n";
239 std::vector<std::wstring> vecInstances, vecCounters;
241 if (!getInstancesAndCountersOfObject(pI.wsFullPath, vecInstances, vecCounters)) {
242 std::wcout << "Could not enumerate instances and counters of " << pI.wsFullPath << '\n'
243 << "Make sure it exists!\n";
247 std::wcout << "Instances of " << pI.wsFullPath << ":\n";
248 if (vecInstances.empty())
249 std::wcout << "> Has no instances\n";
251 for (const auto& instance : vecInstances)
252 std::wcout << "> " << instance << '\n';
254 std::wcout << std::endl;
256 std::wcout << "Performance Counters of " << pI.wsFullPath << ":\n";
257 if (vecCounters.empty())
258 std::wcout << "> Has no counters\n";
260 for (const auto& counter : vecCounters)
261 std::wcout << "> " << counter << "\n";
263 std::wcout << std::endl;
266 bool QueryPerfData(printInfoStruct& pI)
268 PDH_HQUERY hQuery = NULL;
269 PDH_HCOUNTER hCounter = NULL;
270 DWORD dwBufferSize = 0, dwItemCount = 0;
272 if (pI.wsFullPath.empty()) {
273 std::wcout << "No performance counter path given!\n";
277 PDH_FMT_COUNTERVALUE_ITEM *pDisplayValues = NULL;
279 PDH_STATUS status = PdhOpenQuery(NULL, NULL, &hQuery);
283 status = PdhAddEnglishCounter(hQuery, pI.wsFullPath.c_str(), NULL, &hCounter);
286 status = PdhAddCounter(hQuery, pI.wsFullPath.c_str(), NULL, &hCounter);
291 status = PdhCollectQueryData(hQuery);
296 * Most counters need two queries to provide a value.
297 * Those which need only one will return the second.
299 Sleep(pI.dwPerformanceWait);
301 status = PdhCollectQueryData(hQuery);
305 status = PdhGetFormattedCounterArray(hCounter, pI.dwRequestedType, &dwBufferSize, &dwItemCount, NULL);
306 if (status != PDH_MORE_DATA)
309 pDisplayValues = reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(new BYTE[dwBufferSize]);
310 status = PdhGetFormattedCounterArray(hCounter, pI.dwRequestedType, &dwBufferSize, &dwItemCount, pDisplayValues);
315 switch (pI.dwRequestedType) {
317 pI.dValue = pDisplayValues[0].FmtValue.longValue;
319 case (PDH_FMT_LARGE):
320 pI.dValue = (double) pDisplayValues[0].FmtValue.largeValue;
323 pI.dValue = pDisplayValues[0].FmtValue.doubleValue;
327 delete[]pDisplayValues;
332 printPDHError(status);
333 delete[]pDisplayValues;
337 static int printOutput(const po::variables_map& vm, printInfoStruct& pi)
339 std::wstringstream wssPerfData;
341 if (vm.count("perf-syntax"))
342 wssPerfData << "'" << vm["perf-syntax"].as<std::wstring>() << "'=";
344 wssPerfData << "'" << pi.wsFullPath << "'=";
346 wssPerfData << pi.dValue << ';' << pi.tWarn.pString() << ';' << pi.tCrit.pString() << ";;";
348 if (pi.tCrit.rend(pi.dValue)) {
349 std::wcout << "PERFMON CRITICAL for '" << (vm.count("perf-syntax") ? vm["perf-syntax"].as<std::wstring>() : pi.wsFullPath)
350 << "' = " << pi.dValue << " | " << wssPerfData.str() << "\n";
354 if (pi.tWarn.rend(pi.dValue)) {
355 std::wcout << "PERFMON WARNING for '" << (vm.count("perf-syntax") ? vm["perf-syntax"].as<std::wstring>() : pi.wsFullPath)
356 << "' = " << pi.dValue << " | " << wssPerfData.str() << "\n";
360 std::wcout << "PERFMON OK for '" << (vm.count("perf-syntax") ? vm["perf-syntax"].as<std::wstring>() : pi.wsFullPath)
361 << "' = " << pi.dValue << " | " << wssPerfData.str() << "\n";
366 int wmain(int argc, WCHAR **argv)
368 po::variables_map variables_map;
369 printInfoStruct stPrintInfo;
370 if (!parseArguments(argc, argv, variables_map, stPrintInfo))
373 if (variables_map.count("print-objects")) {
378 if (variables_map.count("print-object-info")) {
379 printObjectInfo(stPrintInfo);
383 if (QueryPerfData(stPrintInfo))
384 return printOutput(variables_map, stPrintInfo);