source: nscp/modules/CheckSystem/PDHCollector.cpp @ d9cdcb3

0.4.00.4.10.4.2
Last change on this file since d9cdcb3 was d9cdcb3, checked in by Michael Medin <michael@…>, 13 months ago
  • Fixed issue with check-cpu sampling interval being 10seconds and not 1/10 second.
  • Some git file transformations
  • Property mode set to 100644
File size: 9.7 KB
Line 
1//////////////////////////////////////////////////////////////////////////
2// PDH Collector
3//
4// Functions from this file collects data from the PDH subsystem and stores
5// it for later use
6// *NOTICE* that this is done in a separate thread so threading issues has
7// to be handled. I handle threading issues in the CounterListener's get/
8// set accessors.
9//
10// Copyright (c) 2004 MySolutions NORDIC (http://www.medin.nu)
11//
12// Date: 2004-03-13
13// Author: Michael Medin - <michael@medin.name>
14//
15// This software is provided "AS IS", without a warranty of any kind.
16// You are free to use/modify this code but leave this header intact.
17//
18//////////////////////////////////////////////////////////////////////////
19
20#include "stdafx.h"
21#include "PDHCollector.h"
22#include <sysinfo.h>
23#include "settings.hpp"
24
25PDHCollector::PDHCollector() : hStopEvent_(NULL)/*, data_(NULL)*/ {
26        std::wstring subsystem = SETTINGS_GET_STRING(check_system::PDH_SUBSYSTEM);
27        if (subsystem == setting_keys::check_system::PDH_SUBSYSTEM_FAST) {
28        } else if (subsystem == setting_keys::check_system::PDH_SUBSYSTEM_THREAD_SAFE) {
29                PDH::PDHFactory::set_threadSafe();
30        } else {
31                NSC_LOG_ERROR_STD(_T("Unknown PDH subsystem (") + subsystem + _T(") valid values are: fast and thread-safe"));
32        }
33}
34
35PDHCollector::~PDHCollector()
36{
37        if (hStopEvent_)
38                CloseHandle(hStopEvent_);
39//      delete data_;
40}
41
42boost::shared_ptr<PDHCollectors::PDHCollector> PDHCollector::system_counter_data::counter::create(int check_intervall) {
43        if (data_type == type_uint64 && data_format == format_large && collection_strategy == value) {
44                return boost::shared_ptr<PDHCollectors::PDHCollector>(new PDHCollectors::StaticPDHCounterListener<unsigned __int64, PDHCollectors::format_large, PDHCollectors::PDHCounterNormalMutex>);
45        } else if (data_type == type_int64 && data_format == format_large && collection_strategy == value) {
46                return boost::shared_ptr<PDHCollectors::PDHCollector>(new PDHCollectors::StaticPDHCounterListener<__int64, PDHCollectors::format_large, PDHCollectors::PDHCounterNormalMutex>);
47        } else if (data_type == type_int64 && data_format == format_large && collection_strategy == rrd) {
48                unsigned int buffer_size = get_buffer_length(check_intervall);
49                return boost::shared_ptr<PDHCollectors::PDHCollector>(new PDHCollectors::RoundINTPDHBufferListener<__int64, PDHCollectors::format_large, PDHCollectors::PDHCounterNormalMutex>(buffer_size));
50        }
51        return boost::shared_ptr<PDHCollectors::PDHCollector>();
52}
53
54
55/**
56* Thread that collects the data every "CHECK_INTERVAL" seconds.
57*
58* @param lpParameter Not used
59* @return thread exit status
60*
61* @author mickem
62*
63* @date 03-13-2004               
64*
65* @bug If we have "custom named" counters ?
66* @bug This whole concept needs work I think.
67*
68*/
69DWORD PDHCollector::threadProc(LPVOID lpParameter) {
70        hStopEvent_ = CreateEvent(NULL, TRUE, FALSE, NULL);
71        if (!hStopEvent_) {
72                NSC_LOG_ERROR_STD(_T("Create StopEvent failed: ") + error::lookup::last_error());
73                return 0;
74        }
75
76        system_counter_data *data = reinterpret_cast<system_counter_data*>(lpParameter);
77
78        check_intervall_ = data->check_intervall;
79        std::wstring default_buffer_length = data->buffer_length;
80        PDH::PDHQuery pdh;
81        bool bInit = true;
82
83        {
84                SetThreadLocale(MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT));
85                WriteLock lock(&mutex_, true, 5000);
86                if (!lock.IsLocked()) {
87                        NSC_LOG_ERROR_STD(_T("Failed to get mutex when trying to start thread... thread will now die..."));
88                        bInit = false;
89                } else {
90                        pdh.removeAllCounters();
91                        NSC_DEBUG_MSG_STD(_T("Loading counters..."));
92                        BOOST_FOREACH(system_counter_data::counter c, data->counters) {
93                                try {
94                                        NSC_DEBUG_MSG_STD(_T("Loading counter: ") + c.alias + _T(" = ") + c.path);
95                                        c.set_default_buffer_size(default_buffer_length);
96                                        collector_ptr collector = c.create(check_intervall_);
97                                        if (collector) {
98                                                counters_[c.alias] = collector;
99                                                pdh.addCounter(c.path, collector);
100                                        } else {
101                                                NSC_LOG_ERROR_STD(_T("Failed to load counter: ") + c.alias + _T(" = ") + c.path);
102                                        }
103                                } catch (...) {
104                                        NSC_LOG_ERROR_STD(_T("EXCEPTION: Failed to load counter: ") + c.alias + _T(" = ") + c.path);
105                                }
106                        }
107                        try {
108                                pdh.open();
109                        } catch (const PDH::PDHException &e) {
110                                NSC_LOG_ERROR_STD(_T("Failed to open performance counters: ") + e.getError());
111                                bInit = false;
112                        }
113                }
114        }
115        data = NULL;
116        delete data;
117
118        DWORD waitStatus = 0;
119        if (bInit) {
120                bool first = true;
121                do {
122                        std::list<std::wstring> errors;
123                        {
124                                ReadLock lock(&mutex_, true, 5000);
125                                if (!lock.IsLocked()) {
126                                        NSC_LOG_ERROR(_T("Failed to get Mutex!"));
127                                } else {
128                                        try {
129                                                pdh.gatherData();
130                                        } catch (const PDH::PDHException &e) {
131                                                if (first) {    // If this is the first run an error will be thrown since the data is not yet available
132                                                        // This is "ok" but perhaps another solution would be better, but this works :)
133                                                        first = false;
134                                                } else {
135                                                        errors.push_back(_T("Failed to query performance counters: ") + e.getError());
136                                                }
137                                        } catch (...) {
138                                                errors.push_back(_T("Failed to query performance counters: "));
139                                        }
140                                }
141                        }
142                        for (std::list<std::wstring>::const_iterator cit = errors.begin(); cit != errors.end(); ++cit) {
143                                NSC_LOG_ERROR_STD(*cit);
144                        }
145                } while (((waitStatus = WaitForSingleObject(hStopEvent_, check_intervall_*100)) == WAIT_TIMEOUT));
146        } else {
147                NSC_LOG_ERROR_STD(_T("No performance counters were found we will not wait for the end instead..."));
148                waitStatus = WaitForSingleObject(hStopEvent_, INFINITE);
149        }
150        if (waitStatus != WAIT_OBJECT_0) {
151                NSC_LOG_ERROR(_T("Something odd happened when terminating PDH collection thread!"));
152        }
153
154        {
155                WriteLock lock(&mutex_, true, 5000);
156                if (!lock.IsLocked()) {
157                        NSC_LOG_ERROR(_T("Failed to get Mute when closing thread!"));
158                }
159
160                if (!CloseHandle(hStopEvent_)) {
161                        NSC_LOG_ERROR_STD(_T("Failed to close stopEvent handle: ") + error::lookup::last_error());
162                } else
163                        hStopEvent_ = NULL;
164                try {
165                        pdh.close();
166                } catch (const PDH::PDHException &e) {
167                        NSC_LOG_ERROR_STD(_T("Failed to close performance counters: ") + e.getError());
168                }
169        }
170        return 0;
171}
172
173__int64 PDHCollector::get_int_value(std::wstring counter) {
174        ReadLock lock(&mutex_, true, 5000);
175        if (!lock.IsLocked())  {
176                NSC_LOG_ERROR(_T("Failed to get Mutex for: ") + counter);
177                return 0;
178        }
179
180        counter_map::iterator it = counters_.find(counter);
181        if (it == counters_.end())
182                return 0;
183        collector_ptr ptr = (*it).second;
184        return ptr->get_int64();
185}
186
187double PDHCollector::get_avg_value(std::wstring counter, unsigned int delta) {
188        ReadLock lock(&mutex_, true, 5000);
189        if (!lock.IsLocked())  {
190                NSC_LOG_ERROR(_T("Failed to get Mutex for: ") + counter);
191                return 0;
192        }
193
194        counter_map::iterator it = counters_.find(counter);
195        if (it == counters_.end())
196                return 0;
197        collector_ptr ptr = (*it).second;
198        return ptr->get_average(delta);
199}
200
201
202/**
203* Request termination of the thread (waiting for thread termination is not handled)
204*/
205void PDHCollector::exitThread(void) {
206        if (hStopEvent_ == NULL) {
207                NSC_LOG_ERROR(_T("Stop event is not created!"));
208        } else if (!SetEvent(hStopEvent_)) {
209                        NSC_LOG_ERROR_STD(_T("SetStopEvent failed"));
210        }
211}
212/**
213* Get the average CPU usage for "time"
214* @param time Time to check
215* @return average CPU usage
216*/
217int PDHCollector::getCPUAvrage(std::wstring time) {
218        int frequency;
219        {
220                ReadLock lock(&mutex_, true, 5000);
221                if (!lock.IsLocked()) {
222                        NSC_LOG_ERROR(_T("Failed to get Mutex!"));
223                        return -1;
224                }
225                frequency = check_intervall_*100;
226
227        }
228        try {
229                unsigned int mseconds = strEx::stoui_as_time(time);
230                return static_cast<int>(get_avg_value(PDH_SYSTEM_KEY_CPU, mseconds/frequency));
231        } catch (PDHCollectors::PDHException &e) {
232                NSC_LOG_ERROR(_T("Failed to get CPU value: ") + e.getError());
233                return -1;
234        } catch (...) {
235                NSC_LOG_ERROR(_T("Failed to get CPU value"));
236                return -1;
237        }
238}
239/**
240* Get uptime from counter
241* @bug Do we need to collect this all the time ? (perhaps we can collect this in real time ?)
242* @return uptime for the system
243* @bug Are we overflow protected here ? (seem to recall some issues with overflow before ?)
244*/
245long long PDHCollector::getUptime() {
246        try {
247                return get_int_value(PDH_SYSTEM_KEY_UPT);
248        } catch (PDHCollectors::PDHException &e) {
249                NSC_LOG_ERROR(_T("Failed to get UPTIME value: ") + e.getError());
250                return -1;
251        } catch (...) {
252                NSC_LOG_ERROR(_T("Failed to get UPTIME value"));
253                return -1;
254        }
255}
256/**
257* Memory commit limit (your guess is as good as mine to what this is :)
258* @return Some form of memory check
259*/
260unsigned long long PDHCollector::getMemCommitLimit() {
261        try {
262                return get_int_value(PDH_SYSTEM_KEY_MCL);
263        } catch (PDHCollectors::PDHException &e) {
264                NSC_LOG_ERROR(_T("Failed to get MEM_CMT_LIMIT value: ") + e.getError());
265                return -1;
266        } catch (...) {
267                NSC_LOG_ERROR(_T("Failed to get MEM_CMT_LIMIT value"));
268                return -1;
269        }
270}
271/**
272*
273* Memory committed bytes (your guess is as good as mine to what this is :)
274* @return Some form of memory check
275*/
276unsigned long long PDHCollector::getMemCommit() {
277        try {
278                return get_int_value(PDH_SYSTEM_KEY_MCB);
279        } catch (PDHCollectors::PDHException &e) {
280                NSC_LOG_ERROR(_T("Failed to get MEM_CMT value: ") + e.getError());
281                return -1;
282        } catch (...) {
283                NSC_LOG_ERROR(_T("Failed to get MEM_CMT value"));
284                return -1;
285        }
286}
287
288double PDHCollector::get_double(std::wstring counter) {
289        ReadLock lock(&mutex_, true, 5000);
290        if (!lock.IsLocked()) {
291                NSC_LOG_ERROR(_T("Failed to get Mutex!"));
292                return -1;
293        }
294        try {
295                counter_map::iterator it = counters_.find(counter);
296                if (it == counters_.end()) {
297                        NSC_LOG_ERROR(_T("COunter not found: ") + counter);
298                        return -1;
299                }
300                return (*it).second->get_double();
301        } catch (PDHCollectors::PDHException &e) {
302                NSC_LOG_ERROR(_T("Failed to get double value: ") + e.getError());
303                return -1;
304        } catch (...) {
305                NSC_LOG_ERROR(_T("Failed to get double value"));
306                return -1;
307        }
308}
Note: See TracBrowser for help on using the repository browser.