source: nscp/trunk/modules/CheckSystem/PDHCollector.cpp @ 34f5502

Last change on this file since 34f5502 was 34f5502, checked in by Michael Medin <michael@…>, 5 years ago

+ Added propper output handling to process subsystem (now you can execute programs tat return "much" data.

+ Added select support for SSL_write (now you can send "any amount of data" to the (SSL) socket.

Since check_nrpe doesn't do this it wont work in that end, but still...

  • Property mode set to 100644
File size: 11.4 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 <Settings.h>
23#include <sysinfo.h>
24
25
26PDHCollector::PDHCollector() : hStopEvent_(NULL) {
27        checkIntervall_ = NSCModuleHelper::getSettingsInt(C_SYSTEM_SECTION_TITLE, C_SYSTEM_CHECK_RESOLUTION, C_SYSTEM_CHECK_RESOLUTION_DEFAULT);
28        std::wstring s = NSCModuleHelper::getSettingsString(C_SYSTEM_SECTION_TITLE, C_SYSTEM_CPU_BUFFER_TIME, C_SYSTEM_CPU_BUFFER_TIME_DEFAULT);
29        unsigned int i = strEx::stoui_as_time(s, checkIntervall_*100);
30        cpu.resize(i/(checkIntervall_*100));
31}
32
33PDHCollector::~PDHCollector()
34{
35        if (hStopEvent_)
36                CloseHandle(hStopEvent_);
37}
38
39bool PDHCollector::loadCounter(PDH::PDHQuery &pdh) {
40        if (NSCModuleHelper::getSettingsInt(C_SYSTEM_SECTION_TITLE, C_SYSTEM_AUTODETECT_PDH, C_SYSTEM_AUTODETECT_PDH_DEFAULT) != 1) {
41                NSC_DEBUG_MSG_STD(_T("Autodetect disabled from nsc.ini via: ") + C_SYSTEM_AUTODETECT_PDH);
42                return false;
43        }
44        std::wstring prefix;
45        std::wstring section = NSCModuleHelper::getSettingsString(C_SYSTEM_SECTION_TITLE, C_SYSTEM_FORCE_LANGUAGE, C_SYSTEM_FORCE_LANGUAGE_DEFAULT);
46        int noIndex = NSCModuleHelper::getSettingsInt(C_SYSTEM_SECTION_TITLE, C_SYSTEM_NO_INDEX, C_SYSTEM_NO_INDEX_DEFAULT);
47        bool bUseIndex = false;
48
49        // Investigate environment and find out what to use
50        try {
51                OSVERSIONINFO osVer = systemInfo::getOSVersion();
52                if (!systemInfo::isNTBased(osVer)) {
53                        NSC_LOG_ERROR_STD(_T("Detected Windows 3.x or Windows 9x, PDH will be disabled."));
54                        NSC_LOG_ERROR_STD(_T("To manual set performance counters you need to first set ") C_SYSTEM_AUTODETECT_PDH _T("=0 in the config file, and then you also need to configure the various counter."));
55                        return false;
56                }
57
58                LANGID langId = -1;
59                if (systemInfo::isBelowNT4(osVer)) {
60                        NSC_DEBUG_MSG_STD(_T("Autodetected NT4, using NT4 PDH counters."));
61                        prefix = _T("NT4");
62                        bUseIndex = false;
63                        langId = systemInfo::GetSystemDefaultLangID();
64                } else if (systemInfo::isAboveW2K(osVer)) {
65                        NSC_DEBUG_MSG_STD(_T("Autodetected w2k or later, using w2k PDH counters."));
66                        bUseIndex = true;
67                        prefix = _T("W2K");
68                        langId = systemInfo::GetSystemDefaultUILanguage();
69                } else {
70                        NSC_LOG_ERROR_STD(_T("Unknown OS detected, PDH will be disabled."));
71                        NSC_LOG_ERROR_STD(_T("To manual set performance counters you need to first set ") C_SYSTEM_AUTODETECT_PDH _T("=0 in the config file, and then you also need to configure the various counter."));
72                        return false;
73                }
74
75                if (!section.empty()) {
76                        NSC_DEBUG_MSG_STD(_T("Overriding language with: ") + section);
77                } else {
78                        section = _T("0000") + strEx::ihextos(langId);
79                        section = _T("0x") + section.substr(section.length()-4);
80                }
81                if (bUseIndex&&noIndex==1) {
82                        NSC_DEBUG_MSG_STD(_T("We wanted to use index but were forced not to use them due to: ") + C_SYSTEM_NO_INDEX);
83                        bUseIndex = false;
84                }
85        } catch (const systemInfo::SystemInfoException &e) {
86                NSC_LOG_ERROR_STD(_T("To manual set performance counters you need to first set ") C_SYSTEM_AUTODETECT_PDH _T("=0 in the config file, and then you also need to configure the various counter."));
87                NSC_LOG_ERROR_STD(_T("The Error: ") + e.getError());
88                return false;
89        } catch (...) {
90                NSC_LOG_ERROR_STD(_T("To manual set performance counters you need to first set ") C_SYSTEM_AUTODETECT_PDH _T("=0 in the config file, and then you also need to configure the various counter."));
91                NSC_LOG_ERROR_STD(_T("The Error: UNKNOWN_EXCEPTION"));
92                return false;
93        }
94
95        // Open counters via .defs file or index.
96        try {
97                std::wstring proc;
98                std::wstring uptime;
99                std::wstring memCl;
100                std::wstring memCb;
101                if (bUseIndex) {
102                        NSC_DEBUG_MSG_STD(_T("Using index to retrive counternames"));
103                        proc = _T("\\") + pdh.lookupIndex(238) + _T("(_total)\\") + pdh.lookupIndex(6);
104                        uptime = _T("\\") + pdh.lookupIndex(2) + _T("\\") + pdh.lookupIndex(674);
105                        memCl = _T("\\") + pdh.lookupIndex(4) + _T("\\") + pdh.lookupIndex(30);
106                        memCb = _T("\\") + pdh.lookupIndex(4) + _T("\\") + pdh.lookupIndex(26);
107                } else {
108                        SettingsT settings;
109                        settings.setFile(NSCModuleHelper::getBasePath(),  _T("counters.defs"), true);
110                        NSC_DEBUG_MSG_STD(_T("Detected language: ") + settings.getString(section, _T("Description"), _T("Not found")) + _T(" (") + section + _T(")"));
111                        if (settings.getString(section, _T("Description"), _T("_NOT_FOUND")) == _T("_NOT_FOUND")) {
112                                NSC_LOG_ERROR_STD(_T("Detected language: ") + section + _T(" but it could not be found in: counters.defs"));
113                                NSC_LOG_ERROR_STD(_T("You need to manually configure performance counters!"));
114                                return false;
115                        }
116                        NSC_DEBUG_MSG_STD(_T("Attempting to get localized PDH values from the .defs file"));
117                        proc = settings.getString(section, prefix + _T("_") + C_SYSTEM_CPU, C_SYSTEM_MEM_CPU_DEFAULT);
118                        uptime = settings.getString(section, prefix + _T("_") + C_SYSTEM_UPTIME, C_SYSTEM_UPTIME_DEFAULT);
119                        memCl = settings.getString(section, prefix + _T("_") + C_SYSTEM_MEM_PAGE_LIMIT, C_SYSTEM_MEM_PAGE_LIMIT_DEFAULT);
120                        memCb = settings.getString(section, prefix + _T("_") + C_SYSTEM_MEM_PAGE, C_SYSTEM_MEM_PAGE_DEFAULT);
121                }
122                NSC_DEBUG_MSG_STD(_T("Found countername: CPU:    ") + proc);
123                NSC_DEBUG_MSG_STD(_T("Found countername: UPTIME: ") + uptime);
124                NSC_DEBUG_MSG_STD(_T("Found countername: MCL:    ") + memCl);
125                NSC_DEBUG_MSG_STD(_T("Found countername: MCB:    ") + memCb);
126                pdh.addCounter(proc, &cpu);
127                pdh.addCounter(uptime, &upTime);
128                pdh.addCounter(memCl, &memCmtLim);
129                pdh.addCounter(memCb, &memCmt);
130                pdh.open();
131        } catch (const PDH::PDHException &e) {
132                NSC_LOG_ERROR_STD(_T("Failed to open performance counters: ") + e.getError());
133                return false;
134        }
135        return true;
136}
137
138/**
139* Thread that collects the data every "CHECK_INTERVAL" seconds.
140*
141* @param lpParameter Not used
142* @return thread exit status
143*
144* @author mickem
145*
146* @date 03-13-2004               
147*
148* @bug If we have "custom named" counters ?
149* @bug This whole concept needs work I think.
150*
151*/
152DWORD PDHCollector::threadProc(LPVOID lpParameter) {
153        hStopEvent_ = CreateEvent(NULL, TRUE, FALSE, NULL);
154        if (!hStopEvent_) {
155                NSC_LOG_ERROR_STD(_T("Create StopEvent failed: ") + error::lookup::last_error());
156                return 0;
157        }
158        PDH::PDHQuery pdh;
159        bool bInit = true;
160
161        {
162                WriteLock lock(&mutex_, true, 5000);
163                if (!lock.IsLocked()) {
164                        NSC_LOG_ERROR_STD(_T("Failed to get mutex when trying to start thread... thread will now die..."));
165                        bInit = false;
166                } else if (!loadCounter(pdh)) {
167                        pdh.removeAllCounters();
168                        NSC_DEBUG_MSG_STD(_T("We aparently failed to load counters trying to use default (English) counters or those configured in nsc.ini"));
169                        SetThreadLocale(MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT));
170                        pdh.addCounter(NSCModuleHelper::getSettingsString(C_SYSTEM_SECTION_TITLE, C_SYSTEM_MEM_PAGE_LIMIT, C_SYSTEM_MEM_PAGE_LIMIT_DEFAULT), &memCmtLim);
171                        pdh.addCounter(NSCModuleHelper::getSettingsString(C_SYSTEM_SECTION_TITLE, C_SYSTEM_MEM_PAGE, C_SYSTEM_MEM_PAGE_DEFAULT), &memCmt);
172                        pdh.addCounter(NSCModuleHelper::getSettingsString(C_SYSTEM_SECTION_TITLE, C_SYSTEM_UPTIME, C_SYSTEM_UPTIME_DEFAULT), &upTime);
173                        pdh.addCounter(NSCModuleHelper::getSettingsString(C_SYSTEM_SECTION_TITLE, C_SYSTEM_CPU, C_SYSTEM_MEM_CPU_DEFAULT), &cpu);
174                        try {
175                                pdh.open();
176                        } catch (const PDH::PDHException &e) {
177                                NSC_LOG_ERROR_STD(_T("Failed to open performance counters: ") + e.getError());
178                                bInit = false;
179                        }
180                }
181        }
182
183        DWORD waitStatus = 0;
184        if (bInit) {
185                bool first = true;
186                do {
187                        std::list<std::wstring> errors;
188                        {
189                                ReadLock lock(&mutex_, true, 5000);
190                                if (!lock.IsLocked())
191                                        NSC_LOG_ERROR(_T("Failed to get Mutex!"));
192                                else {
193                                        try {
194                                                pdh.gatherData();
195                                        } catch (const PDH::PDHException &e) {
196                                                if (first) {    // If this is the first run an error will be thrown since the data is not yet avalible
197                                                        // This is "ok" but perhaps another solution would be better, but this works :)
198                                                        first = false;
199                                                } else {
200                                                        errors.push_back(_T("Failed to query performance counters: ") + e.getError());
201                                                }
202                                        }
203                                }
204                        }
205                        for (std::list<std::wstring>::const_iterator cit = errors.begin(); cit != errors.end(); ++cit) {
206                                NSC_LOG_ERROR_STD(*cit);
207                        }
208                } while (((waitStatus = WaitForSingleObject(hStopEvent_, checkIntervall_*100)) == WAIT_TIMEOUT));
209        } else {
210                NSC_LOG_ERROR_STD(_T("No performance counters were found we will not wait for the end instead..."));
211                waitStatus = WaitForSingleObject(hStopEvent_, INFINITE);
212        }
213        if (waitStatus != WAIT_OBJECT_0) {
214                NSC_LOG_ERROR(_T("Something odd happened when terminating PDH collection thread!"));
215        }
216
217        {
218                WriteLock lock(&mutex_, true, 5000);
219                if (!lock.IsLocked()) {
220                        NSC_LOG_ERROR(_T("Failed to get Mute when closing thread!"));
221                }
222
223                if (!CloseHandle(hStopEvent_)) {
224                        NSC_LOG_ERROR_STD(_T("Failed to close stopEvent handle: ") + error::lookup::last_error());
225                } else
226                        hStopEvent_ = NULL;
227                try {
228                        pdh.close();
229                } catch (const PDH::PDHException &e) {
230                        NSC_LOG_ERROR_STD(_T("Failed to close performance counters: ") + e.getError());
231                }
232        }
233        return 0;
234}
235
236
237/**
238* Request termination of the thread (waiting for thread termination is not handled)
239*/
240void PDHCollector::exitThread(void) {
241        if (hStopEvent_ == NULL)
242                NSC_LOG_ERROR(_T("Stop event is not created!"));
243        else if (!SetEvent(hStopEvent_)) {
244                        NSC_LOG_ERROR_STD(_T("SetStopEvent failed"));
245        }
246}
247/**
248* Get the average CPU usage for "time"
249* @param time Time to check
250* @return average CPU usage
251*/
252int PDHCollector::getCPUAvrage(std::wstring time) {
253        unsigned int mseconds = strEx::stoui_as_time(time, checkIntervall_*100);
254        ReadLock lock(&mutex_, true, 5000);
255        if (!lock.IsLocked()) {
256                NSC_LOG_ERROR(_T("Failed to get Mutex!"));
257                return -1;
258        }
259        try {
260                return static_cast<int>(cpu.getAvrage(mseconds / (checkIntervall_*100)));
261        } catch (PDHCollectors::PDHException &e) {
262                NSC_LOG_ERROR(_T("Failed to get (sub) Mutex!"));
263                return -1;
264        }
265}
266/**
267* Get uptime from counter
268* @bug Do we need to collect this all the time ? (perhaps we can collect this in real time ?)
269* @return uptime for the system
270* @bug Are we overflow protected here ? (seem to recall some issues with overflow before ?)
271*/
272long long PDHCollector::getUptime() {
273        ReadLock lock(&mutex_, true, 5000);
274        if (!lock.IsLocked()) {
275                NSC_LOG_ERROR(_T("Failed to get Mutex!"));
276                return -1;
277        }
278        return upTime.getValue();
279}
280/**
281* Memory commit limit (your guess is as good as mine to what this is :)
282* @return Some form of memory check
283*/
284unsigned long long PDHCollector::getMemCommitLimit() {
285        ReadLock lock(&mutex_, true, 5000);
286        if (!lock.IsLocked()) {
287                NSC_LOG_ERROR(_T("Failed to get Mutex!"));
288                return -1;
289        }
290        return memCmtLim.getValue();
291}
292/**
293*
294* Memory committed bytes (your guess is as good as mine to what this is :)
295* @return Some form of memory check
296*/
297unsigned long long PDHCollector::getMemCommit() {
298        ReadLock lock(&mutex_, true, 5000);
299        if (!lock.IsLocked()) {
300                NSC_LOG_ERROR(_T("Failed to get Mutex!"));
301                return -1;
302        }
303        return memCmt.getValue();
304}
Note: See TracBrowser for help on using the repository browser.