source: nscp/include/PDHCounter.h @ 5b40546

0.4.00.4.10.4.2stable
Last change on this file since 5b40546 was 5b40546, checked in by Michael Medin <michael@…>, 6 years ago

nothing much really... probably tinkering...

  • Property mode set to 100644
File size: 12.4 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        class PDHException {
31        private:
32                std::string str_;
33                std::string name_;
34                PDH_STATUS pdhStatus_;
35        public:
36                PDHException(std::string name, std::string str, PDH_STATUS pdhStatus = 0) : name_(name), str_(str), pdhStatus_(pdhStatus) {}
37                PDHException(std::string str, PDH_STATUS pdhStatus) : str_(str), pdhStatus_(pdhStatus) {}
38                PDHException(std::string str) : str_(str), pdhStatus_(0) {}
39                std::string getError() const {
40                        std::string ret;
41                        if (!name_.empty())
42                                ret += name_ + ": ";
43                        ret += str_;
44                        if (pdhStatus_ != 0) {
45                                ret += ": " + error::format::from_module("PDH.DLL", pdhStatus_);
46                        }
47                        return ret;
48                }
49        };
50
51        class PDHCounter;
52        class PDHCounterListener {
53        public:
54                virtual void collect(const PDHCounter &counter) = 0;
55                virtual void attach(const PDHCounter &counter) = 0;
56                virtual void detach(const PDHCounter &counter) = 0;
57                virtual DWORD getFormat() const = 0;
58        };
59
60        class PDHCounterInfo {
61        public:
62                DWORD   dwType;
63                DWORD   CVersion;
64                DWORD   CStatus;
65                LONG    lScale;
66                LONG    lDefaultScale;
67                DWORD_PTR   dwUserData;
68                DWORD_PTR   dwQueryUserData;
69                std::string  szFullPath;
70
71                std::string   szMachineName;
72                std::string   szObjectName;
73                std::string   szInstanceName;
74                std::string   szParentInstance;
75                DWORD    dwInstanceIndex;
76                std::string   szCounterName;
77
78                std::string  szExplainText;
79
80                PDHCounterInfo(BYTE *lpBuffer, DWORD dwBufferSize, BOOL explainText) {
81                        PDH_COUNTER_INFO *info = (PDH_COUNTER_INFO*)lpBuffer;
82                        dwType = info->dwType;
83                        CVersion = info->CVersion;
84                        CStatus = info->CStatus;
85                        lScale = info->lScale;
86                        lDefaultScale = info->lDefaultScale;
87                        dwUserData = info->dwUserData;
88                        dwQueryUserData = info->dwQueryUserData;
89                        szFullPath = info->szFullPath;
90                        if (info->szMachineName)
91                                szMachineName = info->szMachineName;
92                        if (info->szObjectName)
93                                szObjectName = info->szObjectName;
94                        if (info->szInstanceName)
95                                szInstanceName = info->szInstanceName;
96                        if (info->szParentInstance)
97                                szParentInstance = info->szParentInstance;
98                        dwInstanceIndex = info->dwInstanceIndex;
99                        if (info->szCounterName)
100                                szCounterName = info->szCounterName;
101                        if (explainText) {
102                                if (info->szExplainText)
103                                        szExplainText = info->szExplainText;
104                        }
105                }
106        };
107
108        class PDHCounter
109        {
110        private:
111                HCOUNTER hCounter_;
112                std::string name_;
113                PDH_FMT_COUNTERVALUE data_;
114                PDHCounterListener *listener_;
115
116        public:
117
118                PDHCounter(std::string name, PDHCounterListener *listener) : name_(name), listener_(listener), hCounter_(NULL){}
119                PDHCounter(std::string name) : name_(name), listener_(NULL), hCounter_(NULL){}
120                virtual ~PDHCounter(void) {
121                        if (hCounter_ != NULL)
122                                remove();
123                }
124
125                void setListener(PDHCounterListener *listener) {
126                        listener_ = listener;
127                }
128
129                PDHCounterInfo getCounterInfo(BOOL bExplainText = FALSE) {
130                        assert(hCounter_ != NULL);
131                        PDH_STATUS status;
132                        BYTE *lpBuffer = new BYTE[1025];
133                        DWORD bufSize = 1024;
134                        if ((status = PdhGetCounterInfo(hCounter_, bExplainText, &bufSize, (PDH_COUNTER_INFO*)lpBuffer)) != ERROR_SUCCESS) {
135                                throw PDHException(name_, "getCounterInfo failed (no query)", status);
136                        }
137                        return PDHCounterInfo(lpBuffer, bufSize, TRUE);
138                }
139                const HCOUNTER getCounter() const {
140                        return hCounter_;
141                }
142                const std::string getName() const {
143                        return name_;
144                }
145                void addToQuery(HQUERY hQuery) {
146                        PDH_STATUS status;
147                        if (hQuery == NULL)
148                                throw PDHException(name_, "addToQuery failed (no query).");
149                        if (hCounter_ != NULL)
150                                throw PDHException(name_, "addToQuery failed (already opened).");
151                        if (listener_)
152                                listener_->attach(*this);
153                        if ((status = PdhAddCounter(hQuery, name_.c_str(), 0, &hCounter_)) != ERROR_SUCCESS) {
154                                hCounter_ = NULL;
155                                throw PDHException(name_, "PdhOpenQuery failed", status);
156                        }
157                        assert(hCounter_ != NULL);
158                }
159                void remove() {
160                        if (hCounter_ == NULL)
161                                return;
162                        PDH_STATUS status;
163                        if (listener_)
164                                listener_->detach(*this);
165                        if ((status = PdhRemoveCounter(hCounter_)) != ERROR_SUCCESS)
166                                throw PDHException(name_, "PdhRemoveCounter failed", status);
167                        hCounter_ = NULL;
168                }
169                void collect() {
170                        if (hCounter_ == NULL)
171                                return;
172                        PDH_STATUS status;
173                        if (!listener_)
174                                return;
175                        if ((status = PdhGetFormattedCounterValue(hCounter_, listener_->getFormat(), NULL, &data_)) != ERROR_SUCCESS)
176                                throw PDHException(name_, "PdhGetFormattedCounterValue failed", status);
177                        listener_->collect(*this);
178                }
179                double getDoubleValue() const {
180                        return data_.doubleValue;
181                }
182                __int64 getInt64Value() const {
183                        return data_.largeValue;
184                }
185                long getIntValue() const {
186                        return data_.longValue;
187                }
188                std::string getStringValue() const {
189                        return data_.AnsiStringValue;
190                }
191        };
192
193        class PDHQuery
194        {
195        private:
196                typedef std::list<PDHCounter*> CounterList;
197                CounterList counters_;
198                HQUERY hQuery_;
199        public:
200                PDHQuery() : hQuery_(NULL) {
201                }
202                virtual ~PDHQuery(void) {
203                        if (hQuery_)
204                                close();
205                        for (CounterList::iterator it = counters_.begin(); it != counters_.end(); it++) {
206                                delete (*it);
207                        }
208                        counters_.clear();
209                }
210
211                PDHCounter* addCounter(std::string name, PDHCounterListener *listener) {
212                        PDHCounter *counter = new PDHCounter(name, listener);
213                        counters_.push_back(counter);
214                        return counter;
215                }
216                PDHCounter* addCounter(std::string name) {
217                        PDHCounter *counter = new PDHCounter(name);
218                        counters_.push_back(counter);
219                        return counter;
220                }
221
222                void open() {
223                        assert(hQuery_ == NULL);
224                        PDH_STATUS status;
225                        if( (status = PdhOpenQuery( NULL, 0, &hQuery_ )) != ERROR_SUCCESS)
226                                throw PDHException("PdhOpenQuery failed", status);
227                        for (CounterList::iterator it = counters_.begin(); it != counters_.end(); it++) {
228                                (*it)->addToQuery(getQueryHandle());
229                        }
230                }
231
232                void close() {
233                        assert(hQuery_ != NULL);
234                        DWORD x = PDH_INVALID_HANDLE;
235                        PDH_STATUS status;
236                        for (CounterList::iterator it = counters_.begin(); it != counters_.end(); it++) {
237                                (*it)->remove();
238                        }
239                        if( (status = PdhCloseQuery(hQuery_)) != ERROR_SUCCESS)
240                                throw PDHException("PdhCloseQuery failed", status);
241                        hQuery_ = NULL;
242                        for (CounterList::iterator it = counters_.begin(); it != counters_.end(); it++) {
243                                delete (*it);
244                        }
245                        counters_.clear();
246                }
247
248                void gatherData() {
249                        PDH_STATUS status;
250                        if ((status = PdhCollectQueryData(hQuery_)) != ERROR_SUCCESS)
251                                throw PDHException("PdhCollectQueryData failed: ", status);
252                        for (CounterList::iterator it = counters_.begin(); it != counters_.end(); it++) {
253                                (*it)->collect();
254                        }
255                }
256                void collect() {
257                        PDH_STATUS status;
258                        if ((status = PdhCollectQueryData(hQuery_)) != ERROR_SUCCESS)
259                                throw PDHException("PdhCollectQueryData failed: ", status);
260                }
261
262                HQUERY getQueryHandle() const {
263                        return hQuery_;
264                }
265        };
266
267        class Enumerations {
268        public:
269
270                struct Counter {
271                        std::string name;
272                };
273                typedef std::list<Counter> Counters;
274                struct Instance {
275                        std::string name;
276                };
277                typedef std::list<Instance> Instances;
278                struct Object {
279                        std::string name;
280                        Instances instances;
281                        Counters counters;
282                };
283
284                typedef std::list<Object> Objects;
285                static Objects EnumObjects(DWORD dwDetailLevel = PERF_DETAIL_WIZARD) {
286                        Objects ret;
287
288                        DWORD dwObjectBufLen = 0;
289                        LPTSTR szObjectBuffer = NULL;
290                        PDH_STATUS status = PdhEnumObjects(NULL, NULL, szObjectBuffer, &dwObjectBufLen, dwDetailLevel, FALSE);
291                        if (status != PDH_MORE_DATA)
292                                throw PDHException("PdhEnumObjects failed when trying to retrieve size of object buffer", status);
293
294                        szObjectBuffer = new char[dwObjectBufLen+1024];
295                        status = PdhEnumObjects(NULL, NULL, szObjectBuffer, &dwObjectBufLen, dwDetailLevel, FALSE);
296                        if (status != ERROR_SUCCESS)
297                                throw PDHException("PdhEnumObjects failed when trying to retrieve object buffer", status);
298
299                        char *cp=szObjectBuffer;
300                        while(*cp != '\0') {
301                                Object o;
302                                o.name = cp;
303                                ret.push_back(o);
304                                cp += lstrlen(cp)+1;
305                        }
306                        delete [] szObjectBuffer;
307
308                        for (Objects::iterator it = ret.begin(); it != ret.end(); ++it) {
309                                DWORD dwCounterBufLen = 0;
310                                LPTSTR szCounterBuffer = NULL;
311                                DWORD dwInstanceBufLen = 0;
312                                LPTSTR szInstanceBuffer = NULL;
313                                status = PdhEnumObjectItems(NULL, NULL, (*it).name.c_str(), szCounterBuffer, &dwCounterBufLen, szInstanceBuffer, &dwInstanceBufLen, dwDetailLevel, 0);
314                                if (status == PDH_MORE_DATA) {
315                                        szCounterBuffer = new char[dwCounterBufLen+1024];
316                                        szInstanceBuffer = new char[dwInstanceBufLen+1024];
317                                        status = PdhEnumObjectItems(NULL, NULL, (*it).name.c_str(), szCounterBuffer, &dwCounterBufLen, szInstanceBuffer, &dwInstanceBufLen, dwDetailLevel, 0);
318                                        if (status != ERROR_SUCCESS)
319                                                throw PDHException("PdhEnumObjectItems failed when trying to retrieve buffer for " + (*it).name, status);
320
321                                        if (dwCounterBufLen > 0) {
322                                                cp=szCounterBuffer;
323                                                while(*cp != '\0') {
324                                                        Counter o;
325                                                        o.name = cp;
326                                                        (*it).counters.push_back(o);
327                                                        cp += lstrlen(cp)+1;
328                                                }
329                                        }
330                                        if (dwInstanceBufLen > 0) {
331                                                cp=szInstanceBuffer;
332                                                while(*cp != '\0') {
333                                                        Instance o;
334                                                        o.name = cp;
335                                                        (*it).instances.push_back(o);
336                                                        cp += lstrlen(cp)+1;
337                                                }
338                                        }
339                                        delete [] szCounterBuffer;
340                                        delete [] szInstanceBuffer;
341                                        //throw PDHException("PdhEnumObjectItems failed when trying to retrieve size for " + (*it).name, status);
342                                }
343                        }
344                        return ret;
345                }
346                /*
347                static str_lst EnumObjectItems(std::string object) {
348                        str_lst ret;
349                        DWORD bufLen = 4096;
350                        DWORD bufLen2 = 0;
351                        LPTSTR buf = new char[bufLen+1];
352                        PDH_STATUS status = PdhEnumObjectItems(NULL, NULL, object.c_str(), buf, &bufLen, NULL, &bufLen2, PERF_DETAIL_WIZARD, 0);
353                        if (status == ERROR_SUCCESS) {
354                                char *cp=buf;
355                                while(*cp != '\0') {
356                                        ret.push_back(std::string(cp));
357                                        cp += lstrlen(cp)+1;
358                                }
359                        }
360                        return ret;
361                }
362                static str_lst EnumObjectInstances(std::string object) {
363                        str_lst ret;
364                        DWORD bufLen = 4096;
365                        DWORD bufLen2 = 0;
366                        LPTSTR buf = new char[bufLen+1];
367                        PDH_STATUS status = PdhEnumObjectItems(NULL, NULL, object.c_str(), NULL, &bufLen2, buf, &bufLen, PERF_DETAIL_WIZARD, 0);
368                        if (status == ERROR_SUCCESS) {
369                                char *cp=buf;
370                                while(*cp != '\0') {
371                                        ret.push_back(std::string(cp));
372                                        cp += lstrlen(cp)+1;
373                                }
374                        }
375                        return ret;
376                }
377                */
378                static bool validate(std::string counter, std::string &error) {
379                        PDH_STATUS status = PdhValidatePath(counter.c_str());
380                        switch (status) {
381                                case ERROR_SUCCESS:
382                                        return true;
383                                case PDH_CSTATUS_NO_INSTANCE:
384                                        error = "The specified instance of the performance object was not found.";
385                                        break;
386                                case PDH_CSTATUS_NO_COUNTER:
387                                        error = "The specified counter was not found in the performance object.";
388                                        break;
389                                case PDH_CSTATUS_NO_MACHINE:
390                                        error = "The specified computer could not be found or connected to.";
391                                        break;
392                                case PDH_CSTATUS_BAD_COUNTERNAME:
393                                        error = "The counter path string could not be parsed.";
394                                        break;
395                                case PDH_MEMORY_ALLOCATION_FAILURE:
396                                        error = "The function is unable to allocate a required temporary buffer.";
397                                        break;
398                        }
399                        return false;
400                }
401        };
402
403
404}
Note: See TracBrowser for help on using the repository browser.