]> granicus.if.org Git - icinga2/blobdiff - plugins/check_perfmon.cpp
Merge pull request #7403 from Icinga/feature/docs-agents
[icinga2] / plugins / check_perfmon.cpp
index 02b1186203b29463924fee9e544fe5f88acb933a..0f94b12dc5347fefb06cb9a0f1a8fee66eb665e9 100644 (file)
@@ -1,56 +1,29 @@
-/******************************************************************************
-* Icinga 2                                                                   *
-* Copyright (C) 2012-2015 Icinga Development Team (http://www.icinga.org)    *
-*                                                                            *
-* This program is free software; you can redistribute it and/or              *
-* modify it under the terms of the GNU General Public License                *
-* as published by the Free Software Foundation; either version 2             *
-* of the License, or (at your option) any later version.                     *
-*                                                                            *
-* This program is distributed in the hope that it will be useful,            *
-* but WITHOUT ANY WARRANTY; without even the implied warranty of             *
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
-* GNU General Public License for more details.                               *
-*                                                                            *
-* You should have received a copy of the GNU General Public License          *
-* along with this program; if not, write to the Free Software Foundation     *
-* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
-******************************************************************************/
-
-#include <Shlwapi.h>
+/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
+
+#include "plugins/thresholds.hpp"
+#include <boost/program_options.hpp>
 #include <iostream>
 #include <vector>
-
-#include "check_perfmon.h"
+#include <windows.h>
+#include <pdh.h>
+#include <pdhmsg.h>
+#include <shlwapi.h>
 
 #define VERSION 1.0
 
 namespace po = boost::program_options;
 
-INT wmain(INT argc, WCHAR **argv)
+struct printInfoStruct
 {
-       po::variables_map variables_map;
-       printInfoStruct stPrintInfo;
-       if (!ParseArguments(argc, argv, variables_map, stPrintInfo))
-               return 3;
-
-       if (variables_map.count("print-objects")) {
-               PrintObjects();
-               return 0;
-       }
-
-       if (variables_map.count("print-object-info")) {
-               PrintObjectInfo(stPrintInfo);
-               return 0;
-       }
-
-       if (QueryPerfData(stPrintInfo))
-               return PrintOutput(variables_map, stPrintInfo);
-       else
-               return 3;
-}
-
-BOOL ParseArguments(CONST INT ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo)
+       threshold tWarn;
+       threshold tCrit;
+       std::wstring wsFullPath;
+       double dValue;
+       DWORD dwPerformanceWait = 1000;
+       DWORD dwRequestedType = PDH_FMT_DOUBLE;
+};
+
+static bool parseArguments(const int ac, WCHAR **av, po::variables_map& vm, printInfoStruct& printInfo)
 {
        WCHAR szNamePath[MAX_PATH + 1];
        GetModuleFileName(NULL, szNamePath, MAX_PATH);
@@ -67,28 +40,29 @@ BOOL ParseArguments(CONST INT ac, WCHAR **av, po::variables_map& vm, printInfoSt
                ("fmt-countertype", po::wvalue<std::wstring>(), "Value type of counter: 'double'(default), 'long', 'int64'")
                ("print-objects", "Prints all available objects to console")
                ("print-object-info", "Prints all available instances and counters of --performance-counter, do not use a full perfomance counter string here")
+               ("perf-syntax", po::wvalue<std::wstring>(), "Use this string as name for the performance counter (graphite compatibility)")
                ;
 
-       po::basic_command_line_parser<wchar_t> parser(ac, av);
+       po::wcommand_line_parser parser(ac, av);
 
        try {
                po::store(
                        parser
                        .options(desc)
                        .style(
-                       po::command_line_style::unix_style |
-                       po::command_line_style::allow_long_disguise)
+                               po::command_line_style::unix_style |
+                               po::command_line_style::allow_long_disguise)
                        .run(),
                        vm);
                vm.notify();
-       } catch (std::exception& e) {
+       } catch (const std::exception& e) {
                std::cout << e.what() << '\n' << desc << '\n';
-               return FALSE;
+               return false;
        }
 
        if (vm.count("version")) {
                std::wcout << "Version: " << VERSION << '\n';
-               return FALSE;
+               return false;
        }
 
        if (vm.count("help")) {
@@ -109,37 +83,35 @@ BOOL ParseArguments(CONST INT ac, WCHAR **av, po::variables_map& vm, printInfoSt
                        L" 2\tCRITICAL,\n\tThe critical threshold was broken\n"
                        L" 3\tUNKNOWN, \n\tNo check could be performed\n\n"
                        , szProgName);
-               return 0;
+               return false;
        }
 
        if (vm.count("warning")) {
                try {
                        printInfo.tWarn = threshold(vm["warning"].as<std::wstring>());
-               } catch (std::invalid_argument& e) {
+               } catch (const std::invalid_argument& e) {
                        std::wcout << e.what() << '\n';
-                       return FALSE;
+                       return false;
                }
        }
 
        if (vm.count("critical")) {
                try {
                        printInfo.tCrit = threshold(vm["critical"].as<std::wstring>());
-               } catch (std::invalid_argument& e) {
+               } catch (const std::invalid_argument& e) {
                        std::wcout << e.what() << '\n';
-                       return FALSE;
+                       return false;
                }
        }
 
        if (vm.count("fmt-countertype")) {
-               if (vm["fmt-countertype"].as<std::wstring>().compare(L"double"))
-                       printInfo.dwRequestedType = PDH_FMT_DOUBLE;
-               else if (vm["fmt-countertype"].as<std::wstring>().compare(L"int64"))
+               if (!vm["fmt-countertype"].as<std::wstring>().compare(L"int64"))
                        printInfo.dwRequestedType = PDH_FMT_LARGE;
-               else if (vm["fmt-countertype"].as<std::wstring>().compare(L"long"))
+               else if (!vm["fmt-countertype"].as<std::wstring>().compare(L"long"))
                        printInfo.dwRequestedType = PDH_FMT_LONG;
-               else {
+               else if (vm["fmt-countertype"].as<std::wstring>().compare(L"double")) {
                        std::wcout << "Unknown value type " << vm["fmt-countertype"].as<std::wstring>() << '\n';
-                       return FALSE;
+                       return false;
                }
        }
 
@@ -149,47 +121,33 @@ BOOL ParseArguments(CONST INT ac, WCHAR **av, po::variables_map& vm, printInfoSt
        if (vm.count("performance-wait"))
                printInfo.dwPerformanceWait = vm["performance-wait"].as<DWORD>();
 
-       return TRUE;
+       return true;
 }
 
-BOOL GetIntstancesAndCountersOfObject(CONST std::wstring wsObject, 
-                                                                        std::vector<std::wstring>& vecInstances, 
-                                                                        std::vector<std::wstring>& vecCounters)
+static bool getInstancesAndCountersOfObject(const std::wstring& wsObject,
+       std::vector<std::wstring>& vecInstances, std::vector<std::wstring>& vecCounters)
 {
-       LPWSTR szDataSource = NULL, szMachineName = NULL,
-               mszCounterList = NULL, mszInstanceList = NULL;
        DWORD dwCounterListLength = 0, dwInstanceListLength = 0;
 
-       std::wstringstream wssInstanceName, wssCounterName;
-       LPWSTR szObjectName = new WCHAR[wsObject.length() + 1];
-       StrCpyW(szObjectName, wsObject.c_str());
+       if (PdhEnumObjectItems(NULL, NULL, wsObject.c_str(),
+               NULL, &dwCounterListLength, NULL,
+               &dwInstanceListLength, PERF_DETAIL_WIZARD, 0) != PDH_MORE_DATA)
+               return false;
 
-       PDH_STATUS status =
-               PdhEnumObjectItems(szDataSource, szMachineName, szObjectName,
-               mszCounterList, &dwCounterListLength, mszInstanceList,
-               &dwInstanceListLength, PERF_DETAIL_WIZARD, 0);
+       std::vector<WCHAR> mszCounterList(dwCounterListLength + 1);
+       std::vector<WCHAR> mszInstanceList(dwInstanceListLength + 1);
 
-       if (status != PDH_MORE_DATA) {
-               delete[]szObjectName;
-               return FALSE;
-       }
-
-       mszCounterList = new WCHAR[dwCounterListLength + 1];
-       mszInstanceList = new WCHAR[dwInstanceListLength + 1];
-
-       status = PdhEnumObjectItems(szDataSource, szMachineName, szObjectName,
-                                                               mszCounterList, &dwCounterListLength, mszInstanceList,
-                                                               &dwInstanceListLength, PERF_DETAIL_WIZARD, 0);
-
-       if (FAILED(status)) {
-               delete[]mszCounterList;
-               delete[]mszInstanceList;
-               delete[]szObjectName;
-               return FALSE;
+       if (FAILED(PdhEnumObjectItems(NULL, NULL, wsObject.c_str(),
+               mszCounterList.data(), &dwCounterListLength, mszInstanceList.data(),
+               &dwInstanceListLength, PERF_DETAIL_WIZARD, 0))) {
+               return false;
        }
 
        if (dwInstanceListLength) {
-               for (DWORD c = 0; c < dwInstanceListLength-1; ++c) {
+               std::wstringstream wssInstanceName;
+
+               // XXX: is the "- 1" correct?
+               for (DWORD c = 0; c < dwInstanceListLength - 1; ++c) {
                        if (mszInstanceList[c])
                                wssInstanceName << mszInstanceList[c];
                        else {
@@ -200,41 +158,66 @@ BOOL GetIntstancesAndCountersOfObject(CONST std::wstring wsObject,
        }
 
        if (dwCounterListLength) {
-               for (DWORD c = 0; c < dwCounterListLength-1; ++c) {
-                       if (mszCounterList[c]) {
+               std::wstringstream wssCounterName;
+
+               // XXX: is the "- 1" correct?
+               for (DWORD c = 0; c < dwCounterListLength - 1; ++c) {
+                       if (mszCounterList[c])
                                wssCounterName << mszCounterList[c];
-                       else {
+                       else {
                                vecCounters.push_back(wssCounterName.str());
                                wssCounterName.str(L"");
                        }
                }
        }
 
-       delete[]mszCounterList;
-       delete[]mszInstanceList;
-       delete[]szObjectName;
+       return true;
+}
+
+static void printPDHError(PDH_STATUS status)
+{
+       HMODULE hPdhLibrary = NULL;
+       LPWSTR pMessage = NULL;
 
-       return TRUE;
+       hPdhLibrary = LoadLibrary(L"pdh.dll");
+       if (!hPdhLibrary) {
+               std::wcout << "LoadLibrary failed with " << GetLastError() << '\n';
+               return;
+       }
+
+       if (!FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY,
+               hPdhLibrary, status, 0, (LPWSTR)&pMessage, 0, NULL)) {
+               FreeLibrary(hPdhLibrary);
+               std::wcout << "Format message failed with " << std::hex << GetLastError() << '\n';
+               return;
+       }
+
+       FreeLibrary(hPdhLibrary);
+
+       std::wcout << pMessage << '\n';
+       LocalFree(pMessage);
 }
 
-VOID PrintObjects()
+static void printObjects()
 {
-       LPWSTR szDataSource = NULL, szMachineName = NULL, mszObjectList = NULL;
        DWORD dwBufferLength = 0;
-       PDH_STATUS status =
-               PdhEnumObjects(szDataSource, szMachineName, mszObjectList,
+       PDH_STATUS status =     PdhEnumObjects(NULL, NULL, NULL,
                &dwBufferLength, PERF_DETAIL_WIZARD, FALSE);
        //HEX HEX! Only a Magicians gets all the info he wants, and only Microsoft knows what that means
 
-       if (status != PDH_MORE_DATA)
-               goto die;
+       if (status != PDH_MORE_DATA) {
+               printPDHError(status);
+               return;
+       }
 
-       mszObjectList = new WCHAR[dwBufferLength + 2];
-       status = PdhEnumObjects(szDataSource, szMachineName, mszObjectList,
-                                                       &dwBufferLength, PERF_DETAIL_WIZARD, FALSE);
+       std::vector<WCHAR> mszObjectList(dwBufferLength + 2);
+       status = PdhEnumObjects(NULL, NULL, mszObjectList.data(),
+               &dwBufferLength, PERF_DETAIL_WIZARD, FALSE);
 
-       if (FAILED(status))
-               goto die;
+       if (FAILED(status)) {
+               printPDHError(status);
+               return;
+       }
 
        DWORD c = 0;
 
@@ -244,16 +227,9 @@ VOID PrintObjects()
                else
                        std::wcout << mszObjectList[c];
        }
-
-       delete[]mszObjectList;
-       return;
-
-die:
-       FormatPDHError(status);
-       delete[]mszObjectList;
 }
 
-VOID PrintObjectInfo(CONST printInfoStruct& pI)
+static void printObjectInfo(const printInfoStruct& pI)
 {
        if (pI.wsFullPath.empty()) {
                std::wcout << "No object given!\n";
@@ -262,9 +238,9 @@ VOID PrintObjectInfo(CONST printInfoStruct& pI)
 
        std::vector<std::wstring> vecInstances, vecCounters;
 
-       if (!GetIntstancesAndCountersOfObject(pI.wsFullPath, vecInstances, vecCounters)) {
+       if (!getInstancesAndCountersOfObject(pI.wsFullPath, vecInstances, vecCounters)) {
                std::wcout << "Could not enumerate instances and counters of " << pI.wsFullPath << '\n'
-                   << "Make sure it exists!\n";
+                       << "Make sure it exists!\n";
                return;
        }
 
@@ -272,10 +248,8 @@ VOID PrintObjectInfo(CONST printInfoStruct& pI)
        if (vecInstances.empty())
                std::wcout << "> Has no instances\n";
        else {
-               for (std::vector<std::wstring>::iterator it = vecInstances.begin();
-                        it != vecInstances.end(); ++it) {
-                       std::wcout << "> " << *it << '\n';
-               }
+               for (const auto& instance : vecInstances)
+                       std::wcout << "> " << instance << '\n';
        }
        std::wcout << std::endl;
 
@@ -283,31 +257,34 @@ VOID PrintObjectInfo(CONST printInfoStruct& pI)
        if (vecCounters.empty())
                std::wcout << "> Has no counters\n";
        else {
-               for (std::vector<std::wstring>::iterator it = vecCounters.begin();
-                        it != vecCounters.end(); ++it) {
-                       std::wcout << "> " << *it << '\n';
-               }
+               for (const auto& counter : vecCounters)
+                       std::wcout << "> " << counter << "\n";
        }
        std::wcout << std::endl;
 }
 
-BOOL QueryPerfData(printInfoStruct& pI)
+bool QueryPerfData(printInfoStruct& pI)
 {
        PDH_HQUERY hQuery = NULL;
        PDH_HCOUNTER hCounter = NULL;
-       PDH_FMT_COUNTERVALUE_ITEM *pDisplayValues = NULL;
        DWORD dwBufferSize = 0, dwItemCount = 0;
 
        if (pI.wsFullPath.empty()) {
                std::wcout << "No performance counter path given!\n";
-               return FALSE;
+               return false;
        }
 
+       PDH_FMT_COUNTERVALUE_ITEM *pDisplayValues = NULL;
+
        PDH_STATUS status = PdhOpenQuery(NULL, NULL, &hQuery);
        if (FAILED(status))
                goto die;
 
-       status = PdhAddCounter(hQuery, pI.wsFullPath.c_str(), NULL, &hCounter);
+       status = PdhAddEnglishCounter(hQuery, pI.wsFullPath.c_str(), NULL, &hCounter);
+
+       if (FAILED(status))
+               status = PdhAddCounter(hQuery, pI.wsFullPath.c_str(), NULL, &hCounter);
+
        if (FAILED(status))
                goto die;
 
@@ -315,89 +292,96 @@ BOOL QueryPerfData(printInfoStruct& pI)
        if (FAILED(status))
                goto die;
 
-       /* 
-       /* Most counters need two queries to provide a value.
-       /* Those which need only one will return the second.
-        */
+       /*
+       * Most counters need two queries to provide a value.
+       * Those which need only one will return the second.
+       */
        Sleep(pI.dwPerformanceWait);
 
        status = PdhCollectQueryData(hQuery);
        if (FAILED(status))
                goto die;
 
-       status = PdhGetFormattedCounterArray(hCounter, pI.dwRequestedType,
-                                                                                &dwBufferSize, &dwItemCount, pDisplayValues);
+       status = PdhGetFormattedCounterArray(hCounter, pI.dwRequestedType, &dwBufferSize, &dwItemCount, NULL);
        if (status != PDH_MORE_DATA)
                goto die;
 
        pDisplayValues = reinterpret_cast<PDH_FMT_COUNTERVALUE_ITEM*>(new BYTE[dwBufferSize]);
-       status = PdhGetFormattedCounterArray(hCounter, pI.dwRequestedType,
-                                                                                &dwBufferSize, &dwItemCount, pDisplayValues);
+       status = PdhGetFormattedCounterArray(hCounter, pI.dwRequestedType, &dwBufferSize, &dwItemCount, pDisplayValues);
 
        if (FAILED(status))
                goto die;
 
-       switch (pI.dwRequestedType)
-       {
+       switch (pI.dwRequestedType) {
        case (PDH_FMT_LONG):
                pI.dValue = pDisplayValues[0].FmtValue.longValue;
-       case (PDH_FMT_LARGE) :
-               pI.dValue = pDisplayValues[0].FmtValue.largeValue;
+               break;
+       case (PDH_FMT_LARGE):
+               pI.dValue = (double) pDisplayValues[0].FmtValue.largeValue;
+               break;
        default:
                pI.dValue = pDisplayValues[0].FmtValue.doubleValue;
+               break;
        }
 
        delete[]pDisplayValues;
 
-       return TRUE;
+       return true;
 
 die:
-       FormatPDHError(status);
+       printPDHError(status);
        delete[]pDisplayValues;
-       return FALSE;
+       return false;
 }
 
-INT PrintOutput(CONST po::variables_map& vm, printInfoStruct& pi)
+static int printOutput(const po::variables_map& vm, printInfoStruct& pi)
 {
        std::wstringstream wssPerfData;
-       wssPerfData << "perfmon=" << pi.dValue << ';'
-               << pi.tWarn.pString() << ';' << pi.tCrit.pString() << ";; "
-               << '"' << pi.wsFullPath << "\"=" << pi.dValue;
+
+       if (vm.count("perf-syntax"))
+               wssPerfData << "'" << vm["perf-syntax"].as<std::wstring>() << "'=";
+       else
+               wssPerfData << "'" << pi.wsFullPath << "'=";
+
+       wssPerfData << pi.dValue << ';' << pi.tWarn.pString() << ';' << pi.tCrit.pString() << ";;";
 
        if (pi.tCrit.rend(pi.dValue)) {
-               std::wcout << "PERFMON CRITICAL \"" << pi.wsFullPath << "\" = "
-                       << pi.dValue << " | " << wssPerfData.str() << '\n';
+               std::wcout << "PERFMON CRITICAL for '" << (vm.count("perf-syntax") ? vm["perf-syntax"].as<std::wstring>() : pi.wsFullPath)
+                       << "' = " << pi.dValue << " | " << wssPerfData.str() << "\n";
                return 2;
        }
 
        if (pi.tWarn.rend(pi.dValue)) {
-               std::wcout << "PERFMON WARNING \"" << pi.wsFullPath << "\" = "
-                       << pi.dValue << " | " << wssPerfData.str() << '\n';
+               std::wcout << "PERFMON WARNING for '" << (vm.count("perf-syntax") ? vm["perf-syntax"].as<std::wstring>() : pi.wsFullPath)
+                       << "' = " << pi.dValue << " | " << wssPerfData.str() << "\n";
                return 1;
        }
 
-       std::wcout << "PERFMON OK \"" << pi.wsFullPath << "\" = "
-               << pi.dValue << " | " << wssPerfData.str() << '\n';
+       std::wcout << "PERFMON OK for '" << (vm.count("perf-syntax") ? vm["perf-syntax"].as<std::wstring>() : pi.wsFullPath)
+               << "' = " << pi.dValue << " | " << wssPerfData.str() << "\n";
+
        return 0;
 }
 
-VOID FormatPDHError(PDH_STATUS status)
+int wmain(int argc, WCHAR **argv)
 {
-       HANDLE hPdhLibrary = NULL;
-       LPWSTR pMessage = NULL;
+       po::variables_map variables_map;
+       printInfoStruct stPrintInfo;
+       if (!parseArguments(argc, argv, variables_map, stPrintInfo))
+               return 3;
 
-       hPdhLibrary = LoadLibrary(L"pdh.dll");
-       if (NULL == hPdhLibrary) {
-               std::wcout << "LoadLibrary failed with " << GetLastError() << '\n';
-               return;
+       if (variables_map.count("print-objects")) {
+               printObjects();
+               return 0;
        }
 
-       if (!FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY,
-               hPdhLibrary, status, 0, (LPWSTR)&pMessage, 0, NULL)) {
-               std::wcout << "Format message failed with " << std::hex << GetLastError() << '\n';
-               return;
+       if (variables_map.count("print-object-info")) {
+               printObjectInfo(stPrintInfo);
+               return 0;
        }
 
-       std::wcout << pMessage << '\n';
-       LocalFree(pMessage);
+       if (QueryPerfData(stPrintInfo))
+               return printOutput(variables_map, stPrintInfo);
+       else
+               return 3;
 }