windows performance counters with average value for n samples can be configured direc...
[public/netxms.git] / src / agent / subagents / winperf / tools.cpp
1 /*
2 ** Windows Performance NetXMS subagent
3 ** Copyright (C) 2004-2013 Victor Kirhenshtein
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** File: tools.cpp
20 **
21 **/
22
23 #include "winperf.h"
24
25 /**
26 * Max length of counter element
27 */
28 #define MAX_ELEMENT_LENGTH 1024
29
30 /**
31 * List of configured counters
32 */
33 static COUNTER_INDEX *m_pCounterList = NULL;
34 static DWORD m_dwNumCounters = 0;
35
36 /**
37 * Get error text for PDH functions
38 */
39 TCHAR *GetPdhErrorText(DWORD dwError, TCHAR *pszBuffer, int iBufferSize)
40 {
41 TCHAR *pszMsg;
42
43 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
44 FORMAT_MESSAGE_FROM_HMODULE |
45 FORMAT_MESSAGE_IGNORE_INSERTS,
46 GetModuleHandle(_T("PDH.DLL")), dwError,
47 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
48 (LPTSTR)&pszMsg, 0, NULL)>0)
49 {
50 TranslateStr(pszMsg, _T("\r\n"), _T(""));
51 nx_strncpy(pszBuffer, pszMsg, iBufferSize);
52 LocalFree(pszMsg);
53 }
54 else
55 {
56 GetSystemErrorText(dwError, pszBuffer, iBufferSize);
57 }
58 return pszBuffer;
59 }
60
61 /**
62 * Report PDH error to master agent's log
63 */
64 void ReportPdhError(TCHAR *pszFunction, TCHAR *pszPdhCall, PDH_STATUS dwError)
65 {
66 TCHAR szBuffer[1024];
67
68 AgentWriteLog(EVENTLOG_WARNING_TYPE, _T("%s: PDH Error %08X in call to %s (%s)"),
69 pszFunction, dwError, pszPdhCall, GetPdhErrorText(dwError, szBuffer, 1024));
70 }
71
72 /**
73 * Create index of counters
74 */
75 void CreateCounterIndex(TCHAR *pData)
76 {
77 TCHAR *pCurr;
78
79 for(pCurr = pData; *pCurr != 0; )
80 {
81 m_pCounterList = (COUNTER_INDEX *)realloc(m_pCounterList, sizeof(COUNTER_INDEX) * (m_dwNumCounters + 1));
82 m_pCounterList[m_dwNumCounters].dwIndex = _tcstoul(pCurr, NULL, 10);
83 pCurr += _tcslen(pCurr) + 1;
84 m_pCounterList[m_dwNumCounters].pszName = _tcsdup(pCurr);
85 pCurr += _tcslen(pCurr) + 1;
86 m_dwNumCounters++;
87 }
88 }
89
90 /**
91 * Translate single counter name's element
92 */
93 static BOOL TranslateElement(TCHAR *pszText)
94 {
95 DWORD i, dwSize;
96
97 for(i = 0; i < m_dwNumCounters; i++)
98 {
99 if (!_tcsicmp(m_pCounterList[i].pszName, pszText))
100 {
101 dwSize = MAX_ELEMENT_LENGTH * sizeof(TCHAR);
102 return PdhLookupPerfNameByIndex(NULL, m_pCounterList[i].dwIndex, pszText, &dwSize) == ERROR_SUCCESS;
103 }
104 }
105 return FALSE;
106 }
107
108 /**
109 * Translate counter name from English to localized
110 */
111 BOOL TranslateCounterName(const TCHAR *pszName, TCHAR *pszOut)
112 {
113 const TCHAR *pCurr = pszName;
114 const TCHAR *pSlash, *pBrace, *pNext;
115 TCHAR szTemp[MAX_ELEMENT_LENGTH];
116 BOOL bs1, bs2;
117 int nLen;
118
119 // Generic counter name looks like following:
120 // \\machine\object(parent/instance#index)\counter
121 // where machine, parent, instance, and index parts may be omited.
122 // We should translate object and counter parts if possible.
123
124 if (*pCurr != _T('\\'))
125 return FALSE; // Counter name should always start with "\" or "\\"
126 pCurr++;
127
128 // Skip machine name
129 if (*pCurr == _T('\\'))
130 {
131 pCurr++;
132 pCurr = _tcschr(pCurr, _T('\\'));
133 if (pCurr == NULL)
134 return FALSE; // Object name missing
135 pCurr++;
136 }
137 memcpy(pszOut, pszName, (pCurr - pszName) * sizeof(TCHAR));
138 pszOut[pCurr - pszName] = 0;
139
140 // Object name ends by \ or (
141 pSlash = _tcschr(pCurr, _T('\\'));
142 pBrace = _tcschr(pCurr, _T('('));
143 if (pSlash == NULL)
144 return FALSE;
145 if ((pSlash < pBrace) || (pBrace == NULL))
146 {
147 if (pSlash - pCurr >= MAX_ELEMENT_LENGTH)
148 return FALSE;
149 memcpy(szTemp, pCurr, (pSlash - pCurr) * sizeof(TCHAR));
150 szTemp[pSlash - pCurr] = 0;
151 pCurr = pSlash;
152 pNext = pSlash + 1;
153 }
154 else
155 {
156 if (pBrace - pCurr >= MAX_ELEMENT_LENGTH)
157 return FALSE;
158 memcpy(szTemp, pCurr, (pBrace - pCurr) * sizeof(TCHAR));
159 szTemp[pBrace - pCurr] = 0;
160 pCurr = pBrace;
161 pNext = _tcschr(pCurr, _T(')'));
162 if (pNext == NULL)
163 return FALSE;
164 pNext++;
165 if (*pNext != _T('\\'))
166 return FALSE;
167 pNext++;
168 }
169 bs1 = TranslateElement(szTemp);
170 _tcscat(pszOut, szTemp);
171 nLen = (int)_tcslen(pszOut);
172 memcpy(&pszOut[nLen], pCurr, (pNext - pCurr) * sizeof(TCHAR));
173 pszOut[nLen + (pNext - pCurr)] = 0;
174 pCurr = pNext;
175
176 // Translate counter name
177 nx_strncpy(szTemp, pCurr, MAX_ELEMENT_LENGTH);
178 bs2 = TranslateElement(szTemp);
179 _tcscat(pszOut, szTemp);
180
181 return bs1 || bs2;
182 }