Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2796 lines
106 KiB

  1. /*++
  2. Copyright (C) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. logthred.c
  5. Abstract:
  6. Performance Logs and Alerts log/scan thread functions.
  7. --*/
  8. #ifndef UNICODE
  9. #define UNICODE 1
  10. #endif
  11. #ifndef _UNICODE
  12. #define _UNICODE 1
  13. #endif
  14. #ifndef _IMPLEMENT_WMI
  15. #define _IMPLEMENT_WMI 1
  16. #endif
  17. #ifndef _DEBUG_OUTPUT
  18. #define _DEBUG_OUTPUT 0
  19. #endif
  20. //
  21. // Windows Include files
  22. //
  23. #pragma warning ( disable : 4201)
  24. #include <assert.h>
  25. // For Trace *** - these are only necessary because of union query data struct.
  26. #include <nt.h>
  27. #include <ntrtl.h>
  28. #include <nturtl.h>
  29. #include <wtypes.h>
  30. #include <float.h>
  31. #include <limits.h>
  32. #if _IMPLEMENT_WMI
  33. #include <wmistr.h>
  34. #include <evntrace.h>
  35. #endif
  36. #include <lmcons.h>
  37. #include <lmmsg.h> // for net message function
  38. #include <stdio.h>
  39. #include <tchar.h>
  40. #include <pdh.h>
  41. #include <pdhp.h>
  42. #include <pdhmsg.h>
  43. #include "smlogsvc.h"
  44. #include "smlogmsg.h"
  45. #define SECONDS_IN_DAY ((LONGLONG)(86400))
  46. #define LOG_EVENT_ON_ERROR ((BOOL)(1))
  47. DWORD
  48. ValidateCommandFilePath (
  49. IN PLOG_QUERY_DATA pArg )
  50. {
  51. DWORD dwStatus = ERROR_SUCCESS;
  52. if ( 0 != lstrlen ( pArg->szCmdFileName ) ) {
  53. HANDLE hOpenFile;
  54. LONG lErrorMode;
  55. lErrorMode = SetErrorMode ( SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX );
  56. hOpenFile = CreateFile (
  57. pArg->szCmdFileName,
  58. GENERIC_READ,
  59. 0, // Not shared
  60. NULL, // Security attributes
  61. OPEN_EXISTING, //
  62. FILE_ATTRIBUTE_NORMAL,
  63. NULL );
  64. if ( ( NULL == hOpenFile )
  65. || INVALID_HANDLE_VALUE == hOpenFile ) {
  66. LPWSTR szStringArray[3];
  67. DWORD dwStatus = GetLastError();
  68. szStringArray[0] = pArg->szCmdFileName;
  69. szStringArray[1] = pArg->szQueryName;
  70. szStringArray[2] = FormatEventLogMessage(dwStatus);
  71. ReportEvent (hEventLog,
  72. EVENTLOG_WARNING_TYPE,
  73. 0,
  74. SMLOG_CMD_FILE_INVALID,
  75. NULL,
  76. 3,
  77. sizeof(DWORD),
  78. szStringArray,
  79. (LPVOID)&dwStatus );
  80. pArg->dwCmdFileFailure = dwStatus;
  81. } else {
  82. CloseHandle(hOpenFile);
  83. }
  84. SetErrorMode ( lErrorMode );
  85. }
  86. return dwStatus;
  87. }
  88. DWORD
  89. AddCounterToCounterLog (
  90. IN PLOG_QUERY_DATA pArg,
  91. IN LPWSTR pszThisPath,
  92. IN HANDLE hQuery,
  93. IN BOOL bLogErrorEvent,
  94. IN OUT DWORD* pdwCounterCount )
  95. {
  96. LPWSTR szStringArray[3];
  97. DWORD dwStatus = ERROR_SUCCESS;
  98. HCOUNTER hThisCounter = NULL;
  99. PDH_STATUS pdhStatus;
  100. PLOG_COUNTER_INFO pCtrInfo = NULL;
  101. dwStatus = pdhStatus = PdhAdd009Counter (
  102. hQuery,
  103. pszThisPath,
  104. (* pdwCounterCount),
  105. &hThisCounter);
  106. if (dwStatus != ERROR_SUCCESS) {
  107. dwStatus = pdhStatus = PdhAddCounter (
  108. hQuery,
  109. pszThisPath,
  110. (* pdwCounterCount),
  111. &hThisCounter);
  112. }
  113. if ( !IsErrorSeverity(pdhStatus) ) {
  114. if ( IsWarningSeverity(pdhStatus) ) {
  115. // Write event log warning message
  116. szStringArray[0] = pszThisPath;
  117. szStringArray[1] = pArg->szQueryName;
  118. szStringArray[2] = FormatEventLogMessage(pdhStatus);
  119. ReportEvent (hEventLog,
  120. EVENTLOG_WARNING_TYPE,
  121. 0,
  122. SMLOG_ADD_COUNTER_WARNING,
  123. NULL,
  124. 3,
  125. sizeof(DWORD),
  126. szStringArray,
  127. (LPVOID)&pdhStatus);
  128. }
  129. // then add this handle to the list
  130. (*pdwCounterCount)++;
  131. pCtrInfo = G_ALLOC (sizeof (LOG_COUNTER_INFO));
  132. if (pCtrInfo != NULL) {
  133. // insert at front of list since the order isn't
  134. // important and this is simpler than walking the
  135. // list each time.
  136. pCtrInfo->hCounter = hThisCounter;
  137. pCtrInfo->next = pArg->pFirstCounter;
  138. pArg->pFirstCounter = pCtrInfo;
  139. pCtrInfo = NULL;
  140. } else {
  141. dwStatus = ERROR_OUTOFMEMORY;
  142. }
  143. } else {
  144. // For LogByObject, the call is retried with expanded counter if
  145. // the first try fails, so don't log error event the first time.
  146. if ( bLogErrorEvent ) {
  147. // unable to add the current counter so write event log message
  148. szStringArray[0] = pszThisPath;
  149. szStringArray[1] = pArg->szQueryName;
  150. szStringArray[2] = FormatEventLogMessage(pdhStatus);
  151. if ( PDH_ACCESS_DENIED == pdhStatus ) {
  152. ReportEvent (
  153. hEventLog,
  154. EVENTLOG_WARNING_TYPE,
  155. 0,
  156. SMLOG_UNABLE_ACCESS_COUNTER,
  157. NULL,
  158. 2,
  159. 0,
  160. szStringArray,
  161. NULL);
  162. } else {
  163. ReportEvent (
  164. hEventLog,
  165. EVENTLOG_WARNING_TYPE,
  166. 0,
  167. SMLOG_UNABLE_ADD_COUNTER,
  168. NULL,
  169. 3,
  170. sizeof(DWORD),
  171. szStringArray,
  172. (LPVOID)&pdhStatus);
  173. }
  174. }
  175. }
  176. return dwStatus;
  177. }
  178. BOOL
  179. IsPdhDataCollectSuccess ( PDH_STATUS pdhStatus )
  180. {
  181. BOOL bSuccess = FALSE;
  182. if ( ERROR_SUCCESS == pdhStatus
  183. || PDH_INVALID_DATA == pdhStatus ) {
  184. bSuccess = TRUE;
  185. } else if ( 0 < iPdhDataCollectSuccessCount ) {
  186. INT iIndex;
  187. for ( iIndex = 0; iIndex < iPdhDataCollectSuccessCount; iIndex++ ) {
  188. if ( pdhStatus == (PDH_STATUS)arrPdhDataCollectSuccess[iIndex] ) {
  189. bSuccess = TRUE;
  190. break;
  191. }
  192. }
  193. }
  194. return bSuccess;
  195. }
  196. void
  197. ComputeSessionTics(
  198. IN PLOG_QUERY_DATA pArg,
  199. IN OUT LONGLONG* pllWaitTics
  200. )
  201. {
  202. LONGLONG llLocalTime;
  203. // Compute total session time based on Stop modes
  204. // and values.
  205. // -1 (NULL_INTERVAL_TICS) signals no session time limit. This is true for
  206. // Stop mode SLQ_AUTO_MODE_NONE and SLQ_AUTO_MODE_SIZE.
  207. //
  208. // 0 signals that the Stop time is past, so exit immediately.
  209. //
  210. // Assume that session is starting, so Start mode isn't relevant.
  211. if ( NULL != pArg && NULL != pllWaitTics ) {
  212. *pllWaitTics = NULL_INTERVAL_TICS;
  213. if ( SLQ_AUTO_MODE_AFTER == pArg->stiCurrentStop.dwAutoMode
  214. || SLQ_AUTO_MODE_AT == pArg->stiCurrentStop.dwAutoMode ) {
  215. GetLocalFileTime (&llLocalTime);
  216. if ( SLQ_AUTO_MODE_AT == pArg->stiCurrentStop.dwAutoMode ) {
  217. if ( pArg->stiCurrentStop.llDateTime > llLocalTime ) {
  218. *pllWaitTics = pArg->stiCurrentStop.llDateTime - llLocalTime;
  219. } else {
  220. // Session length = 0. Exit immediately.
  221. *pllWaitTics = ((LONGLONG)(0));
  222. }
  223. } else if ( SLQ_AUTO_MODE_AFTER == pArg->stiCurrentStop.dwAutoMode ) {
  224. TimeInfoToTics( &pArg->stiCurrentStop, pllWaitTics );
  225. }
  226. }
  227. } else {
  228. assert ( FALSE );
  229. }
  230. // Todo: Report errors
  231. return;
  232. }
  233. void
  234. ComputeNewFileTics(
  235. IN PLOG_QUERY_DATA pArg,
  236. IN OUT LONGLONG* pllWaitTics
  237. )
  238. {
  239. LONGLONG llLocalTime;
  240. // Compute time until next file creation based on Create New File modes
  241. // and values.
  242. // -1 (NULL_INTERVAL_TICS) signals no time limit. This is true for
  243. // mode SLQ_AUTO_MODE_NONE and SLQ_AUTO_MODE_SIZE.
  244. //
  245. // 0 signals that the time is past, so exit immediately.
  246. //
  247. // Assume that session is starting, so Start mode isn't relevant.
  248. if ( NULL != pArg && NULL != pllWaitTics ) {
  249. *pllWaitTics = NULL_INTERVAL_TICS;
  250. if ( SLQ_AUTO_MODE_AFTER == pArg->stiCreateNewFile.dwAutoMode ) {
  251. GetLocalFileTime (&llLocalTime);
  252. if ( SLQ_AUTO_MODE_AFTER == pArg->stiCreateNewFile.dwAutoMode ) {
  253. TimeInfoToTics( &pArg->stiCreateNewFile, pllWaitTics );
  254. assert ( (LONGLONG)(0) != *pllWaitTics );
  255. } else if ( SLQ_AUTO_MODE_AT == pArg->stiCreateNewFile.dwAutoMode ) {
  256. assert ( FALSE );
  257. *pllWaitTics = (LONGLONG)(0);
  258. }
  259. }
  260. } else {
  261. assert ( FALSE );
  262. }
  263. // Todo: Report errors
  264. return;
  265. }
  266. void
  267. ComputeSampleCount(
  268. IN PLOG_QUERY_DATA pArg,
  269. IN BOOL bSessionCount,
  270. OUT LONGLONG* pllSampleCount
  271. )
  272. {
  273. // Compute sample count based on Stop or CreateNewFile modes
  274. // and values. Account for the first sample in the log.
  275. //
  276. // 0 signals no sample limit in the file. This is true for
  277. // Stop modes SLQ_AUTO_MODE_NONE and SLQ_AUTO_MODE_SIZE.
  278. //
  279. // -1 signals that the Stop time is past.
  280. // Assume that sampling is starting, so Start mode isn't relevant.
  281. LONGLONG llLocalSampleCount = NULL_INTERVAL_TICS;
  282. assert ( NULL != pllSampleCount );
  283. if ( NULL != pllSampleCount ) {
  284. *pllSampleCount = (LONGLONG)(-1);
  285. if ( bSessionCount ) {
  286. ComputeSessionTics ( pArg, &llLocalSampleCount );
  287. } else {
  288. ComputeNewFileTics ( pArg, &llLocalSampleCount );
  289. }
  290. if ( NULL_INTERVAL_TICS == llLocalSampleCount ) {
  291. // No session/sample limit
  292. *pllSampleCount = (LONGLONG)(0);
  293. } else if ( (LONGLONG)(0) == llLocalSampleCount ){
  294. // Stop time is past
  295. *pllSampleCount = INFINITE_TICS;
  296. } else {
  297. *pllSampleCount = llLocalSampleCount
  298. / (pArg->dwMillisecondSampleInterval * FILETIME_TICS_PER_MILLISECOND);
  299. *pllSampleCount += 1; // add in the "zero-th" sample
  300. }
  301. }
  302. return;
  303. }
  304. BOOL
  305. ProcessRepeatOption (
  306. IN OUT PLOG_QUERY_DATA pArg,
  307. OUT LARGE_INTEGER* pliStartDelayTics )
  308. {
  309. BOOL bRepeat = TRUE;
  310. if ( NULL != pliStartDelayTics ) {
  311. // If restart not enabled, then exit.
  312. if ( SLQ_AUTO_MODE_NONE == pArg->stiRepeat.dwAutoMode ) {
  313. pliStartDelayTics->QuadPart = NULL_INTERVAL_TICS;
  314. bRepeat = FALSE;
  315. } else {
  316. // For SLQ_AUTO_MODE_AFTER, the only value currently supported is 0.
  317. pliStartDelayTics->QuadPart = (LONGLONG)0;
  318. // For SLQ_AUTO_MODE_CALENDAR, add n*24 hours to the original start time.
  319. // If Stop mode is SLQ_AUTO_MODE_AT, add n*24 hours to stop time.
  320. if ( SLQ_AUTO_MODE_CALENDAR == pArg->stiRepeat.dwAutoMode ) {
  321. // Delay of NULL_INTERVAL signals exit immediately.
  322. // Todo: This should not occur. Report Event, assert.
  323. pliStartDelayTics->QuadPart = ComputeStartWaitTics ( pArg, TRUE );
  324. if ( NULL_INTERVAL_TICS == pliStartDelayTics->QuadPart ) {
  325. bRepeat = FALSE;
  326. } else {
  327. pArg->dwCurrentState = SLQ_QUERY_START_PENDING;
  328. WriteRegistryDwordValue (
  329. pArg->hKeyQuery,
  330. (LPCWSTR)L"Current State",
  331. &pArg->dwCurrentState,
  332. REG_DWORD );
  333. // Todo: Warning event on failure.
  334. }
  335. } // else for SLQ_AUTO_MODE_AFTER, repeat immediately
  336. }
  337. } else {
  338. bRepeat = FALSE;
  339. assert ( FALSE );
  340. }
  341. return bRepeat;
  342. }
  343. void
  344. SetPdhOpenOptions (
  345. IN PLOG_QUERY_DATA pArg,
  346. OUT DWORD* pdwAccess,
  347. OUT DWORD* pdwLogFileType )
  348. {
  349. // get file type
  350. switch ( pArg->dwLogFileType ) {
  351. case SLF_TSV_FILE:
  352. *pdwLogFileType = PDH_LOG_TYPE_TSV;
  353. break;
  354. case SLF_BIN_FILE:
  355. case SLF_BIN_CIRC_FILE:
  356. *pdwLogFileType = PDH_LOG_TYPE_BINARY;
  357. break;
  358. case SLF_SQL_LOG:
  359. *pdwLogFileType = PDH_LOG_TYPE_SQL;
  360. break;
  361. case SLF_CSV_FILE:
  362. default:
  363. *pdwLogFileType = PDH_LOG_TYPE_CSV;
  364. break;
  365. }
  366. *pdwAccess = PDH_LOG_WRITE_ACCESS |
  367. PDH_LOG_CREATE_ALWAYS;
  368. if (SLF_BIN_CIRC_FILE == pArg->dwLogFileType)
  369. *pdwAccess |= PDH_LOG_OPT_CIRCULAR;
  370. if ( ( PDH_LOG_TYPE_BINARY != *pdwLogFileType )
  371. && (NULL != pArg->szLogFileComment ) )
  372. *pdwAccess |= PDH_LOG_OPT_USER_STRING;
  373. // NOTE: For all types except sequential binary,
  374. // the append mode is determined by the file type.
  375. // All Sql logs are APPEND
  376. // All text logs are OVERWRITE
  377. if ( (pArg->dwAppendMode)
  378. && (* pdwLogFileType == PDH_LOG_TYPE_BINARY) ) {
  379. * pdwAccess |= PDH_LOG_OPT_APPEND;
  380. }
  381. }
  382. DWORD
  383. StartLogQuery (
  384. IN PLOG_QUERY_DATA pArg
  385. )
  386. {
  387. HKEY hKeyLogQuery;
  388. SLQ_TIME_INFO slqTime;
  389. DWORD dwStatus;
  390. SC_HANDLE hSC = NULL;
  391. SC_HANDLE hService = NULL;
  392. SERVICE_STATUS ssData;
  393. WCHAR szQueryKeyNameBuf[MAX_PATH];
  394. WCHAR szLogPath[2*MAX_PATH];
  395. DWORD dwCurrentState;
  396. DWORD dwValue;
  397. DWORD dwDefault;
  398. SYSTEMTIME st;
  399. LONGLONG llTime;
  400. LONGLONG llModifiedTime;
  401. // open registry key to the desired service
  402. dwStatus = GetQueryKeyName (
  403. pArg->szPerfLogName,
  404. szQueryKeyNameBuf,
  405. MAX_PATH );
  406. if ( ERROR_SUCCESS == dwStatus && 0 < lstrlen (szQueryKeyNameBuf) ) {
  407. lstrcpyW (szLogPath, (LPCWSTR)L"SYSTEM\\CurrentControlSet\\Services\\SysmonLog\\Log Queries");
  408. lstrcatW (szLogPath, (LPCWSTR)L"\\");
  409. lstrcatW (szLogPath, szQueryKeyNameBuf);
  410. dwStatus = RegOpenKeyEx (
  411. (HKEY)HKEY_LOCAL_MACHINE,
  412. szLogPath,
  413. 0L,
  414. KEY_READ | KEY_WRITE,
  415. (PHKEY)&hKeyLogQuery);
  416. if (dwStatus == ERROR_SUCCESS) {
  417. // if current state is running, then skip the rest
  418. dwDefault = SLQ_QUERY_STOPPED;
  419. dwStatus = ReadRegistryDwordValue (
  420. hKeyLogQuery,
  421. pArg->szPerfLogName,
  422. (LPCWSTR)L"Current State",
  423. &dwDefault,
  424. &dwCurrentState);
  425. if (dwCurrentState == SLQ_QUERY_STOPPED) {
  426. // update the start time to MIN_TIME_VALUE
  427. GetLocalTime(&st);
  428. SystemTimeToFileTime (&st, (FILETIME *)&llTime);
  429. memset (&slqTime, 0, sizeof(slqTime));
  430. slqTime.wTimeType = SLQ_TT_TTYPE_START;
  431. slqTime.wDataType = SLQ_TT_DTYPE_DATETIME;
  432. slqTime.dwAutoMode = SLQ_AUTO_MODE_NONE;
  433. slqTime.llDateTime = MIN_TIME_VALUE;
  434. dwStatus = WriteRegistrySlqTime (
  435. hKeyLogQuery,
  436. (LPCWSTR)L"Start",
  437. &slqTime);
  438. // If stop time mode set to manual, or StopAt with time before Now,
  439. // set the mode to Manual, value to MAX_TIME_VALUE
  440. memset (&slqTime, 0, sizeof(slqTime));
  441. slqTime.wTimeType = SLQ_TT_TTYPE_STOP;
  442. slqTime.wDataType = SLQ_TT_DTYPE_DATETIME;
  443. slqTime.dwAutoMode = SLQ_AUTO_MODE_NONE;
  444. slqTime.llDateTime = MAX_TIME_VALUE;
  445. dwStatus = ReadRegistrySlqTime (
  446. hKeyLogQuery,
  447. pArg->szPerfLogName,
  448. (LPCWSTR)L"Stop",
  449. &slqTime,
  450. &slqTime);
  451. if ( SLQ_AUTO_MODE_NONE == slqTime.dwAutoMode
  452. || ( SLQ_AUTO_MODE_AT == slqTime.dwAutoMode
  453. && llTime >= slqTime.llDateTime ) ) {
  454. slqTime.wTimeType = SLQ_TT_TTYPE_STOP;
  455. slqTime.wDataType = SLQ_TT_DTYPE_DATETIME;
  456. slqTime.dwAutoMode = SLQ_AUTO_MODE_NONE;
  457. slqTime.llDateTime = MAX_TIME_VALUE;
  458. dwStatus = WriteRegistrySlqTime (
  459. hKeyLogQuery,
  460. (LPCWSTR)L"Stop",
  461. &slqTime);
  462. }
  463. // Set state to start pending.
  464. if (dwStatus == ERROR_SUCCESS) {
  465. dwValue = SLQ_QUERY_START_PENDING;
  466. dwStatus = WriteRegistryDwordValue (
  467. hKeyLogQuery,
  468. (LPCWSTR)L"Current State",
  469. &dwValue,
  470. REG_DWORD);
  471. }
  472. // update the modified time to indicate a change has occurred
  473. memset (&slqTime, 0, sizeof(slqTime));
  474. // LastModified and LastConfigured values are stored as GMT
  475. GetSystemTimeAsFileTime ( (LPFILETIME)(&llModifiedTime) );
  476. slqTime.wTimeType = SLQ_TT_TTYPE_LAST_MODIFIED;
  477. slqTime.wDataType = SLQ_TT_DTYPE_DATETIME;
  478. slqTime.dwAutoMode = SLQ_AUTO_MODE_NONE;
  479. slqTime.llDateTime = llModifiedTime;
  480. dwStatus = WriteRegistrySlqTime (
  481. hKeyLogQuery,
  482. (LPCWSTR)L"Last Modified",
  483. &slqTime);
  484. if (dwStatus == ERROR_SUCCESS) {
  485. hSC = OpenSCManager ( NULL, NULL, SC_MANAGER_ALL_ACCESS);
  486. if (hSC != NULL) {
  487. // ping the service controller to rescan the entries
  488. hService = OpenServiceW (
  489. hSC,
  490. (LPCWSTR)L"SysmonLog",
  491. SERVICE_USER_DEFINED_CONTROL | SERVICE_START );
  492. if (hService != NULL) {
  493. ControlService (
  494. hService,
  495. SERVICE_CONTROL_SYNCHRONIZE,
  496. &ssData);
  497. CloseServiceHandle (hService);
  498. } else {
  499. // unable to open log service
  500. dwStatus = GetLastError();
  501. }
  502. CloseServiceHandle (hSC);
  503. } else {
  504. // unable to open service controller
  505. dwStatus = GetLastError();
  506. }
  507. } else {
  508. // unable to set the time
  509. }
  510. RegCloseKey (hKeyLogQuery);
  511. if ( ( ERROR_SUCCESS != dwStatus )
  512. && ( 1 != pArg->dwAlertLogFailureReported ) ) {
  513. LPWSTR szStringArray[2];
  514. szStringArray[0] = pArg->szPerfLogName;
  515. szStringArray[1] = pArg->szQueryName;
  516. ReportEvent (hEventLog,
  517. EVENTLOG_WARNING_TYPE,
  518. 0,
  519. SMLOG_UNABLE_START_ALERT_LOG,
  520. NULL,
  521. 2,
  522. sizeof(DWORD),
  523. szStringArray,
  524. (LPVOID)&dwStatus );
  525. pArg->dwAlertLogFailureReported = 1;
  526. }
  527. } else {
  528. // it's probably already running so don't bother with it
  529. dwStatus = ERROR_SUCCESS;
  530. }
  531. } else {
  532. dwStatus = SMLOG_UNABLE_READ_ALERT_LOG;
  533. if ( 1 != pArg->dwAlertLogFailureReported ) {
  534. LPWSTR szStringArray[2];
  535. szStringArray[0] = pArg->szPerfLogName;
  536. szStringArray[1] = pArg->szQueryName;
  537. ReportEvent (hEventLog,
  538. EVENTLOG_WARNING_TYPE,
  539. 0,
  540. SMLOG_UNABLE_READ_ALERT_LOG,
  541. NULL,
  542. 2,
  543. 0,
  544. szStringArray,
  545. NULL );
  546. pArg->dwAlertLogFailureReported = 1;
  547. }
  548. }
  549. } else {
  550. dwStatus = SMLOG_UNABLE_READ_ALERT_LOG;
  551. if ( 1 != pArg->dwAlertLogFailureReported ) {
  552. LPWSTR szStringArray[2];
  553. szStringArray[0] = pArg->szPerfLogName;
  554. szStringArray[1] = pArg->szQueryName;
  555. ReportEvent (hEventLog,
  556. EVENTLOG_WARNING_TYPE,
  557. 0,
  558. SMLOG_UNABLE_READ_ALERT_LOG,
  559. NULL,
  560. 2,
  561. 0,
  562. szStringArray,
  563. NULL );
  564. pArg->dwAlertLogFailureReported = 1;
  565. }
  566. }
  567. return dwStatus;
  568. }
  569. DWORD
  570. DoAlertCommandFile (
  571. IN PLOG_QUERY_DATA pArg,
  572. IN PALERT_COUNTER_INFO pAlertCI,
  573. IN LPCWSTR szTimeStamp,
  574. IN LPCWSTR szMeasuredValue,
  575. IN LPCWSTR szOverUnder,
  576. IN LPCWSTR szLimitValue
  577. )
  578. {
  579. const INT ciMaxDelimPerArg = 3;
  580. DWORD dwStatus = ERROR_SUCCESS;
  581. BOOL bStatus = FALSE;
  582. LPTSTR szCommandString = NULL;
  583. INT iBufLen = 0;
  584. LPTSTR szTempBuffer = NULL;
  585. LONG lErrorMode;
  586. DWORD iStrLen;
  587. DWORD dwCmdFlags;
  588. BOOL bSingleArg = FALSE;
  589. STARTUPINFO si;
  590. PROCESS_INFORMATION pi;
  591. DWORD dwCreationFlags = NORMAL_PRIORITY_CLASS;
  592. LPWSTR szDelim1;
  593. LPWSTR szDelim2;
  594. BOOL bFirstArgDone = FALSE;
  595. if ( NULL != pArg
  596. && NULL != pAlertCI ) {
  597. if ( NULL != pArg->szCmdFileName ) {
  598. dwStatus = pArg->dwCmdFileFailure;
  599. if ( ERROR_SUCCESS == dwStatus ) {
  600. // See if any of the argument flags are set.
  601. dwCmdFlags = pArg->dwAlertActionFlags & ALRT_CMD_LINE_MASK;
  602. if ( 0 != dwCmdFlags ) {
  603. // Allocate space for all arguments
  604. if ( NULL != pArg->szQueryName ) {
  605. iBufLen += lstrlen ( pArg->szQueryName ) + ciMaxDelimPerArg;
  606. }
  607. if ( NULL != szTimeStamp ) {
  608. iBufLen += lstrlen ( szTimeStamp ) + ciMaxDelimPerArg;
  609. }
  610. if ( NULL != pAlertCI->pAlertInfo->szCounterPath) {
  611. iBufLen += lstrlen ( pAlertCI->pAlertInfo->szCounterPath ) + ciMaxDelimPerArg;
  612. }
  613. if ( NULL != szMeasuredValue ) {
  614. iBufLen += lstrlen ( szMeasuredValue ) + ciMaxDelimPerArg;
  615. }
  616. if ( NULL != szOverUnder ) {
  617. iBufLen += lstrlen ( szOverUnder ) + ciMaxDelimPerArg;
  618. }
  619. if ( NULL != szLimitValue ) {
  620. iBufLen += lstrlen ( szLimitValue ) + ciMaxDelimPerArg;
  621. }
  622. if ( NULL != pArg->szUserText ) {
  623. iBufLen += lstrlen ( pArg->szUserText ) + ciMaxDelimPerArg;
  624. }
  625. iBufLen+= 2; // 1 for possible leading ", 1 for NULL.
  626. szCommandString = (LPWSTR)G_ALLOC(iBufLen * sizeof(TCHAR));
  627. if ( NULL != szCommandString ) {
  628. szCommandString[0] = _T('\0');
  629. // build command line arguments
  630. if ((pArg->dwAlertActionFlags & ALRT_CMD_LINE_SINGLE) != 0) {
  631. bSingleArg = TRUE;
  632. szDelim1 = (LPWSTR)L",";
  633. szDelim2 = (LPWSTR)L"\0";
  634. } else {
  635. // multiple arguments enclosed by double quotes and
  636. // separated by a space
  637. szDelim1 = (LPWSTR)L" \"";
  638. szDelim2 = (LPWSTR)L"\"";
  639. }
  640. if (pArg->dwAlertActionFlags & ALRT_CMD_LINE_A_NAME ) {
  641. if ( NULL != pArg->szQueryName ) {
  642. if (bFirstArgDone) {
  643. lstrcatW(szCommandString, szDelim1); // add leading delimiter
  644. } else {
  645. lstrcatW(szCommandString, (LPCWSTR)L"\""); // add leading quote
  646. bFirstArgDone = TRUE;
  647. }
  648. lstrcatW(szCommandString, pArg->szQueryName);
  649. lstrcatW(szCommandString, szDelim2);
  650. } else {
  651. dwStatus = ERROR_INVALID_PARAMETER;
  652. }
  653. }
  654. if ( ERROR_SUCCESS == dwStatus
  655. && ( pArg->dwAlertActionFlags & ALRT_CMD_LINE_D_TIME ) )
  656. {
  657. if ( NULL != szTimeStamp ) {
  658. if (bFirstArgDone) {
  659. lstrcatW(szCommandString, szDelim1); // add leading delimiter
  660. } else {
  661. lstrcatW(szCommandString, (LPCWSTR)L"\""); // add leading quote
  662. bFirstArgDone = TRUE;
  663. }
  664. lstrcatW(szCommandString, szTimeStamp);
  665. lstrcatW(szCommandString, szDelim2);
  666. } else {
  667. dwStatus = ERROR_INVALID_PARAMETER;
  668. }
  669. }
  670. if ( ERROR_SUCCESS == dwStatus
  671. && ( pArg->dwAlertActionFlags & ALRT_CMD_LINE_C_NAME ) )
  672. {
  673. if ( NULL != pAlertCI->pAlertInfo->szCounterPath ) {
  674. if (bFirstArgDone) {
  675. lstrcatW(szCommandString, szDelim1); // add leading delimiter
  676. } else {
  677. lstrcatW(szCommandString, (LPCWSTR)L"\""); // add leading quote
  678. bFirstArgDone = TRUE;
  679. }
  680. lstrcatW(szCommandString, pAlertCI->pAlertInfo->szCounterPath);
  681. lstrcatW(szCommandString, szDelim2);
  682. } else {
  683. dwStatus = ERROR_INVALID_PARAMETER;
  684. }
  685. }
  686. if ( ERROR_SUCCESS == dwStatus
  687. && ( pArg->dwAlertActionFlags & ALRT_CMD_LINE_M_VAL ) )
  688. {
  689. if ( NULL != szMeasuredValue ) {
  690. if (bFirstArgDone) {
  691. lstrcatW(szCommandString, szDelim1); // add leading delimiter
  692. } else {
  693. lstrcatW(szCommandString, (LPCWSTR)L"\""); // add leading quote
  694. bFirstArgDone = TRUE;
  695. }
  696. lstrcatW(szCommandString, szMeasuredValue);
  697. lstrcatW(szCommandString, szDelim2);
  698. } else {
  699. dwStatus = ERROR_INVALID_PARAMETER;
  700. }
  701. }
  702. if ( ERROR_SUCCESS == dwStatus
  703. && ( pArg->dwAlertActionFlags & ALRT_CMD_LINE_L_VAL ) )
  704. {
  705. if ( NULL != szOverUnder && NULL != szLimitValue ) {
  706. if (bFirstArgDone) {
  707. lstrcatW(szCommandString, szDelim1); // add leading delimiter
  708. } else {
  709. lstrcatW(szCommandString, (LPCWSTR)L"\""); // add leading quote
  710. bFirstArgDone = TRUE;
  711. }
  712. lstrcatW(szCommandString, szOverUnder);
  713. lstrcatW(szCommandString, (LPCWSTR)L" ");
  714. lstrcatW(szCommandString, szLimitValue);
  715. lstrcatW(szCommandString, szDelim2);
  716. } else {
  717. dwStatus = ERROR_INVALID_PARAMETER;
  718. }
  719. }
  720. if ( ERROR_SUCCESS == dwStatus
  721. && ( pArg->dwAlertActionFlags & ALRT_CMD_LINE_U_TEXT ) )
  722. {
  723. if ( NULL != pArg->szUserText ) {
  724. if (bFirstArgDone) {
  725. lstrcatW(szCommandString, szDelim1); // add leading delimiter
  726. } else {
  727. lstrcatW(szCommandString, (LPCWSTR)L"\""); // add leading quote
  728. bFirstArgDone = TRUE;
  729. }
  730. lstrcatW(szCommandString, pArg->szUserText);
  731. lstrcatW(szCommandString, szDelim2);
  732. } else {
  733. dwStatus = ERROR_INVALID_PARAMETER;
  734. }
  735. }
  736. if (bFirstArgDone && bSingleArg) {
  737. // add closing quote if there's at least 1 arg in the command line
  738. lstrcatW(szCommandString, (LPCWSTR)L"\"");
  739. }
  740. } else {
  741. dwStatus = ERROR_OUTOFMEMORY;
  742. }
  743. if ( ERROR_SUCCESS == dwStatus )
  744. {
  745. iBufLen = lstrlen( pArg->szCmdFileName ) + 1; // 1 for NULL
  746. if ( NULL != szCommandString ) {
  747. iBufLen += lstrlen ( szCommandString ) + 1; // 1 for space char
  748. }
  749. szTempBuffer = (LPWSTR)G_ALLOC(iBufLen * sizeof(TCHAR));
  750. }
  751. if ( NULL != szTempBuffer ) {
  752. // build command line arguments
  753. lstrcpy (szTempBuffer, pArg->szCmdFileName) ;
  754. // see if this is a CMD or a BAT file
  755. // if it is then create a process with a console window, otherwise
  756. // assume it's an executable file that will create it's own window
  757. // or console if necessary
  758. //
  759. _tcslwr (szTempBuffer);
  760. if ((_tcsstr(szTempBuffer, (LPCTSTR)TEXT(".bat")) != NULL) ||
  761. (_tcsstr(szTempBuffer, (LPCTSTR)TEXT(".cmd")) != NULL)){
  762. dwCreationFlags |= CREATE_NEW_CONSOLE;
  763. } else {
  764. dwCreationFlags |= DETACHED_PROCESS;
  765. }
  766. // recopy the image name to the temp buffer since it was modified
  767. // (i.e. lowercased) for the previous comparison.
  768. lstrcpy (szTempBuffer, pArg->szCmdFileName) ;
  769. if ( NULL != szCommandString ) {
  770. // now add on the alert text preceded with a space char
  771. iStrLen = lstrlen (szTempBuffer) ;
  772. szTempBuffer [iStrLen] = TEXT(' ') ;
  773. iStrLen++ ;
  774. lstrcpy (&szTempBuffer[iStrLen], szCommandString) ;
  775. }
  776. // initialize Startup Info block
  777. memset (&si, 0, sizeof(si));
  778. si.cb = sizeof(si);
  779. si.dwFlags = STARTF_USESHOWWINDOW ;
  780. si.wShowWindow = SW_SHOWNOACTIVATE ;
  781. //si.lpDesktop = L"WinSta0\\Default";
  782. memset (&pi, 0, sizeof(pi));
  783. // supress pop-ups inf the detached process
  784. lErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
  785. if( pArg->hUserToken != NULL ){
  786. bStatus = CreateProcessAsUser (
  787. pArg->hUserToken,
  788. NULL,
  789. szTempBuffer,
  790. NULL, NULL, FALSE,
  791. dwCreationFlags,
  792. NULL,
  793. NULL,
  794. &si,
  795. &pi);
  796. } else {
  797. bStatus = CreateProcess (
  798. NULL,
  799. szTempBuffer,
  800. NULL, NULL, FALSE,
  801. dwCreationFlags,
  802. NULL,
  803. NULL,
  804. &si,
  805. &pi);
  806. }
  807. SetErrorMode(lErrorMode);
  808. if (bStatus) {
  809. dwStatus = ERROR_SUCCESS;
  810. if ( NULL != pi.hThread && INVALID_HANDLE_VALUE != pi.hThread ) {
  811. CloseHandle(pi.hThread);
  812. pi.hThread = NULL;
  813. }
  814. if ( NULL != pi.hProcess && INVALID_HANDLE_VALUE != pi.hProcess ) {
  815. CloseHandle(pi.hProcess);
  816. pi.hProcess = NULL;
  817. }
  818. } else {
  819. dwStatus = GetLastError();
  820. }
  821. } else {
  822. dwStatus = ERROR_OUTOFMEMORY;
  823. }
  824. if (szCommandString != NULL) G_FREE(szCommandString);
  825. if (szTempBuffer != NULL) G_FREE(szTempBuffer);
  826. }
  827. }
  828. if ( ERROR_SUCCESS != dwStatus ) {
  829. LPWSTR szStringArray[2];
  830. szStringArray[0] = szTempBuffer;
  831. szStringArray[1] = pArg->szQueryName;
  832. ReportEvent (hEventLog,
  833. EVENTLOG_WARNING_TYPE,
  834. 0,
  835. SMLOG_ALERT_CMD_FAIL,
  836. NULL,
  837. 2,
  838. sizeof(DWORD),
  839. szStringArray,
  840. (LPVOID)&dwStatus );
  841. pArg->dwCmdFileFailure = dwStatus;
  842. }
  843. } else {
  844. dwStatus = ERROR_INVALID_PARAMETER;
  845. }
  846. } else {
  847. dwStatus = ERROR_INVALID_PARAMETER;
  848. }
  849. return dwStatus;
  850. }
  851. BOOL
  852. ExamineAlertValues (
  853. IN PLOG_QUERY_DATA pArg
  854. )
  855. {
  856. PALERT_COUNTER_INFO pAlertCI;
  857. PDH_STATUS pdhStatus;
  858. DWORD dwType;
  859. PDH_FMT_COUNTERVALUE pdhCurrentValue;
  860. BOOL bDoAlertAction;
  861. // for each counter in query, compare it's formatted
  862. // value against the alert value and do the desired operation
  863. // if the alert condition is exceeded.
  864. for (pAlertCI = (PALERT_COUNTER_INFO)pArg->pFirstCounter;
  865. pAlertCI != NULL;
  866. pAlertCI = pAlertCI->next) {
  867. bDoAlertAction = FALSE;
  868. // get formatted counter value
  869. pdhStatus = PdhGetFormattedCounterValue (
  870. pAlertCI->hCounter,
  871. PDH_FMT_DOUBLE | PDH_FMT_NOCAP100,
  872. &dwType,
  873. &pdhCurrentValue);
  874. if ((pdhStatus == ERROR_SUCCESS) &&
  875. ((pdhCurrentValue.CStatus == PDH_CSTATUS_VALID_DATA) ||
  876. (pdhCurrentValue.CStatus == PDH_CSTATUS_NEW_DATA))) {
  877. // then the value was good so compare it
  878. if ((pAlertCI->pAlertInfo->dwFlags & AIBF_OVER) == AIBF_OVER) {
  879. // test for value > limit
  880. if (pdhCurrentValue.doubleValue > pAlertCI->pAlertInfo->dLimit) {
  881. bDoAlertAction = TRUE;
  882. }
  883. } else {
  884. // test for value < limit
  885. if (pdhCurrentValue.doubleValue < pAlertCI->pAlertInfo->dLimit) {
  886. bDoAlertAction = TRUE;
  887. }
  888. }
  889. }
  890. if (bDoAlertAction) {
  891. WCHAR szValueString[32];
  892. WCHAR szLimitString[32];
  893. WCHAR szOverUnderString[64];
  894. WCHAR szTimeStampFmt[64];
  895. WCHAR szTimeStamp[48];
  896. DWORD dwFmtStringFlags;
  897. DWORD dwBufLen;
  898. SYSTEMTIME st;
  899. // build arguments used by event log and net messsage if either
  900. // option is enabled
  901. dwFmtStringFlags = ALRT_ACTION_LOG_EVENT | ALRT_ACTION_SEND_MSG | ALRT_ACTION_EXEC_CMD;
  902. if ((pArg->dwAlertActionFlags & dwFmtStringFlags) != 0) {
  903. INT nResId;
  904. // report event to event log
  905. // format message string elements
  906. _stprintf (szValueString, (LPCWSTR)L"%.*g", DBL_DIG, pdhCurrentValue.doubleValue);
  907. _stprintf (szLimitString, (LPCWSTR)L"%.*g", DBL_DIG, pAlertCI->pAlertInfo->dLimit);
  908. nResId = pAlertCI->pAlertInfo->dwFlags & AIBF_OVER ? IDS_OVER : IDS_UNDER;
  909. LoadString (hModule,
  910. nResId,
  911. szOverUnderString,
  912. (sizeof(szOverUnderString) / sizeof(szOverUnderString[0])));
  913. // get timestampformat string
  914. LoadString (hModule,
  915. IDS_ALERT_TIMESTAMP_FMT,
  916. szTimeStampFmt,
  917. (sizeof(szTimeStampFmt) / sizeof(szTimeStampFmt[0])));
  918. // message format string expects the following args:
  919. // Timestamp
  920. // Counter path string
  921. // measured value
  922. // over/under
  923. // limit value
  924. GetLocalTime (&st);
  925. dwBufLen = swprintf (
  926. szTimeStamp,
  927. szTimeStampFmt,
  928. st.wYear, st.wMonth, st.wDay,
  929. st.wHour, st.wMinute, st.wSecond);
  930. assert (dwBufLen < (sizeof(szTimeStamp) / sizeof(szTimeStamp[0])));
  931. }
  932. // do action(s) as defined in flags
  933. if ((pArg->dwAlertActionFlags & ALRT_ACTION_LOG_EVENT) == ALRT_ACTION_LOG_EVENT) {
  934. LPWSTR szStringArray[4];
  935. szStringArray[0] = pAlertCI->pAlertInfo->szCounterPath;
  936. szStringArray[1] = szValueString;
  937. szStringArray[2] = szOverUnderString;
  938. szStringArray[3] = szLimitString;
  939. ReportEvent (hEventLog,
  940. EVENTLOG_INFORMATION_TYPE,
  941. 0,
  942. SMLOG_ALERT_LIMIT_CROSSED,
  943. NULL,
  944. 4,
  945. 0,
  946. szStringArray,
  947. NULL);
  948. }
  949. if ((pArg->dwAlertActionFlags & ALRT_ACTION_SEND_MSG) == ALRT_ACTION_SEND_MSG) {
  950. if (pArg->szNetName != NULL) {
  951. DWORD dwStatus = ERROR_SUCCESS;
  952. WCHAR szMessageFormat[MAX_PATH];
  953. WCHAR szMessageText[MAX_PATH * 2];
  954. DWORD dwBufLen;
  955. // get message format string
  956. LoadString (hModule,
  957. IDS_ALERT_MSG_FMT,
  958. szMessageFormat,
  959. (sizeof(szMessageFormat) / sizeof(szMessageFormat[0])));
  960. // message format string expects the following args:
  961. // Timestamp
  962. // Counter path string
  963. // measured value
  964. // over/under
  965. // limit value
  966. dwBufLen = swprintf (szMessageText, szMessageFormat,
  967. szTimeStamp,
  968. pAlertCI->pAlertInfo->szCounterPath,
  969. szValueString,
  970. szOverUnderString,
  971. szLimitString);
  972. assert (dwBufLen < (sizeof(szMessageText) / sizeof(szMessageText[0])));
  973. dwBufLen += 1;
  974. dwBufLen *= sizeof(WCHAR);
  975. // send network message to specified computer
  976. dwStatus = NetMessageBufferSend(
  977. NULL,
  978. pArg->szNetName,
  979. NULL,
  980. (LPBYTE)szMessageText,
  981. dwBufLen);
  982. if ( ( ERROR_SUCCESS != dwStatus )
  983. && ( 1 != pArg->dwNetMsgFailureReported ) ) {
  984. LPWSTR szStringArray[3];
  985. // Write event log warning message
  986. szStringArray[0] = pArg->szQueryName;
  987. szStringArray[1] = pArg->szNetName;
  988. szStringArray[2] = FormatEventLogMessage(dwStatus);
  989. ReportEvent (hEventLog,
  990. EVENTLOG_WARNING_TYPE,
  991. 0,
  992. SMLOG_NET_MESSAGE_WARNING,
  993. NULL,
  994. 3,
  995. sizeof(DWORD),
  996. szStringArray,
  997. (LPVOID)&dwStatus);
  998. pArg->dwNetMsgFailureReported = 1;
  999. }
  1000. } else {
  1001. // there's something flaky in the configuration
  1002. // in that the flag is set, but there's no name
  1003. // in any case, it's not worth worrying about so skip
  1004. }
  1005. }
  1006. if ((pArg->dwAlertActionFlags & ALRT_ACTION_EXEC_CMD) == ALRT_ACTION_EXEC_CMD) {
  1007. DWORD dwStatus = ERROR_SUCCESS;
  1008. dwStatus = DoAlertCommandFile (
  1009. pArg,
  1010. pAlertCI,
  1011. szTimeStamp,
  1012. szValueString,
  1013. szOverUnderString,
  1014. szLimitString);
  1015. }
  1016. if ((pArg->dwAlertActionFlags & ALRT_ACTION_START_LOG) == ALRT_ACTION_START_LOG) {
  1017. DWORD dwStatus;
  1018. // start specified perf data log
  1019. dwStatus = StartLogQuery ( pArg );
  1020. }
  1021. }
  1022. } // end of for each counter in alert loop
  1023. return TRUE;
  1024. }
  1025. BOOL
  1026. AlertProc (
  1027. IN PLOG_QUERY_DATA pArg
  1028. )
  1029. {
  1030. DWORD dwStatus = ERROR_SUCCESS;
  1031. HQUERY hQuery = NULL;
  1032. LARGE_INTEGER liStartDelayTics;
  1033. LARGE_INTEGER liSampleDelayTics;
  1034. LONGLONG llSampleCollectionTics;
  1035. LONGLONG llSampleIntervalTics;
  1036. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  1037. DWORD dwCounterCount;
  1038. LPTSTR szThisPath;
  1039. BOOL bRun = FALSE;
  1040. LPTSTR szStringArray[4];
  1041. LONGLONG llSessionSampleCount=(LONGLONG)-1;
  1042. PALERT_COUNTER_INFO pCtrInfo = NULL;
  1043. PALERT_INFO_BLOCK pAlertInfo = NULL;
  1044. DWORD dwBufSize;
  1045. LONGLONG llStartTime = 0;
  1046. LONGLONG llFinishTime = 0;
  1047. __try {
  1048. #if _DEBUG_OUTPUT
  1049. {
  1050. TCHAR szDebugString[MAX_PATH];
  1051. swprintf (szDebugString, (LPCWSTR)L" Query %s: Thread created\n", pArg->szQueryName);
  1052. OutputDebugString (szDebugString);
  1053. }
  1054. #endif
  1055. liStartDelayTics.QuadPart = ((LONGLONG)(0));
  1056. liSampleDelayTics.QuadPart = ((LONGLONG)(0));
  1057. llSampleCollectionTics = ((LONGLONG)(0));
  1058. // Read registry values.
  1059. if ( ERROR_SUCCESS == LoadQueryConfig ( pArg ) ) {
  1060. bRun = TRUE;
  1061. }
  1062. if ( TRUE == bRun ) {
  1063. // Delay of -1 signals exit immediately.
  1064. liStartDelayTics.QuadPart = ComputeStartWaitTics ( pArg, TRUE );
  1065. if ( NULL_INTERVAL_TICS == liStartDelayTics.QuadPart ) {
  1066. bRun = FALSE;
  1067. }
  1068. }
  1069. if ( TRUE == bRun ) {
  1070. ValidateCommandFilePath ( pArg );
  1071. // open query and add counters from info file
  1072. if (pArg->dwRealTimeQuery == DATA_SOURCE_WBEM) {
  1073. pdhStatus = PdhOpenQueryH(
  1074. H_WBEM_DATASOURCE, 0, & hQuery); // from current activity
  1075. } else {
  1076. pdhStatus = PdhOpenQueryH(
  1077. H_REALTIME_DATASOURCE, 0, & hQuery);
  1078. }
  1079. if (pdhStatus != ERROR_SUCCESS) {
  1080. // unable to open query so write event log message and exit
  1081. szStringArray[0] = pArg->szQueryName;
  1082. szStringArray[1] = FormatEventLogMessage(pdhStatus);
  1083. ReportEvent (hEventLog,
  1084. EVENTLOG_WARNING_TYPE,
  1085. 0,
  1086. SMLOG_UNABLE_OPEN_PDH_QUERY,
  1087. NULL,
  1088. 2,
  1089. sizeof(DWORD),
  1090. szStringArray,
  1091. (LPVOID)&pdhStatus);
  1092. bRun = FALSE;
  1093. }
  1094. }
  1095. // Add each counter and associated alert limits
  1096. if ( TRUE == bRun ) {
  1097. dwCounterCount = 0;
  1098. for (szThisPath = pArg->mszCounterList;
  1099. *szThisPath != 0;
  1100. szThisPath += lstrlen(szThisPath) + 1) {
  1101. HCOUNTER hThisCounter;
  1102. // allocate information block
  1103. dwBufSize = (lstrlenW(szThisPath) + 1) * sizeof(WCHAR);
  1104. dwBufSize += sizeof(ALERT_INFO_BLOCK);
  1105. pAlertInfo = (PALERT_INFO_BLOCK)G_ALLOC(dwBufSize);
  1106. if (pAlertInfo == NULL) {
  1107. dwStatus = SMLOG_UNABLE_ALLOC_ALERT_MEMORY;
  1108. break;
  1109. } else {
  1110. if (MakeInfoFromString (szThisPath, pAlertInfo, &dwBufSize)) {
  1111. // get alert info from string
  1112. pdhStatus = PdhAdd009Counter (hQuery,
  1113. (LPTSTR)pAlertInfo->szCounterPath,
  1114. dwCounterCount,
  1115. &hThisCounter);
  1116. if (pdhStatus != ERROR_SUCCESS) {
  1117. pdhStatus = PdhAddCounter (hQuery,
  1118. (LPTSTR)pAlertInfo->szCounterPath,
  1119. dwCounterCount,
  1120. &hThisCounter);
  1121. }
  1122. if ( !IsErrorSeverity(pdhStatus) ) {
  1123. dwCounterCount++;
  1124. if ( ERROR_SUCCESS != pdhStatus ) {
  1125. // Write event log warning message
  1126. szStringArray[0] = szThisPath;
  1127. szStringArray[1] = pArg->szQueryName;
  1128. szStringArray[2] = FormatEventLogMessage(pdhStatus);
  1129. ReportEvent (hEventLog,
  1130. EVENTLOG_WARNING_TYPE,
  1131. 0,
  1132. SMLOG_ADD_COUNTER_WARNING,
  1133. NULL,
  1134. 3,
  1135. sizeof(DWORD),
  1136. szStringArray,
  1137. (LPVOID)&pdhStatus);
  1138. }
  1139. // then add this handle to the list
  1140. pCtrInfo = G_ALLOC (sizeof (ALERT_COUNTER_INFO));
  1141. if (pCtrInfo != NULL) {
  1142. // insert at front of list since the order isn't
  1143. // important and this is simpler than walking the
  1144. // list each time.
  1145. pCtrInfo->hCounter = hThisCounter;
  1146. pCtrInfo->pAlertInfo = pAlertInfo;
  1147. pCtrInfo->next = (PALERT_COUNTER_INFO)pArg->pFirstCounter;
  1148. pArg->pFirstCounter = (PLOG_COUNTER_INFO)pCtrInfo;
  1149. pAlertInfo = NULL;
  1150. pCtrInfo = NULL;
  1151. } else {
  1152. dwStatus = SMLOG_UNABLE_ALLOC_ALERT_MEMORY;
  1153. G_FREE (pAlertInfo); // toss unused alert buffer
  1154. pAlertInfo = NULL;
  1155. break;
  1156. }
  1157. } else {
  1158. // unable to add the current counter so write event log message
  1159. szStringArray[0] = pAlertInfo->szCounterPath;
  1160. szStringArray[1] = pArg->szQueryName;
  1161. szStringArray[2] = FormatEventLogMessage(pdhStatus);
  1162. if ( PDH_ACCESS_DENIED == pdhStatus ) {
  1163. ReportEvent (
  1164. hEventLog,
  1165. EVENTLOG_WARNING_TYPE,
  1166. 0,
  1167. SMLOG_UNABLE_ACCESS_COUNTER,
  1168. NULL,
  1169. 2,
  1170. 0,
  1171. szStringArray,
  1172. NULL);
  1173. } else {
  1174. ReportEvent (
  1175. hEventLog,
  1176. EVENTLOG_WARNING_TYPE,
  1177. 0,
  1178. SMLOG_UNABLE_ADD_COUNTER,
  1179. NULL,
  1180. 3,
  1181. sizeof(DWORD),
  1182. szStringArray,
  1183. (LPVOID)&pdhStatus);
  1184. }
  1185. if ( NULL != pAlertInfo ) {
  1186. G_FREE (pAlertInfo); // toss unused alert buffer
  1187. pAlertInfo = NULL;
  1188. }
  1189. }
  1190. } else {
  1191. // unable to parse alert info so log an error
  1192. // unable to add the current counter so write event log message
  1193. szStringArray[0] = szThisPath;
  1194. szStringArray[1] = pArg->szQueryName;
  1195. ReportEvent (hEventLog,
  1196. EVENTLOG_WARNING_TYPE,
  1197. 0,
  1198. SMLOG_UNABLE_PARSE_ALERT_INFO,
  1199. NULL,
  1200. 2,
  1201. 0,
  1202. szStringArray,
  1203. NULL);
  1204. if ( NULL != pAlertInfo ) {
  1205. G_FREE (pAlertInfo); // toss unused alert buffer
  1206. pAlertInfo = NULL;
  1207. }
  1208. }
  1209. }
  1210. }
  1211. if ( ERROR_SUCCESS == dwStatus ) {
  1212. if ( 0 < dwCounterCount ) {
  1213. // to make sure we get to log the data
  1214. SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
  1215. } else {
  1216. bRun = FALSE;
  1217. // unable to add any counters so write event log message and exit.
  1218. szStringArray[0] = pArg->szQueryName;
  1219. ReportEvent (hEventLog,
  1220. EVENTLOG_WARNING_TYPE,
  1221. 0,
  1222. SMLOG_UNABLE_ADD_ANY_COUNTERS,
  1223. NULL,
  1224. 1,
  1225. 0,
  1226. szStringArray,
  1227. NULL);
  1228. }
  1229. } else {
  1230. assert ( ERROR_OUTOFMEMORY == dwStatus );
  1231. // Memory allocation error so write event log message and exit.
  1232. szStringArray[0] = pArg->szQueryName;
  1233. ReportEvent (hEventLog,
  1234. EVENTLOG_WARNING_TYPE,
  1235. 0,
  1236. SMLOG_UNABLE_ALLOC_ALERT_MEMORY,
  1237. NULL,
  1238. 1,
  1239. 0,
  1240. szStringArray,
  1241. NULL);
  1242. bRun = FALSE;
  1243. }
  1244. while (bRun) {
  1245. HANDLE arrEventHandle[2];
  1246. arrEventHandle[0] = pArg->hExitEvent; // WAIT_OBJECT_0
  1247. arrEventHandle[1] = pArg->hReconfigEvent;
  1248. if ( 0 < liStartDelayTics.QuadPart ) {
  1249. // NtWaitForMultipleObjects requires negative Tic value
  1250. liStartDelayTics.QuadPart = ((LONGLONG)(0)) - liStartDelayTics.QuadPart;
  1251. // Wait until specified start time, or until exit or reconfigure event.
  1252. if ( STATUS_TIMEOUT != NtWaitForMultipleObjects (
  1253. 2,
  1254. &arrEventHandle[0],
  1255. WaitAny,
  1256. FALSE,
  1257. &liStartDelayTics )) {
  1258. #if _DEBUG_OUTPUT
  1259. {
  1260. TCHAR szDebugString[MAX_PATH];
  1261. swprintf (szDebugString, (LPCWSTR)L" Query %s: Thread received exit or reconfig event\n", pArg->szQueryName);
  1262. OutputDebugString (szDebugString);
  1263. }
  1264. #endif
  1265. bRun = FALSE;
  1266. break; // if we're not supposed to be running then bail out
  1267. }
  1268. }
  1269. pArg->dwCurrentState = SLQ_QUERY_RUNNING;
  1270. dwStatus = WriteRegistryDwordValue (
  1271. pArg->hKeyQuery,
  1272. (LPCWSTR)L"Current State",
  1273. &pArg->dwCurrentState,
  1274. REG_DWORD );
  1275. assert (dwStatus == ERROR_SUCCESS);
  1276. szStringArray[0] = pArg->szQueryName;
  1277. ReportEvent (hEventLog,
  1278. EVENTLOG_INFORMATION_TYPE,
  1279. 0,
  1280. SMLOG_ALERT_SCANNING,
  1281. NULL,
  1282. 1,
  1283. 0,
  1284. szStringArray,
  1285. NULL);
  1286. // Compute session sample count.
  1287. // 0 samples signals no limit.
  1288. // -1 samples signals exit immediately
  1289. ComputeSampleCount( pArg, TRUE, &llSessionSampleCount );
  1290. if ( -1 == llSessionSampleCount ) {
  1291. goto ProcessAlertRepeat;
  1292. }
  1293. // Start sampling immediately. liSampleDelayTics is initialized to 0.
  1294. // Wait until specified sample time, or until exit or reconfigure event.
  1295. while ( STATUS_TIMEOUT == NtWaitForMultipleObjects (
  1296. 2,
  1297. &arrEventHandle[0],
  1298. WaitAny,
  1299. FALSE,
  1300. &liSampleDelayTics)) {
  1301. // An event flag will be set when the sampling should exit or reconfigure. if
  1302. // the wait times out, then that means it's time to collect and
  1303. // log another sample of data.
  1304. GetLocalFileTime (&llStartTime);
  1305. // Check for reconfig event.
  1306. if ( pArg->bLoadNewConfig ) {
  1307. bRun = FALSE;
  1308. break;
  1309. }
  1310. pdhStatus = PdhCollectQueryData (hQuery);
  1311. if ( IsPdhDataCollectSuccess ( pdhStatus )
  1312. || IsWarningSeverity ( pdhStatus ) ) {
  1313. if (pdhStatus == ERROR_SUCCESS) {
  1314. // process alert counters here
  1315. ExamineAlertValues (pArg);
  1316. }
  1317. // see if it's time to restart or end the alert scan.
  1318. // 0 samples signals no sample limit.
  1319. if ( 0 != llSessionSampleCount ) {
  1320. if ( !--llSessionSampleCount )
  1321. break;
  1322. }
  1323. } else {
  1324. // unable to collect the query data so log event and exit
  1325. szStringArray[0] = pArg->szQueryName;
  1326. szStringArray[1] = FormatEventLogMessage(pdhStatus);
  1327. ReportEvent (hEventLog,
  1328. EVENTLOG_WARNING_TYPE,
  1329. 0,
  1330. SMLOG_UNABLE_COLLECT_DATA,
  1331. NULL,
  1332. 2,
  1333. sizeof(DWORD),
  1334. szStringArray,
  1335. (LPVOID)&pdhStatus);
  1336. bRun = FALSE;
  1337. break;
  1338. }
  1339. // compute new timeout value
  1340. GetLocalFileTime (&llFinishTime);
  1341. // compute difference in tics
  1342. llSampleCollectionTics = llFinishTime - llStartTime;
  1343. llSampleIntervalTics =
  1344. (LONGLONG)pArg->dwMillisecondSampleInterval*FILETIME_TICS_PER_MILLISECOND;
  1345. if ( llSampleCollectionTics < llSampleIntervalTics ) {
  1346. liSampleDelayTics.QuadPart = llSampleIntervalTics - llSampleCollectionTics;
  1347. } else {
  1348. liSampleDelayTics.QuadPart = ((LONGLONG)(0));
  1349. }
  1350. // NtWaitForMultipleObjects requires negative Tic value
  1351. liSampleDelayTics.QuadPart = ((LONGLONG)(0)) - liSampleDelayTics.QuadPart;
  1352. } // end while wait keeps timing out
  1353. // Use 0 SampleDelayTics value to check for ExitEvent.
  1354. liSampleDelayTics.QuadPart = ((LONGLONG)(0));
  1355. if ( pArg->bLoadNewConfig ) {
  1356. bRun = FALSE;
  1357. } else if ( STATUS_TIMEOUT != NtWaitForSingleObject (
  1358. pArg->hExitEvent,
  1359. FALSE,
  1360. &liSampleDelayTics ) ) {
  1361. // then the loop was terminated by the Exit event
  1362. // so clear the "run" flag to exit the loop & thread
  1363. bRun = FALSE;
  1364. #if _DEBUG_OUTPUT
  1365. {
  1366. TCHAR szDebugString[MAX_PATH];
  1367. swprintf (szDebugString, (LPCWSTR)L" Query %s: Thread received exit event\n", pArg->szQueryName);
  1368. OutputDebugString (szDebugString);
  1369. }
  1370. #endif
  1371. }
  1372. // If restart not enabled, then exit.
  1373. ProcessAlertRepeat:
  1374. if ( bRun ) {
  1375. bRun = ProcessRepeatOption ( pArg, &liStartDelayTics );
  1376. }
  1377. } // end while (bRun)
  1378. PdhCloseQuery (hQuery);
  1379. hQuery = NULL;
  1380. #if _DEBUG_OUTPUT
  1381. szStringArray[0] = pArg->szQueryName;
  1382. szStringArray[1] = szCurrentLogFile;
  1383. ReportEvent (hEventLog,
  1384. EVENTLOG_INFORMATION_TYPE,
  1385. 0,
  1386. SMLOG_QUERY_STOPPED,
  1387. NULL,
  1388. 2,
  1389. 0,
  1390. szStringArray,
  1391. NULL);
  1392. #endif
  1393. }
  1394. SetLastError ( ERROR_SUCCESS );
  1395. } __except ( EXCEPTION_EXECUTE_HANDLER ) {
  1396. bRun = FALSE;
  1397. if ( NULL != hQuery ) {
  1398. PdhCloseQuery ( hQuery );
  1399. hQuery = NULL;
  1400. }
  1401. SetLastError ( SMLOG_THREAD_FAILED );
  1402. }
  1403. DeallocateQueryBuffers ( pArg );
  1404. while ( NULL != pArg->pFirstCounter ) {
  1405. PALERT_COUNTER_INFO pDelCI = (PALERT_COUNTER_INFO)pArg->pFirstCounter;
  1406. if (pDelCI->pAlertInfo != NULL) G_FREE(pDelCI->pAlertInfo);
  1407. pArg->pFirstCounter = (PLOG_COUNTER_INFO)pDelCI->next;
  1408. G_FREE( pDelCI );
  1409. }
  1410. return bRun;
  1411. }
  1412. BOOL
  1413. CounterLogProc (
  1414. IN PLOG_QUERY_DATA pArg )
  1415. {
  1416. #define INSTBUFLEN 4096
  1417. HQUERY hQuery = NULL;
  1418. HLOG hLog = NULL;
  1419. LARGE_INTEGER liStartDelayTics;
  1420. LARGE_INTEGER liSampleDelayTics;
  1421. LONGLONG llSampleCollectionTics;
  1422. LONGLONG llSampleIntervalTics;
  1423. PDH_STATUS pdhStatus = ERROR_SUCCESS;
  1424. DWORD dwCounterCount;
  1425. DWORD dwStatus = ERROR_SUCCESS;
  1426. INT iCnfSerial;
  1427. DWORD dwSessionSerial;
  1428. LPTSTR szThisPath;
  1429. DWORD dwPdhLogFileType;
  1430. DWORD dwPdhAccessFlags;
  1431. BOOL bRun = FALSE;
  1432. LONGLONG llSessionSampleCount=(LONGLONG)-1;
  1433. LONGLONG llCnfSampleCount=(LONGLONG)-1;
  1434. LONGLONG llLoopSampleCount=(LONGLONG)-1;
  1435. TCHAR szCurrentLogFile[MAX_PATH+1];
  1436. LPTSTR szStringArray[4];
  1437. DWORD dwFileSizeLimit;
  1438. ULONGLONG ullFileSizeLimit;
  1439. LONGLONG llFileSize;
  1440. LONGLONG llStartTime = 0;
  1441. LONGLONG llFinishTime = 0;
  1442. HANDLE arrEventHandle[2];
  1443. PLOG_COUNTER_INFO pDelCI;
  1444. // Wildcard processing
  1445. ULONG ulBufLen;
  1446. INT nCounterBufRetry;
  1447. LPWSTR pszCounterBuf = NULL;
  1448. LPTSTR pszCounter;
  1449. DWORD dwPdhExpandFlags;
  1450. TCHAR achInfoBuf[sizeof(PDH_COUNTER_PATH_ELEMENTS) + MAX_PATH + 5];
  1451. ULONG ulBufSize;
  1452. PPDH_COUNTER_PATH_ELEMENTS pPathInfo = (PPDH_COUNTER_PATH_ELEMENTS)achInfoBuf;
  1453. __try {
  1454. #if _DEBUG_OUTPUT
  1455. {
  1456. TCHAR szDebugString[MAX_PATH];
  1457. swprintf (szDebugString, (LPCWSTR)L" Query %s: Thread created\n", pArg->szQueryName);
  1458. OutputDebugString (szDebugString);
  1459. }
  1460. #endif
  1461. liStartDelayTics.QuadPart = ((LONGLONG)(0));
  1462. liSampleDelayTics.QuadPart = ((LONGLONG)(0));
  1463. llSampleCollectionTics = ((LONGLONG)(0));
  1464. // Read registry values.
  1465. if ( ERROR_SUCCESS == LoadQueryConfig ( pArg ) ) {
  1466. bRun = TRUE;
  1467. }
  1468. if ( TRUE == bRun ) {
  1469. // Delay of -1 signals exit immediately.
  1470. liStartDelayTics.QuadPart = ComputeStartWaitTics ( pArg, TRUE );
  1471. if ( NULL_INTERVAL_TICS == liStartDelayTics.QuadPart ) {
  1472. bRun = FALSE;
  1473. }
  1474. }
  1475. if ( TRUE == bRun ) {
  1476. ValidateCommandFilePath ( pArg );
  1477. // open query and add counters from info file
  1478. if (pArg->dwRealTimeQuery == DATA_SOURCE_WBEM) {
  1479. pdhStatus = PdhOpenQueryH(
  1480. H_WBEM_DATASOURCE, 0, & hQuery); // from current activity
  1481. }
  1482. else {
  1483. pdhStatus = PdhOpenQueryH(
  1484. H_REALTIME_DATASOURCE, 0, & hQuery);
  1485. }
  1486. if (pdhStatus != ERROR_SUCCESS) {
  1487. // unable to open query so write event log message and exit
  1488. szStringArray[0] = pArg->szQueryName;
  1489. szStringArray[1] = FormatEventLogMessage(pdhStatus);
  1490. ReportEvent (hEventLog,
  1491. EVENTLOG_WARNING_TYPE,
  1492. 0,
  1493. SMLOG_UNABLE_OPEN_PDH_QUERY,
  1494. NULL,
  1495. 2,
  1496. sizeof(DWORD),
  1497. szStringArray,
  1498. (LPVOID)&pdhStatus);
  1499. bRun = FALSE;
  1500. }
  1501. }
  1502. // Add each counter to the open query.
  1503. if ( TRUE == bRun ) {
  1504. dwStatus = ERROR_SUCCESS;
  1505. dwCounterCount = 0;
  1506. for (szThisPath = pArg->mszCounterList;
  1507. *szThisPath != 0;
  1508. szThisPath += lstrlen(szThisPath) + 1) {
  1509. if (_tcschr(szThisPath, TEXT('*')) == NULL) {
  1510. // No wildcards
  1511. dwStatus = AddCounterToCounterLog( pArg, szThisPath, hQuery, LOG_EVENT_ON_ERROR, &dwCounterCount );
  1512. } else {
  1513. // At least one wildcard
  1514. dwPdhExpandFlags = 0;
  1515. pszCounterBuf = NULL;
  1516. // Only expand wildcard instances for text log files
  1517. //
  1518. if (pArg->dwLogFileType == SLF_SQL_LOG) {
  1519. // No need to expand wildcard instances for SQL log.
  1520. // SQL log now has the capability to catch dynamic
  1521. // instances, so we can pass in wildcard-instance
  1522. // counter names here.
  1523. //
  1524. dwPdhExpandFlags |= PDH_NOEXPANDINSTANCES;
  1525. }
  1526. else if ( SLF_CSV_FILE != pArg->dwLogFileType
  1527. && SLF_TSV_FILE != pArg->dwLogFileType) {
  1528. // This is binary counter logfile case.
  1529. // No need for expand wildcard instances, also if
  1530. // default real-time datasource is from registry (not
  1531. // WMI), we can handle add-by-object.
  1532. //
  1533. dwPdhExpandFlags |= PDH_NOEXPANDINSTANCES;
  1534. if ( DATA_SOURCE_REGISTRY == pArg->dwRealTimeQuery) {
  1535. // If both instance and counter are wildcards, then log by object
  1536. // rather than expanding the counter path.
  1537. // This is only true when the actual data source is the registry.
  1538. // Parse pathname
  1539. ZeroMemory ( achInfoBuf, sizeof(achInfoBuf) );
  1540. ulBufSize = sizeof(achInfoBuf);
  1541. pdhStatus = PdhParseCounterPath(szThisPath, pPathInfo, &ulBufSize, 0);
  1542. if (pdhStatus == ERROR_SUCCESS) {
  1543. if ( 0 == lstrcmpi ( pPathInfo->szCounterName, _T("*") ) ) {
  1544. if ( NULL != pPathInfo->szInstanceName ) {
  1545. if ( 0 == lstrcmpi ( pPathInfo->szInstanceName, _T("*") ) ) {
  1546. // If PdhAddCounter failed,the realtime data source is actually WBEM.
  1547. // In this case, expand the counter paths.
  1548. dwStatus = AddCounterToCounterLog( pArg, szThisPath, hQuery, !LOG_EVENT_ON_ERROR, &dwCounterCount );
  1549. if ( ERROR_SUCCESS == dwStatus ) {
  1550. continue;
  1551. } else {
  1552. // enumerate counter paths below and retry
  1553. dwStatus = ERROR_SUCCESS;
  1554. }
  1555. }
  1556. } else {
  1557. dwStatus = AddCounterToCounterLog( pArg, szThisPath, hQuery, !LOG_EVENT_ON_ERROR, &dwCounterCount );
  1558. // If PdhAddCounter failed,the realtime data source is actually WBEM.
  1559. // In this case, expand the counter paths.
  1560. if ( ERROR_SUCCESS == dwStatus ) {
  1561. continue;
  1562. } else {
  1563. // enumerate counter paths below and retry
  1564. dwStatus = ERROR_SUCCESS;
  1565. }
  1566. }
  1567. }
  1568. } else {
  1569. // Report event and continue to next counter
  1570. szStringArray[0] = szThisPath;
  1571. szStringArray[1] = pArg->szQueryName;
  1572. szStringArray[2] = FormatEventLogMessage(pdhStatus);
  1573. ReportEvent (
  1574. hEventLog,
  1575. EVENTLOG_WARNING_TYPE,
  1576. 0,
  1577. SMLOG_UNABLE_PARSE_COUNTER,
  1578. NULL,
  1579. 3,
  1580. sizeof(DWORD),
  1581. szStringArray,
  1582. (LPVOID)&pdhStatus);
  1583. continue;
  1584. }
  1585. }
  1586. }
  1587. // Log by object paths are already processed. For other paths with at least
  1588. // one wildcard, expand the path before adding counters.
  1589. ulBufLen = INSTBUFLEN;
  1590. nCounterBufRetry = 10; // the retry counter
  1591. do {
  1592. if ( NULL != pszCounterBuf ) {
  1593. G_FREE(pszCounterBuf);
  1594. pszCounterBuf = NULL;
  1595. ulBufLen *= 2;
  1596. }
  1597. pszCounterBuf = (WCHAR*) G_ALLOC(ulBufLen * sizeof(TCHAR));
  1598. if (pszCounterBuf == NULL) {
  1599. dwStatus = ERROR_OUTOFMEMORY;
  1600. break;
  1601. }
  1602. pdhStatus = PdhExpandWildCardPath (
  1603. NULL,
  1604. (LPWSTR)szThisPath,
  1605. (LPWSTR)pszCounterBuf,
  1606. &ulBufLen,
  1607. dwPdhExpandFlags);
  1608. nCounterBufRetry--;
  1609. } while ((pdhStatus == PDH_MORE_DATA) && (nCounterBufRetry));
  1610. if (ERROR_SUCCESS == pdhStatus && ERROR_SUCCESS == dwStatus ) {
  1611. // Add path
  1612. for (pszCounter = pszCounterBuf;
  1613. *pszCounter != 0;
  1614. pszCounter += lstrlen(pszCounter) + 1) {
  1615. dwStatus = AddCounterToCounterLog ( pArg, pszCounter, hQuery, LOG_EVENT_ON_ERROR, &dwCounterCount );
  1616. if ( ERROR_OUTOFMEMORY == dwStatus ) {
  1617. break;
  1618. }
  1619. }
  1620. }
  1621. if ( NULL != pszCounterBuf ) {
  1622. G_FREE(pszCounterBuf);
  1623. pszCounterBuf = NULL;
  1624. }
  1625. }
  1626. if ( ERROR_OUTOFMEMORY == dwStatus ) {
  1627. szStringArray[0] = pArg->szQueryName;
  1628. ReportEvent (hEventLog,
  1629. EVENTLOG_WARNING_TYPE,
  1630. 0,
  1631. SMLOG_UNABLE_ALLOC_LOG_MEMORY,
  1632. NULL,
  1633. 1,
  1634. 0,
  1635. szStringArray,
  1636. NULL);
  1637. bRun = FALSE;
  1638. } // Other errors reported within the loop
  1639. }
  1640. if ( bRun ) {
  1641. if ( 0 < dwCounterCount ) {
  1642. // to make sure we get to log the data
  1643. SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
  1644. } else {
  1645. bRun = FALSE;
  1646. // unable to add any counters so write event log message and exit.
  1647. szStringArray[0] = pArg->szQueryName;
  1648. ReportEvent (hEventLog,
  1649. EVENTLOG_WARNING_TYPE,
  1650. 0,
  1651. SMLOG_UNABLE_ADD_ANY_COUNTERS,
  1652. NULL,
  1653. 1,
  1654. 0,
  1655. szStringArray,
  1656. NULL);
  1657. }
  1658. }
  1659. while (bRun) {
  1660. arrEventHandle[0] = pArg->hExitEvent; // WAIT_OBJECT_0
  1661. arrEventHandle[1] = pArg->hReconfigEvent;
  1662. // Wait until specified start time, or until exit or reconfig event.
  1663. if ( 0 < liStartDelayTics.QuadPart ) {
  1664. // NtWaitForMultipleObjects requires negative Tic value
  1665. liStartDelayTics.QuadPart = ((LONGLONG)(0)) - liStartDelayTics.QuadPart;
  1666. if ( STATUS_TIMEOUT != NtWaitForMultipleObjects (
  1667. 2,
  1668. &arrEventHandle[0],
  1669. WaitAny,
  1670. FALSE,
  1671. &liStartDelayTics)) {
  1672. #if _DEBUG_OUTPUT
  1673. {
  1674. TCHAR szDebugString[MAX_PATH];
  1675. swprintf (szDebugString, (LPCWSTR)L" Query %s: Thread received reconfig or exit event\n", pArg->szQueryName);
  1676. OutputDebugString (szDebugString);
  1677. }
  1678. #endif
  1679. bRun = FALSE;
  1680. break; // if we're not supposed to be running then bail out
  1681. }
  1682. }
  1683. // Compute session sample count.
  1684. // 0 samples signals no limit.
  1685. // -1 samples signals exit immediately, because stop time is past.
  1686. ComputeSampleCount( pArg, TRUE, &llSessionSampleCount );
  1687. if ( (LONGLONG)(-1) == llSessionSampleCount ) {
  1688. goto ProcessCounterRepeat;
  1689. }
  1690. // Set session or cnf file size limit.
  1691. if ( SLQ_DISK_MAX_SIZE != pArg->dwMaxFileSize )
  1692. dwFileSizeLimit = pArg->dwMaxFileSize * pArg->dwLogFileSizeUnit;
  1693. else
  1694. dwFileSizeLimit = 0;
  1695. // 0 file size signals no limit.
  1696. // Translate from DWORD to ULONGLONG instead of LONGLONG to preserve
  1697. // positive value, even if high bit of dword is used.
  1698. ullFileSizeLimit = ((ULONGLONG)(dwFileSizeLimit));
  1699. ComputeSampleCount( pArg, FALSE, &llCnfSampleCount );
  1700. if ( (LONGLONG)(-1) == llCnfSampleCount ) {
  1701. // Todo cnf: Internal program error, report error and exit.
  1702. bRun = FALSE;
  1703. break;
  1704. }
  1705. if ( SLQ_AUTO_MODE_AFTER == pArg->stiCreateNewFile.dwAutoMode
  1706. || SLQ_AUTO_MODE_SIZE == pArg->stiCreateNewFile.dwAutoMode ) {
  1707. iCnfSerial = 1;
  1708. } else {
  1709. assert ( SLQ_AUTO_MODE_NONE == pArg->stiCreateNewFile.dwAutoMode );
  1710. iCnfSerial = 0;
  1711. }
  1712. dwSessionSerial = pArg->dwCurrentSerialNumber;
  1713. BuildCurrentLogFileName (
  1714. pArg->szQueryName,
  1715. pArg->szBaseFileName,
  1716. pArg->szLogFileFolder,
  1717. pArg->szSqlLogName,
  1718. szCurrentLogFile,
  1719. &dwSessionSerial,
  1720. pArg->dwAutoNameFormat,
  1721. pArg->dwLogFileType,
  1722. iCnfSerial++ );
  1723. // update log serial number if modified.
  1724. if (pArg->dwAutoNameFormat == SLF_NAME_NNNNNN) {
  1725. pArg->dwCurrentSerialNumber++;
  1726. // Todo: Info event on number wrap - Server Beta 3.
  1727. if ( MAXIMUM_SERIAL_NUMBER < pArg->dwCurrentSerialNumber ) {
  1728. pArg->dwCurrentSerialNumber = MINIMUM_SERIAL_NUMBER;
  1729. }
  1730. dwStatus = RegSetValueEx (
  1731. pArg->hKeyQuery,
  1732. (LPCTSTR)TEXT("Log File Serial Number"),
  1733. 0L,
  1734. REG_DWORD,
  1735. (LPBYTE)&pArg->dwCurrentSerialNumber,
  1736. sizeof(DWORD));
  1737. assert ( ERROR_SUCCESS == dwStatus );
  1738. }
  1739. SetPdhOpenOptions ( pArg, &dwPdhAccessFlags, &dwPdhLogFileType );
  1740. // Create new file loop
  1741. while ( bRun && (LONGLONG)(-1) != llSessionSampleCount ) {
  1742. assert ( (LONGLONG)(-1) != llCnfSampleCount );
  1743. // Compute cnf or session loop interval
  1744. if ( (LONGLONG)(0) == llCnfSampleCount
  1745. || ( (LONGLONG)(0) != llSessionSampleCount
  1746. && llCnfSampleCount > llSessionSampleCount ) )
  1747. {
  1748. // No need to create new file within session
  1749. llLoopSampleCount = llSessionSampleCount;
  1750. // Specify exit after first loop if not cnf by size
  1751. if ( SLQ_AUTO_MODE_SIZE != pArg->stiCreateNewFile.dwAutoMode ) {
  1752. llSessionSampleCount = (LONGLONG)(-1);
  1753. }
  1754. } else {
  1755. // Create new file by time before session ends.
  1756. llLoopSampleCount = llCnfSampleCount;
  1757. if ( (LONGLONG)(0) != llSessionSampleCount ) {
  1758. llSessionSampleCount -= llCnfSampleCount;
  1759. // todo cnf: The following should be logically impossible,
  1760. // because session > newfile wait.
  1761. if ( llSessionSampleCount <= (LONGLONG)(0) ) {
  1762. llSessionSampleCount = (LONGLONG)(-1);
  1763. }
  1764. }
  1765. }
  1766. __try {
  1767. // Open log file using this query
  1768. // For text files, max size is checked after each data collection
  1769. pdhStatus = PdhOpenLog (
  1770. szCurrentLogFile,
  1771. dwPdhAccessFlags,
  1772. &dwPdhLogFileType,
  1773. hQuery,
  1774. ( SLF_BIN_CIRC_FILE == pArg->dwLogFileType
  1775. || SLF_BIN_FILE == pArg->dwLogFileType
  1776. || SLF_SQL_LOG == pArg->dwLogFileType )
  1777. ? dwFileSizeLimit
  1778. : 0,
  1779. ( ( PDH_LOG_TYPE_BINARY != dwPdhLogFileType ) ? pArg->szLogFileComment : NULL ),
  1780. &hLog);
  1781. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1782. pdhStatus = PDH_INVALID_ARGUMENT;
  1783. }
  1784. if ( ERROR_SUCCESS != pdhStatus ) {
  1785. // unable to open log file so log event log message
  1786. szStringArray[0] = szCurrentLogFile;
  1787. szStringArray[1] = pArg->szQueryName;
  1788. szStringArray[2] = FormatEventLogMessage(pdhStatus);
  1789. ReportEvent (hEventLog,
  1790. EVENTLOG_WARNING_TYPE,
  1791. 0,
  1792. SMLOG_UNABLE_OPEN_LOG_FILE,
  1793. NULL,
  1794. 3,
  1795. sizeof(DWORD),
  1796. szStringArray,
  1797. (LPVOID)&pdhStatus);
  1798. bRun = FALSE; // exit now
  1799. break;
  1800. } else {
  1801. RegisterCurrentFile( pArg->hKeyQuery, szCurrentLogFile, 0 );
  1802. pArg->dwCurrentState = SLQ_QUERY_RUNNING;
  1803. dwStatus = WriteRegistryDwordValue (
  1804. pArg->hKeyQuery,
  1805. (LPCWSTR)L"Current State",
  1806. &pArg->dwCurrentState,
  1807. REG_DWORD );
  1808. assert (dwStatus == ERROR_SUCCESS);
  1809. szStringArray[0] = pArg->szQueryName;
  1810. szStringArray[1] = szCurrentLogFile;
  1811. ReportEvent (hEventLog,
  1812. EVENTLOG_INFORMATION_TYPE,
  1813. 0,
  1814. SMLOG_LOGGING_QUERY,
  1815. NULL,
  1816. 2,
  1817. 0,
  1818. szStringArray,
  1819. NULL);
  1820. }
  1821. // Start sampling immediately. liSampleDelayTics is initialized to 0.
  1822. while ( STATUS_TIMEOUT == NtWaitForMultipleObjects (
  1823. 2,
  1824. &arrEventHandle[0],
  1825. WaitAny,
  1826. FALSE,
  1827. &liSampleDelayTics)) {
  1828. // An event flag will be set when the sampling should exit or reconfigure. if
  1829. // the wait times out, then that means it's time to collect and
  1830. // log another sample of data.
  1831. GetLocalFileTime (&llStartTime);
  1832. // Check for reconfig event.
  1833. if ( pArg->bLoadNewConfig ) {
  1834. bRun = FALSE;
  1835. break;
  1836. }
  1837. pdhStatus = PdhUpdateLog (hLog, pArg->szLogFileComment );
  1838. if ( IsPdhDataCollectSuccess ( pdhStatus )
  1839. || IsWarningSeverity ( pdhStatus ) ) {
  1840. // see if it's time to restart or end the log.
  1841. // 0 samples signals no sample limit.
  1842. if ( ((LONGLONG)0) != llLoopSampleCount ) {
  1843. if ( !--llLoopSampleCount )
  1844. break;
  1845. }
  1846. if ( ( ((ULONGLONG)0) != ullFileSizeLimit )
  1847. && ( SLF_BIN_CIRC_FILE != pArg->dwLogFileType ) ) {
  1848. // see if the file is too big
  1849. pdhStatus = PdhGetLogFileSize (hLog, &llFileSize);
  1850. if (pdhStatus == ERROR_SUCCESS) {
  1851. if (ullFileSizeLimit <= (ULONGLONG)llFileSize)
  1852. break;
  1853. }
  1854. }
  1855. } else {
  1856. // unable to update the log so log event and exit
  1857. szStringArray[0] = pArg->szQueryName;
  1858. szStringArray[1] = FormatEventLogMessage(pdhStatus);
  1859. ReportEvent (hEventLog,
  1860. EVENTLOG_WARNING_TYPE,
  1861. 0,
  1862. SMLOG_UNABLE_UPDATE_LOG,
  1863. NULL,
  1864. 2,
  1865. sizeof(DWORD),
  1866. szStringArray,
  1867. (LPVOID)&pdhStatus);
  1868. bRun = FALSE;
  1869. break;
  1870. }
  1871. // compute new timeout value
  1872. GetLocalFileTime (&llFinishTime);
  1873. // compute difference in tics
  1874. llSampleCollectionTics = llFinishTime - llStartTime;
  1875. llSampleIntervalTics =
  1876. (LONGLONG)pArg->dwMillisecondSampleInterval*FILETIME_TICS_PER_MILLISECOND;
  1877. if ( llSampleCollectionTics < llSampleIntervalTics ) {
  1878. liSampleDelayTics.QuadPart = llSampleIntervalTics - llSampleCollectionTics;
  1879. } else {
  1880. liSampleDelayTics.QuadPart = ((LONGLONG)(0));
  1881. }
  1882. // NtWaitForMultipleObjects requires negative Tic value
  1883. liSampleDelayTics.QuadPart = ((LONGLONG)(0)) - liSampleDelayTics.QuadPart;
  1884. } // end while wait keeps timing out
  1885. // Use 0 SampleDelayTics value to check for ExitEvent.
  1886. liSampleDelayTics.QuadPart = ((LONGLONG)(0));
  1887. if ( pArg->bLoadNewConfig ) {
  1888. bRun = FALSE;
  1889. } else if ( STATUS_TIMEOUT != NtWaitForSingleObject (
  1890. pArg->hExitEvent,
  1891. FALSE,
  1892. &liSampleDelayTics ) ) {
  1893. // then the loop was terminated by the Exit event
  1894. // so clear the "run" flag to exit the loop & thread
  1895. bRun = FALSE;
  1896. #if _DEBUG_OUTPUT
  1897. {
  1898. TCHAR szDebugString[MAX_PATH];
  1899. swprintf (szDebugString, (LPCWSTR)L" Query %s: Thread received exit event\n", pArg->szQueryName);
  1900. OutputDebugString (szDebugString);
  1901. }
  1902. #endif
  1903. }
  1904. // close log file, but keep query open
  1905. PdhCloseLog (hLog, 0);
  1906. hLog = NULL;
  1907. if ( pArg->bLoadNewConfig )
  1908. break;
  1909. if ( pArg->szCmdFileName != NULL )
  1910. DoLogCommandFile (pArg, szCurrentLogFile, bRun);
  1911. if ( (LONGLONG)(-1) != llSessionSampleCount ) {
  1912. // Create new log name
  1913. BuildCurrentLogFileName (
  1914. pArg->szQueryName,
  1915. pArg->szBaseFileName,
  1916. pArg->szLogFileFolder,
  1917. pArg->szSqlLogName,
  1918. szCurrentLogFile,
  1919. &dwSessionSerial,
  1920. pArg->dwAutoNameFormat,
  1921. pArg->dwLogFileType,
  1922. iCnfSerial++ );
  1923. // Todo cnf: report event on error;
  1924. }
  1925. } // End of log file creation while loop
  1926. // cnf Todo: Handle break from sample loop. ?
  1927. // If restart not enabled, then exit.
  1928. ProcessCounterRepeat:
  1929. if ( bRun ) {
  1930. bRun = ProcessRepeatOption ( pArg, &liStartDelayTics );
  1931. }
  1932. } // end while (bRun)
  1933. PdhCloseQuery (hQuery);
  1934. hQuery = NULL;
  1935. #if _DEBUG_OUTPUT
  1936. szStringArray[0] = pArg->szQueryName;
  1937. szStringArray[1] = szCurrentLogFile;
  1938. ReportEvent (hEventLog,
  1939. EVENTLOG_INFORMATION_TYPE,
  1940. 0,
  1941. SMLOG_QUERY_STOPPED,
  1942. NULL,
  1943. 2,
  1944. 0,
  1945. szStringArray,
  1946. NULL);
  1947. #endif
  1948. }
  1949. SetLastError ( ERROR_SUCCESS );
  1950. } __except ( EXCEPTION_EXECUTE_HANDLER ) {
  1951. bRun = FALSE;
  1952. if ( NULL != pszCounterBuf ) {
  1953. G_FREE(pszCounterBuf);
  1954. pszCounterBuf = NULL;
  1955. }
  1956. if ( NULL != hLog ) {
  1957. PdhCloseLog ( hLog, 0 );
  1958. hLog = NULL;
  1959. }
  1960. if ( NULL != hQuery ) {
  1961. PdhCloseQuery ( hQuery );
  1962. hQuery = NULL;
  1963. }
  1964. SetLastError ( SMLOG_THREAD_FAILED );
  1965. }
  1966. DeallocateQueryBuffers ( pArg );
  1967. while ( NULL != pArg->pFirstCounter ) {
  1968. pDelCI = pArg->pFirstCounter;
  1969. pArg->pFirstCounter = pDelCI->next;
  1970. G_FREE( pDelCI );
  1971. }
  1972. return bRun;
  1973. }
  1974. BOOL
  1975. TraceLogProc (
  1976. IN PLOG_QUERY_DATA pArg
  1977. )
  1978. {
  1979. LARGE_INTEGER liStartDelayTics;
  1980. LARGE_INTEGER liWaitTics;
  1981. LONGLONG llSessionWaitTics = 0;
  1982. LONGLONG llNewFileWaitTics = INFINITE_TICS;
  1983. DWORD dwStatus = ERROR_SUCCESS;
  1984. DWORD dwIndex;
  1985. BOOL bRun = FALSE;
  1986. BOOL bStarted = FALSE;
  1987. LPTSTR szStringArray[4];
  1988. TCHAR szCurrentLogFile[MAX_PATH+1];
  1989. INT iCnfSerial = 0;
  1990. ULONG ulIndex;
  1991. int iEnableCount = 0;
  1992. DWORD dwSessionSerial;
  1993. HANDLE arrEventHandle[2];
  1994. __try {
  1995. #if _DEBUG_OUTPUT
  1996. {
  1997. TCHAR szDebugString[MAX_PATH];
  1998. swprintf (szDebugString, (LPCWSTR)L" Query %s: Thread created\n", pArg->szQueryName);
  1999. OutputDebugString (szDebugString);
  2000. }
  2001. #endif
  2002. liStartDelayTics.QuadPart = NULL_INTERVAL_TICS;
  2003. liWaitTics.QuadPart = ((LONGLONG)(0));
  2004. // Read registry values.
  2005. if ( ERROR_SUCCESS == LoadQueryConfig ( pArg ) ) {
  2006. bRun = TRUE;
  2007. }
  2008. if ( TRUE == bRun ) {
  2009. // Delay of -1 signals exit immediately.
  2010. liStartDelayTics.QuadPart = ComputeStartWaitTics ( pArg, TRUE );
  2011. if ( NULL_INTERVAL_TICS == liStartDelayTics.QuadPart ) {
  2012. bRun = FALSE;
  2013. }
  2014. }
  2015. if ( bRun ) {
  2016. ValidateCommandFilePath ( pArg );
  2017. // to make sure we get to log the data
  2018. SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
  2019. }
  2020. while (bRun) {
  2021. arrEventHandle[0] = pArg->hExitEvent; // WAIT_OBJECT_0
  2022. arrEventHandle[1] = pArg->hReconfigEvent;
  2023. if ( 0 < liStartDelayTics.QuadPart ) {
  2024. // NtWaitForMultipleObjects requires negative Tic value
  2025. liStartDelayTics.QuadPart = ((LONGLONG)(0)) - liStartDelayTics.QuadPart;
  2026. // Wait until specified start time, or until exit or reconfig event.
  2027. if ( STATUS_TIMEOUT != NtWaitForMultipleObjects (
  2028. 2,
  2029. &arrEventHandle[0],
  2030. WaitAny,
  2031. FALSE,
  2032. &liStartDelayTics)) {
  2033. #if _DEBUG_OUTPUT
  2034. {
  2035. TCHAR szDebugString[MAX_PATH];
  2036. swprintf (szDebugString, (LPCWSTR)L" Query %s: Thread received exit or reconfig event\n", pArg->szQueryName);
  2037. OutputDebugString (szDebugString);
  2038. }
  2039. #endif
  2040. bRun = FALSE; // if we're not supposed to be running then bail out
  2041. break;
  2042. }
  2043. }
  2044. ComputeSessionTics( pArg, &llSessionWaitTics );
  2045. // 0 signals no session time, so exit.
  2046. if ( ((LONGLONG)(0)) == llSessionWaitTics ) {
  2047. goto ProcessTraceRepeat;
  2048. }
  2049. // llNewFileWaitTics defaults to -1 if no time limit.
  2050. ComputeNewFileTics( pArg, &llNewFileWaitTics );
  2051. // InitTraceProperties creates the current file name
  2052. dwSessionSerial = pArg->dwCurrentSerialNumber;
  2053. InitTraceProperties ( pArg, TRUE, &dwSessionSerial, &iCnfSerial );
  2054. dwStatus = GetTraceQueryStatus ( pArg, NULL );
  2055. // If trace session with this name already started and successful,
  2056. // don't create another session.
  2057. if ( ERROR_SUCCESS != dwStatus ) {
  2058. dwStatus = StartTrace(
  2059. &pArg->LoggerHandle,
  2060. pArg->szLoggerName,
  2061. &pArg->Properties );
  2062. if (dwStatus == ERROR_SUCCESS) {
  2063. bStarted = TRUE;
  2064. }
  2065. if ( ( ERROR_SUCCESS == dwStatus )
  2066. && !( pArg->Properties.EnableFlags & EVENT_TRACE_FLAG_PROCESS
  2067. || pArg->Properties.EnableFlags & EVENT_TRACE_FLAG_THREAD
  2068. || pArg->Properties.EnableFlags & EVENT_TRACE_FLAG_DISK_IO
  2069. || pArg->Properties.EnableFlags & EVENT_TRACE_FLAG_NETWORK_TCPIP ) ) {
  2070. for ( ulIndex = 0; ulIndex < pArg->ulGuidCount; ulIndex++ ) {
  2071. // Enable user mode and special kernel tracing.
  2072. dwStatus = EnableTrace (
  2073. TRUE,
  2074. 0,
  2075. 0,
  2076. pArg->arrpGuid[ulIndex],
  2077. pArg->LoggerHandle);
  2078. if ( ERROR_SUCCESS == dwStatus ) {
  2079. iEnableCount++;
  2080. } else {
  2081. szStringArray[0] = pArg->arrpszProviderName[ulIndex];
  2082. szStringArray[1] = pArg->szQueryName;
  2083. ReportEvent (hEventLog,
  2084. EVENTLOG_WARNING_TYPE,
  2085. 0,
  2086. SMLOG_UNABLE_ENABLE_TRACE_PROV,
  2087. NULL,
  2088. 2,
  2089. sizeof(DWORD),
  2090. szStringArray,
  2091. (LPVOID)&dwStatus);
  2092. }
  2093. }
  2094. if ( 0 < iEnableCount ) {
  2095. dwStatus = ERROR_SUCCESS;
  2096. } else {
  2097. szStringArray[0] = pArg->szQueryName;
  2098. ReportEvent (hEventLog,
  2099. EVENTLOG_WARNING_TYPE,
  2100. 0,
  2101. SMLOG_TRACE_NO_PROVIDERS,
  2102. NULL,
  2103. 1,
  2104. 0,
  2105. szStringArray,
  2106. NULL);
  2107. bRun = FALSE;
  2108. }
  2109. }
  2110. if ( bRun && ERROR_SUCCESS == dwStatus ) {
  2111. pArg->dwCurrentState = SLQ_QUERY_RUNNING;
  2112. dwStatus = WriteRegistryDwordValue (
  2113. pArg->hKeyQuery,
  2114. (LPCTSTR)L"Current State",
  2115. &pArg->dwCurrentState,
  2116. REG_DWORD );
  2117. szStringArray[0] = pArg->szQueryName;
  2118. szStringArray[1] = pArg->szLogFileName;
  2119. ReportEvent (hEventLog,
  2120. EVENTLOG_INFORMATION_TYPE,
  2121. 0,
  2122. SMLOG_LOGGING_QUERY,
  2123. NULL,
  2124. 2,
  2125. 0,
  2126. szStringArray,
  2127. NULL);
  2128. } else {
  2129. //StartTraceFailed
  2130. //dwStatus should be ERROR_ALREADY_EXISTS if logger already started or anything else
  2131. if ( ERROR_ALREADY_EXISTS == dwStatus ) {
  2132. szStringArray[0] = pArg->szQueryName;
  2133. ReportEvent (hEventLog,
  2134. EVENTLOG_WARNING_TYPE,
  2135. 0,
  2136. SMLOG_TRACE_ALREADY_RUNNING,
  2137. NULL,
  2138. 1,
  2139. 0,
  2140. szStringArray,
  2141. NULL);
  2142. } else {
  2143. szStringArray[0] = pArg->szQueryName;
  2144. ReportEvent (hEventLog,
  2145. EVENTLOG_WARNING_TYPE,
  2146. 0,
  2147. SMLOG_UNABLE_START_TRACE,
  2148. NULL,
  2149. 1,
  2150. sizeof(DWORD),
  2151. szStringArray,
  2152. (LPVOID)&dwStatus );
  2153. }
  2154. bRun = FALSE;
  2155. }
  2156. } else {
  2157. // This means that QueryTrace Returned Error Success.
  2158. // The specified logger is already running.
  2159. szStringArray[0] = pArg->szQueryName;
  2160. ReportEvent (hEventLog,
  2161. EVENTLOG_WARNING_TYPE,
  2162. 0,
  2163. SMLOG_TRACE_ALREADY_RUNNING,
  2164. NULL,
  2165. 1,
  2166. 0,
  2167. szStringArray,
  2168. NULL);
  2169. bRun = FALSE;
  2170. }
  2171. if ( TRUE == bRun ) {
  2172. // Trace logger is now running.
  2173. // Exit when:
  2174. // Wait times out,
  2175. // Exit event signaled, or
  2176. // Reconfig event signaled.
  2177. // -1 wait time signals no limit.
  2178. // Loop wait intervals, calculating interval before each wait.
  2179. while ( ((LONGLONG)(0)) != llSessionWaitTics ) {
  2180. // Calculate wait interval.
  2181. if ( INFINITE_TICS == llNewFileWaitTics
  2182. || ( INFINITE_TICS != llSessionWaitTics
  2183. && llNewFileWaitTics > llSessionWaitTics ) ) {
  2184. // No need to create new file within session
  2185. if ( INFINITE_TICS == llSessionWaitTics ) {
  2186. liWaitTics.QuadPart = llSessionWaitTics;
  2187. // Exit after first loop
  2188. llSessionWaitTics = 0;
  2189. } else {
  2190. liWaitTics.QuadPart = llSessionWaitTics;
  2191. // Exit after first loop
  2192. llSessionWaitTics = 0;
  2193. }
  2194. } else {
  2195. // Create new file before session ends.
  2196. liWaitTics.QuadPart = llNewFileWaitTics;
  2197. if ( INFINITE_TICS != llSessionWaitTics ) {
  2198. llSessionWaitTics -= llNewFileWaitTics;
  2199. // todo cnf: The following should be logically impossible,
  2200. // because session > newfile wait.
  2201. if ( 0 > llSessionWaitTics ) {
  2202. llSessionWaitTics = 0;
  2203. }
  2204. }
  2205. }
  2206. // NtWaitForMultipleObjects requires negative Tic value
  2207. if ( INFINITE_TICS != liWaitTics.QuadPart ) {
  2208. liWaitTics.QuadPart = ((LONGLONG)(0)) - liWaitTics.QuadPart;
  2209. }
  2210. if ( STATUS_TIMEOUT != NtWaitForMultipleObjects (
  2211. 2,
  2212. arrEventHandle,
  2213. WaitAny,
  2214. FALSE,
  2215. ( INFINITE_TICS != liWaitTics.QuadPart ) ? &liWaitTics : NULL ))
  2216. {
  2217. bRun = FALSE;
  2218. break;
  2219. } else {
  2220. // If cnf by time, llNewFileWaitTics will not be infinite
  2221. if ( INFINITE_TICS != llNewFileWaitTics
  2222. && ((LONGLONG)(0)) != llSessionWaitTics ) {
  2223. // Time to create a new file. Don't update the autoformat
  2224. // serial number. Use the initial autoformat serial number
  2225. InitTraceProperties ( pArg, FALSE, &dwSessionSerial, &iCnfSerial );
  2226. dwStatus = UpdateTrace(
  2227. pArg->LoggerHandle,
  2228. pArg->szLoggerName,
  2229. &pArg->Properties );
  2230. // Todo cnf report event on bad status.
  2231. }
  2232. }
  2233. }
  2234. }
  2235. #if _DEBUG_OUTPUT
  2236. liWaitTics.QuadPart = ((LONGLONG)(0));
  2237. if ( pArg->bLoadNewConfig ) {
  2238. TCHAR szDebugString[MAX_PATH];
  2239. swprintf (szDebugString, (LPCWSTR)L" Query %s: Thread received reconfig event\n", pArg->szQueryName);
  2240. OutputDebugString (szDebugString);
  2241. } else if ( STATUS_TIMEOUT != NtWaitForSingleObject (pArg->hExitEvent, FALSE, &liWaitTics )) {
  2242. TCHAR szDebugString[MAX_PATH];
  2243. swprintf (szDebugString, (LPCWSTR)L" Query %s: Thread received exit event\n", pArg->szQueryName);
  2244. OutputDebugString (szDebugString);
  2245. }
  2246. #endif
  2247. if (bStarted == TRUE) {
  2248. // Stop the query.
  2249. if ( !( pArg->Properties.EnableFlags & EVENT_TRACE_FLAG_PROCESS
  2250. || pArg->Properties.EnableFlags & EVENT_TRACE_FLAG_THREAD
  2251. || pArg->Properties.EnableFlags & EVENT_TRACE_FLAG_DISK_IO
  2252. || pArg->Properties.EnableFlags & EVENT_TRACE_FLAG_NETWORK_TCPIP ) ) {
  2253. for (dwIndex = 0; dwIndex < pArg->ulGuidCount; dwIndex++) {
  2254. dwStatus = EnableTrace (
  2255. FALSE,
  2256. 0,
  2257. 0,
  2258. pArg->arrpGuid[dwIndex],
  2259. pArg->LoggerHandle);
  2260. }
  2261. }
  2262. dwStatus = StopTrace (
  2263. pArg->LoggerHandle,
  2264. pArg->szLoggerName,
  2265. &pArg->Properties );
  2266. }
  2267. if ( pArg->bLoadNewConfig )
  2268. break;
  2269. if ( pArg->szCmdFileName != NULL )
  2270. DoLogCommandFile (pArg, szCurrentLogFile, bRun);
  2271. // If restart not enabled, then exit.
  2272. ProcessTraceRepeat:
  2273. if ( bRun ) {
  2274. bRun = ProcessRepeatOption ( pArg, &liStartDelayTics );
  2275. }
  2276. } // end while (bRun)
  2277. #if _DEBUG_OUTPUT
  2278. szStringArray[0] = pArg->szQueryName;
  2279. szStringArray[1] = szCurrentLogFile;
  2280. ReportEvent (hEventLog,
  2281. EVENTLOG_INFORMATION_TYPE,
  2282. 0,
  2283. SMLOG_QUERY_STOPPED,
  2284. NULL,
  2285. 2,
  2286. 0,
  2287. szStringArray,
  2288. NULL);
  2289. #endif
  2290. SetLastError ( ERROR_SUCCESS );
  2291. } __except ( EXCEPTION_EXECUTE_HANDLER ) {
  2292. bRun = FALSE;
  2293. SetLastError ( SMLOG_THREAD_FAILED );
  2294. }
  2295. return bRun;
  2296. }
  2297. DWORD
  2298. LoggingThreadProc (
  2299. IN LPVOID lpThreadArg
  2300. )
  2301. {
  2302. PLOG_QUERY_DATA pThreadData = (PLOG_QUERY_DATA)lpThreadArg;
  2303. DWORD dwStatus = ERROR_SUCCESS;
  2304. HRESULT hr = NOERROR;
  2305. BOOL bContinue = TRUE;
  2306. LPWSTR szStringArray[2];
  2307. if (pThreadData != NULL) {
  2308. __try {
  2309. hr = PdhiPlaRunAs( pThreadData->szQueryName, NULL, &pThreadData->hUserToken );
  2310. if( ERROR_SUCCESS != hr ){
  2311. szStringArray[0] = pThreadData->szQueryName;
  2312. ReportEvent (hEventLog,
  2313. EVENTLOG_WARNING_TYPE,
  2314. 0,
  2315. SMLOG_INVALID_CREDENTIALS,
  2316. NULL,
  2317. 1,
  2318. sizeof(HRESULT),
  2319. szStringArray,
  2320. (LPVOID)&hr
  2321. );
  2322. return hr;
  2323. }
  2324. do {
  2325. // read config from registry
  2326. // expand counter paths as necessary
  2327. if (pThreadData->dwLogType == SLQ_ALERT) {
  2328. // call Alert procedure
  2329. bContinue = AlertProc (pThreadData);
  2330. } else if (pThreadData->dwLogType == SLQ_COUNTER_LOG) {
  2331. // call Logging procedure
  2332. bContinue = CounterLogProc (pThreadData);
  2333. } else if (pThreadData->dwLogType == SLQ_TRACE_LOG) {
  2334. // call Logging procedure
  2335. bContinue = TraceLogProc (pThreadData);
  2336. } else {
  2337. assert (FALSE); // incorrect log type for this function
  2338. }
  2339. // see if this thread was paused for reloading
  2340. // or stopped to terminate
  2341. if (pThreadData->bLoadNewConfig) {
  2342. bContinue = TRUE;
  2343. // Reset the reconfig flag and event.
  2344. pThreadData->bLoadNewConfig = FALSE;
  2345. ResetEvent ( pThreadData->hReconfigEvent );
  2346. } // else bContinue is always returned as FALSE
  2347. // so that will terminate this loop
  2348. } while (bContinue);
  2349. dwStatus = GetLastError();
  2350. } __except ( EXCEPTION_EXECUTE_HANDLER ) {
  2351. dwStatus = SMLOG_THREAD_FAILED;
  2352. }
  2353. } else {
  2354. // unable to find data block so return
  2355. dwStatus = ERROR_INVALID_PARAMETER;
  2356. }
  2357. if ( ERROR_SUCCESS != dwStatus ) {
  2358. szStringArray[0] = pThreadData->szQueryName;
  2359. ReportEvent (
  2360. hEventLog,
  2361. EVENTLOG_WARNING_TYPE,
  2362. 0,
  2363. dwStatus,
  2364. NULL,
  2365. 1,
  2366. 0,
  2367. szStringArray,
  2368. NULL
  2369. );
  2370. }
  2371. return dwStatus;
  2372. }