source: nscp/include/PDHCounter.h @ 47b843a

0.4.00.4.10.4.2stable
Last change on this file since 47b843a was 3f69109, checked in by Michael Medin <michael@…>, 5 years ago

2007-12-11 MickeM

+ Added support for index-lookups of PDH counters (hopefully *all* local problems are now fixed (yeah right))

2007-12-10 MickeM

+ Added intial draft for LUA module

  • Property mode set to 100644
File size: 14.7 KB
Line 
1/**************************************************************************
2*   Copyright (C) 2004-2007 by Michael Medin <michael@medin.name>         *
3*                                                                         *
4*   This code is part of NSClient++ - http://trac.nakednuns.org/nscp      *
5*                                                                         *
6*   This program is free software; you can redistribute it and/or modify  *
7*   it under the terms of the GNU General Public License as published by  *
8*   the Free Software Foundation; either version 2 of the License, or     *
9*   (at your option) any later version.                                   *
10*                                                                         *
11*   This program is distributed in the hope that it will be useful,       *
12*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14*   GNU General Public License for more details.                          *
15*                                                                         *
16*   You should have received a copy of the GNU General Public License     *
17*   along with this program; if not, write to the                         *
18*   Free Software Foundation, Inc.,                                       *
19*   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
20***************************************************************************/
21#pragma once
22
23#include <list>
24#include <pdh.h>
25#include <pdhmsg.h>
26#include <assert.h>
27#include <sstream>
28
29namespace PDH {
30
31
32
33        class PDHException {
34        private:
35                std::wstring str_;
36                std::wstring name_;
37                PDH_STATUS pdhStatus_;
38        public:
39                PDHException(std::wstring name, std::wstring str, PDH_STATUS pdhStatus = 0) : name_(name), str_(str), pdhStatus_(pdhStatus) {}
40                PDHException(std::wstring str, PDH_STATUS pdhStatus) : str_(str), pdhStatus_(pdhStatus) {}
41                PDHException(std::wstring str) : str_(str), pdhStatus_(0) {}
42                std::wstring getError() const {
43                        std::wstring ret;
44                        if (!name_.empty())
45                                ret += name_ + _T(": ");
46                        ret += str_;
47                        if (pdhStatus_ != 0) {
48                                ret += _T(": ") + error::format::from_module(_T("PDH.DLL"), pdhStatus_);
49                        }
50                        return ret;
51                }
52        };
53
54        class PDHResolver {
55        public:
56                //typedef PDH_FUNCTION (*fpPdhLookupPerfNameByIndex)(IN LPCWSTR szMachineName,IN DWORD dwNameIndex,IN LPWSTR szNameBuffer,IN LPDWORD pcchNameBufferSize);
57                typedef PDH_STATUS (WINAPI *fpPdhLookupPerfNameByIndex)(LPCWSTR,DWORD,LPWSTR,LPDWORD);
58                static fpPdhLookupPerfNameByIndex pPdhLookupPerfNameByIndex;
59                static HMODULE PDH_;
60        private:
61                static void lookup_function() {
62                        if (pPdhLookupPerfNameByIndex != NULL)
63                                return;
64                        PDH_ = ::LoadLibrary(_TEXT("PDH"));
65                       
66                        if (PDH_ == NULL) {
67                                throw PDHException(_T("LoadLibrary for PDH failed: ")+ error::lookup::last_error());
68                        }
69#ifdef UNICODE
70                        //*(FARPROC *)&pPdhLookupPerfNameByIndex
71                        pPdhLookupPerfNameByIndex = (fpPdhLookupPerfNameByIndex)::GetProcAddress(PDH_, "PdhLookupPerfNameByIndexW");
72#else
73                        pPdhLookupPerfNameByIndex = (fpPdhLookupPerfNameByIndex)::GetProcAddress(PDH_, "PdhLookupPerfNameByIndexA");
74#endif
75                        if (pPdhLookupPerfNameByIndex == NULL) {
76                                throw PDHException(_T("Failed to find function: PdhLookupPerfNameByIndex!")+ error::lookup::last_error());
77                        }
78                }
79        public:
80                static PDH_STATUS PdhLookupPerfNameByIndex(LPCTSTR szMachineName,DWORD dwNameIndex,LPTSTR szNameBuffer,LPDWORD pcchNameBufferSize) {
81                        PDHResolver::lookup_function();
82                        if (pPdhLookupPerfNameByIndex == NULL)
83                                throw PDHException(_T("Failed to initalize PdhLookupPerfNameByIndex :("));
84                        return pPdhLookupPerfNameByIndex(szMachineName,dwNameIndex,szNameBuffer,pcchNameBufferSize);
85                }
86#define PDH_INDEX_BUF_LEN 2048
87                static std::wstring PdhLookupPerfNameByIndex(LPCTSTR szMachineName, DWORD dwNameIndex) {
88                        TCHAR *buffer = new TCHAR[PDH_INDEX_BUF_LEN+1];
89                        DWORD bufLen = PDH_INDEX_BUF_LEN;
90                        PDH_STATUS status = PDHResolver::PdhLookupPerfNameByIndex(szMachineName,dwNameIndex,buffer,&bufLen);
91                        if (status != ERROR_SUCCESS) {
92                                delete [] buffer;
93                                throw PDHException(_T("RESOLVER"), _T("PdhLookupPerfNameByIndex: Could not find index: ") + strEx::itos(dwNameIndex), status);
94                        }
95                        std::wstring ret = buffer;
96                        delete [] buffer;
97                        return ret;
98                }
99        };
100
101        class PDHCounter;
102        class PDHCounterListener {
103        public:
104                virtual void collect(const PDHCounter &counter) = 0;
105                virtual void attach(const PDHCounter &counter) = 0;
106                virtual void detach(const PDHCounter &counter) = 0;
107                virtual DWORD getFormat() const = 0;
108        };
109
110        class PDHCounterInfo {
111        public:
112                DWORD   dwType;
113                DWORD   CVersion;
114                DWORD   CStatus;
115                LONG    lScale;
116                LONG    lDefaultScale;
117                DWORD_PTR   dwUserData;
118                DWORD_PTR   dwQueryUserData;
119                std::wstring  szFullPath;
120
121                std::wstring   szMachineName;
122                std::wstring   szObjectName;
123                std::wstring   szInstanceName;
124                std::wstring   szParentInstance;
125                DWORD    dwInstanceIndex;
126                std::wstring   szCounterName;
127
128                std::wstring  szExplainText;
129
130                PDHCounterInfo(BYTE *lpBuffer, DWORD dwBufferSize, BOOL explainText) {
131                        PDH_COUNTER_INFO *info = (PDH_COUNTER_INFO*)lpBuffer;
132                        dwType = info->dwType;
133                        CVersion = info->CVersion;
134                        CStatus = info->CStatus;
135                        lScale = info->lScale;
136                        lDefaultScale = info->lDefaultScale;
137                        dwUserData = info->dwUserData;
138                        dwQueryUserData = info->dwQueryUserData;
139                        szFullPath = info->szFullPath;
140                        if (info->szMachineName)
141                                szMachineName = info->szMachineName;
142                        if (info->szObjectName)
143                                szObjectName = info->szObjectName;
144                        if (info->szInstanceName)
145                                szInstanceName = info->szInstanceName;
146                        if (info->szParentInstance)
147                                szParentInstance = info->szParentInstance;
148                        dwInstanceIndex = info->dwInstanceIndex;
149                        if (info->szCounterName)
150                                szCounterName = info->szCounterName;
151                        if (explainText) {
152                                if (info->szExplainText)
153                                        szExplainText = info->szExplainText;
154                        }
155                }
156        };
157
158        class PDHCounter
159        {
160        private:
161                HCOUNTER hCounter_;
162                std::wstring name_;
163                PDH_FMT_COUNTERVALUE data_;
164                PDHCounterListener *listener_;
165
166        public:
167
168                PDHCounter(std::wstring name, PDHCounterListener *listener) : name_(name), listener_(listener), hCounter_(NULL){}
169                PDHCounter(std::wstring name) : name_(name), listener_(NULL), hCounter_(NULL){}
170                virtual ~PDHCounter(void) {
171                        if (hCounter_ != NULL)
172                                remove();
173                }
174
175                void setListener(PDHCounterListener *listener) {
176                        listener_ = listener;
177                }
178
179                PDHCounterInfo getCounterInfo(BOOL bExplainText = FALSE) {
180                        assert(hCounter_ != NULL);
181                        PDH_STATUS status;
182                        BYTE *lpBuffer = new BYTE[1025];
183                        DWORD bufSize = 1024;
184                        if ((status = PdhGetCounterInfo(hCounter_, bExplainText, &bufSize, (PDH_COUNTER_INFO*)lpBuffer)) != ERROR_SUCCESS) {
185                                throw PDHException(name_, _T("getCounterInfo failed (no query)"), status);
186                        }
187                        return PDHCounterInfo(lpBuffer, bufSize, TRUE);
188                }
189                const HCOUNTER getCounter() const {
190                        return hCounter_;
191                }
192                const std::wstring getName() const {
193                        return name_;
194                }
195                void addToQuery(HQUERY hQuery) {
196                        PDH_STATUS status;
197                        if (hQuery == NULL)
198                                throw PDHException(name_, _T("addToQuery failed (no query)."));
199                        if (hCounter_ != NULL)
200                                throw PDHException(name_, _T("addToQuery failed (already opened)."));
201                        if (listener_)
202                                listener_->attach(*this);
203                        LPCWSTR name = name_.c_str();
204                        if ((status = PdhAddCounter(hQuery, name, 0, &hCounter_)) != ERROR_SUCCESS) {
205                                hCounter_ = NULL;
206                                throw PDHException(name_, _T("PdhAddCounter failed"), status);
207                        }
208                        assert(hCounter_ != NULL);
209                }
210                void remove() {
211                        if (hCounter_ == NULL)
212                                return;
213                        PDH_STATUS status;
214                        if (listener_)
215                                listener_->detach(*this);
216                        if ((status = PdhRemoveCounter(hCounter_)) != ERROR_SUCCESS)
217                                throw PDHException(name_, _T("PdhRemoveCounter failed"), status);
218                        hCounter_ = NULL;
219                }
220                void collect() {
221                        if (hCounter_ == NULL)
222                                return;
223                        PDH_STATUS status;
224                        if (!listener_)
225                                return;
226                        if ((status = PdhGetFormattedCounterValue(hCounter_, listener_->getFormat(), NULL, &data_)) != ERROR_SUCCESS) {
227                                throw PDHException(name_, _T("PdhGetFormattedCounterValue failed"), status);
228                        }
229                        listener_->collect(*this);
230                }
231                double getDoubleValue() const {
232                        return data_.doubleValue;
233                }
234                __int64 getInt64Value() const {
235                        return data_.largeValue;
236                }
237                long getIntValue() const {
238                        return data_.longValue;
239                }
240                std::wstring getStringValue() const {
241                        return data_.WideStringValue;
242                }
243        };
244
245        class PDHQuery
246        {
247        private:
248                typedef std::list<PDHCounter*> CounterList;
249                CounterList counters_;
250                HQUERY hQuery_;
251        public:
252                PDHQuery() : hQuery_(NULL) {
253                }
254                virtual ~PDHQuery(void) {
255                        removeAllCounters();
256                }
257
258                PDHCounter* addCounter(std::wstring name, PDHCounterListener *listener) {
259                        PDHCounter *counter = new PDHCounter(name, listener);
260                        counters_.push_back(counter);
261                        return counter;
262                }
263                std::wstring lookupIndex(DWORD index) {
264                        return PDHResolver::PdhLookupPerfNameByIndex(NULL, index);
265                }
266                PDHCounter* addCounter(std::wstring name) {
267                        PDHCounter *counter = new PDHCounter(name);
268                        counters_.push_back(counter);
269                        return counter;
270                }
271                void removeAllCounters() {
272                        if (hQuery_)
273                                close();
274                        for (CounterList::iterator it = counters_.begin(); it != counters_.end(); it++) {
275                                delete (*it);
276                        }
277                        counters_.clear();
278                }
279
280                void open() {
281                        assert(hQuery_ == NULL);
282                        PDH_STATUS status;
283                        if( (status = PdhOpenQuery( NULL, 0, &hQuery_ )) != ERROR_SUCCESS)
284                                throw PDHException(_T("PdhOpenQuery failed"), status);
285                        for (CounterList::iterator it = counters_.begin(); it != counters_.end(); it++) {
286                                (*it)->addToQuery(getQueryHandle());
287                        }
288                }
289
290                void close() {
291                        assert(hQuery_ != NULL);
292                        PDH_STATUS status;
293                        for (CounterList::iterator it = counters_.begin(); it != counters_.end(); it++) {
294                                (*it)->remove();
295                        }
296                        if( (status = PdhCloseQuery(hQuery_)) != ERROR_SUCCESS)
297                                throw PDHException(_T("PdhCloseQuery failed"), status);
298                        hQuery_ = NULL;
299                        for (CounterList::iterator it = counters_.begin(); it != counters_.end(); it++) {
300                                delete (*it);
301                        }
302                        counters_.clear();
303                }
304
305                void gatherData() {
306                        PDH_STATUS status;
307                        if ((status = PdhCollectQueryData(hQuery_)) != ERROR_SUCCESS)
308                                throw PDHException(_T("PdhCollectQueryData failed: "), status);
309                        for (CounterList::iterator it = counters_.begin(); it != counters_.end(); it++) {
310                                (*it)->collect();
311                        }
312                }
313                void collect() {
314                        PDH_STATUS status;
315                        if ((status = PdhCollectQueryData(hQuery_)) != ERROR_SUCCESS)
316                                throw PDHException(_T("PdhCollectQueryData failed: "), status);
317                }
318
319                HQUERY getQueryHandle() const {
320                        return hQuery_;
321                }
322        };
323
324        class Enumerations {
325        public:
326
327                struct Counter {
328                        std::wstring name;
329                };
330                typedef std::list<Counter> Counters;
331                struct Instance {
332                        std::wstring name;
333                };
334                typedef std::list<Instance> Instances;
335                struct Object {
336                        std::wstring name;
337                        Instances instances;
338                        Counters counters;
339                };
340
341                typedef std::list<Object> Objects;
342                static Objects EnumObjects(DWORD dwDetailLevel = PERF_DETAIL_WIZARD) {
343                        Objects ret;
344
345                        DWORD dwObjectBufLen = 0;
346                        TCHAR* szObjectBuffer = NULL;
347                        PDH_STATUS status = PdhEnumObjects(NULL, NULL, szObjectBuffer, &dwObjectBufLen, dwDetailLevel, FALSE);
348                        if (status != PDH_MORE_DATA)
349                                throw PDHException(_T("PdhEnumObjects failed when trying to retrieve size of object buffer"), status);
350
351                        szObjectBuffer = new TCHAR[dwObjectBufLen+1024];
352                        status = PdhEnumObjects(NULL, NULL, szObjectBuffer, &dwObjectBufLen, dwDetailLevel, FALSE);
353                        if (status != ERROR_SUCCESS)
354                                throw PDHException(_T("PdhEnumObjects failed when trying to retrieve object buffer"), status);
355
356                        TCHAR *cp=szObjectBuffer;
357                        while(*cp != '\0') {
358                                Object o;
359                                o.name = cp;
360                                ret.push_back(o);
361                                cp += lstrlen(cp)+1;
362                        }
363                        delete [] szObjectBuffer;
364
365                        for (Objects::iterator it = ret.begin(); it != ret.end(); ++it) {
366                                DWORD dwCounterBufLen = 0;
367                                TCHAR* szCounterBuffer = NULL;
368                                DWORD dwInstanceBufLen = 0;
369                                TCHAR* szInstanceBuffer = NULL;
370                                status = PdhEnumObjectItems(NULL, NULL, (*it).name.c_str(), szCounterBuffer, &dwCounterBufLen, szInstanceBuffer, &dwInstanceBufLen, dwDetailLevel, 0);
371                                if (status == PDH_MORE_DATA) {
372                                        szCounterBuffer = new TCHAR[dwCounterBufLen+1024];
373                                        szInstanceBuffer = new TCHAR[dwInstanceBufLen+1024];
374                                        status = PdhEnumObjectItems(NULL, NULL, (*it).name.c_str(), szCounterBuffer, &dwCounterBufLen, szInstanceBuffer, &dwInstanceBufLen, dwDetailLevel, 0);
375                                        if (status != ERROR_SUCCESS)
376                                                throw PDHException(_T("PdhEnumObjectItems failed when trying to retrieve buffer for ") + (*it).name, status);
377
378                                        if (dwCounterBufLen > 0) {
379                                                cp=szCounterBuffer;
380                                                while(*cp != '\0') {
381                                                        Counter o;
382                                                        o.name = cp;
383                                                        (*it).counters.push_back(o);
384                                                        cp += lstrlen(cp)+1;
385                                                }
386                                        }
387                                        if (dwInstanceBufLen > 0) {
388                                                cp=szInstanceBuffer;
389                                                while(*cp != '\0') {
390                                                        Instance o;
391                                                        o.name = cp;
392                                                        (*it).instances.push_back(o);
393                                                        cp += lstrlen(cp)+1;
394                                                }
395                                        }
396                                        delete [] szCounterBuffer;
397                                        delete [] szInstanceBuffer;
398                                        //throw PDHException("PdhEnumObjectItems failed when trying to retrieve size for " + (*it).name, status);
399                                }
400                        }
401                        return ret;
402                }
403                /*
404                static str_lst EnumObjectItems(std::wstring object) {
405                        str_lst ret;
406                        DWORD bufLen = 4096;
407                        DWORD bufLen2 = 0;
408                        LPTSTR buf = new char[bufLen+1];
409                        PDH_STATUS status = PdhEnumObjectItems(NULL, NULL, object.c_str(), buf, &bufLen, NULL, &bufLen2, PERF_DETAIL_WIZARD, 0);
410                        if (status == ERROR_SUCCESS) {
411                                char *cp=buf;
412                                while(*cp != '\0') {
413                                        ret.push_back(std::wstring(cp));
414                                        cp += lstrlen(cp)+1;
415                                }
416                        }
417                        return ret;
418                }
419                static str_lst EnumObjectInstances(std::wstring object) {
420                        str_lst ret;
421                        DWORD bufLen = 4096;
422                        DWORD bufLen2 = 0;
423                        LPTSTR buf = new char[bufLen+1];
424                        PDH_STATUS status = PdhEnumObjectItems(NULL, NULL, object.c_str(), NULL, &bufLen2, buf, &bufLen, PERF_DETAIL_WIZARD, 0);
425                        if (status == ERROR_SUCCESS) {
426                                char *cp=buf;
427                                while(*cp != '\0') {
428                                        ret.push_back(std::wstring(cp));
429                                        cp += lstrlen(cp)+1;
430                                }
431                        }
432                        return ret;
433                }
434                */
435                static bool validate(std::wstring counter, std::wstring &error) {
436                        PDH_STATUS status = PdhValidatePath(counter.c_str());
437                        switch (status) {
438                                case ERROR_SUCCESS:
439                                        return true;
440                                case PDH_CSTATUS_NO_INSTANCE:
441                                        error = _T("The specified instance of the performance object was not found.");
442                                        break;
443                                case PDH_CSTATUS_NO_COUNTER:
444                                        error = _T("The specified counter was not found in the performance object.");
445                                        break;
446                                case PDH_CSTATUS_NO_MACHINE:
447                                        error = _T("The specified computer could not be found or connected to.");
448                                        break;
449                                case PDH_CSTATUS_BAD_COUNTERNAME:
450                                        error = _T("The counter path string could not be parsed.");
451                                        break;
452                                case PDH_MEMORY_ALLOCATION_FAILURE:
453                                        error = _T("The function is unable to allocate a required temporary buffer.");
454                                        break;
455                        }
456                        return false;
457                }
458        };
459
460
461}
Note: See TracBrowser for help on using the repository browser.