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.

893 lines
25 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. omlog.c
  5. Abstract:
  6. logging routines for the object log stream
  7. this code was jumpstarted from the clusrtl logging code. Most notably, it
  8. is UTF-8 encoded which allows full Unicode without the cost of writing
  9. 16b. for each character.
  10. remaining issues to solve: proper truncation of log file based on current
  11. starting session. We'd like to remember as many sessions as possible but
  12. since I've chosen UTF-8, I can't jump to the middle of the file and start
  13. looking around. One possibility strategy is using an alternate NTFS stream
  14. to record the starting offsets of sessions. If that stream didn't exist or
  15. we're on a FAT FS, then we'll continue with the current strategy.
  16. Author:
  17. Charlie Wickham (charlwi) 07-May-2001
  18. Environment:
  19. User Mode
  20. Revision History:
  21. --*/
  22. #include "omp.h"
  23. //
  24. // when this sequence is at the beginning of the file, it indicates that the
  25. // file is UTF8 encoded
  26. //
  27. #define UTF8_BOM "\x0EF\x0BB\x0BF"
  28. //
  29. // Private Data
  30. //
  31. DWORD OmpLogFileLimit;
  32. DWORD OmpCurrentSessionStart;
  33. BOOL OmpLogToFile = FALSE;
  34. HANDLE OmpLogFileHandle = NULL;
  35. DWORD OmpProcessId;
  36. DWORD OmpCurrentSessionOffset;
  37. PCLRTL_WORK_QUEUE OmpLoggerWorkQueue;
  38. //
  39. // structure used to pass formatted buffers to work queue routine
  40. //
  41. typedef struct _OM_LOG_BUFFER_DESC {
  42. DWORD TimeBytes;
  43. DWORD MsgBytes;
  44. PCHAR TimeBuffer;
  45. PCHAR MsgBuffer;
  46. } OM_LOG_BUFFER_DESC, *POM_LOG_BUFFER_DESC;
  47. #define MAX_NUMBER_LENGTH 20
  48. // Specify maximum file size ( DWORD / 1MB )
  49. #define MAX_FILE_SIZE ( 0xFFFFF000 / ( 1024 * 1024 ) )
  50. DWORD OmpLogFileLimit = ( 1 * 1024 * 1024 ); // 1 MB default
  51. DWORD OmpLogFileLoWater = 0;
  52. //
  53. // internal functions
  54. //
  55. DWORD
  56. OmpTruncateFile(
  57. IN HANDLE FileHandle,
  58. IN DWORD FileSize,
  59. IN LPDWORD LastPosition
  60. )
  61. /*++
  62. Routine Description:
  63. Truncate a file by copying the portion starting at LastPosition and ending
  64. at EOF to the front of the file and setting the file's EOF pointer to the
  65. end of the new chunk. We always keep the current session even that means
  66. growing larger than the file limit.
  67. For now, we have no good way of finding all the sessions within the file,
  68. so if the file must be truncated, we whack it back to the beginning of the
  69. current session. If time permits, I'll add something more intelligent
  70. later on.
  71. Arguments:
  72. FileHandle - File handle.
  73. FileSize - Current End of File.
  74. LastPosition - On input, specifies the starting position in the file from
  75. which the copy begins. On output, it is set to the new EOF
  76. Return Value:
  77. New end of file.
  78. --*/
  79. {
  80. //
  81. // The following buffer size should never be more than 1/4 the size of the
  82. // file.
  83. //
  84. #define BUFFER_SIZE ( 64 * 1024 )
  85. DWORD bytesLeft;
  86. DWORD endPosition = sizeof( UTF8_BOM ) - 1;
  87. DWORD bufferSize;
  88. DWORD bytesRead;
  89. DWORD bytesWritten;
  90. DWORD fileSizeHigh = 0;
  91. DWORD readPosition;
  92. DWORD writePosition;
  93. PVOID dataBuffer;
  94. //
  95. // current session is already at beginning of file so bale now...
  96. //
  97. if ( OmpCurrentSessionOffset == sizeof( UTF8_BOM ) - 1) {
  98. return FileSize;
  99. }
  100. //
  101. // don't truncate the current session, i.e., always copy from the start of
  102. // the current session
  103. //
  104. if ( *LastPosition > OmpCurrentSessionOffset ) {
  105. *LastPosition = OmpCurrentSessionOffset;
  106. }
  107. if ( *LastPosition > FileSize ) {
  108. //
  109. // something's confused; the spot we're supposed to copy from is at or
  110. // past the current EOF. reset the entire file
  111. //
  112. goto error_exit;
  113. }
  114. dataBuffer = LocalAlloc( LMEM_FIXED, BUFFER_SIZE );
  115. if ( !dataBuffer ) {
  116. goto error_exit;
  117. }
  118. //
  119. // calc number of bytes to move
  120. //
  121. bytesLeft = FileSize - *LastPosition;
  122. endPosition = bytesLeft + sizeof( UTF8_BOM ) - 1;
  123. //
  124. // Point back to last position for reading.
  125. //
  126. readPosition = *LastPosition;
  127. writePosition = sizeof( UTF8_BOM ) - 1;
  128. while ( bytesLeft ) {
  129. if ( bytesLeft >= BUFFER_SIZE ) {
  130. bufferSize = BUFFER_SIZE;
  131. } else {
  132. bufferSize = bytesLeft;
  133. }
  134. bytesLeft -= bufferSize;
  135. SetFilePointer( FileHandle,
  136. readPosition,
  137. &fileSizeHigh,
  138. FILE_BEGIN );
  139. if ( ReadFile( FileHandle,
  140. dataBuffer,
  141. bufferSize,
  142. &bytesRead,
  143. NULL ) )
  144. {
  145. SetFilePointer( FileHandle,
  146. writePosition,
  147. &fileSizeHigh,
  148. FILE_BEGIN );
  149. WriteFile( FileHandle,
  150. dataBuffer,
  151. bytesRead,
  152. &bytesWritten,
  153. NULL );
  154. } else {
  155. endPosition = sizeof( UTF8_BOM ) - 1;
  156. break;
  157. }
  158. readPosition += bytesRead;
  159. writePosition += bytesWritten;
  160. }
  161. LocalFree( dataBuffer );
  162. //
  163. // for now, we only only one truncate by setting the current position to
  164. // the beginning of file.
  165. //
  166. OmpCurrentSessionOffset = sizeof( UTF8_BOM ) - 1;
  167. error_exit:
  168. //
  169. // Force end of file to get set.
  170. //
  171. SetFilePointer( FileHandle,
  172. endPosition,
  173. &fileSizeHigh,
  174. FILE_BEGIN );
  175. SetEndOfFile( FileHandle );
  176. *LastPosition = endPosition;
  177. return(endPosition);
  178. } // OmpTruncateFile
  179. VOID
  180. OmpLoggerWorkThread(
  181. IN PCLRTL_WORK_ITEM WorkItem,
  182. IN DWORD Status,
  183. IN DWORD BytesTransferred,
  184. IN ULONG_PTR IoContext
  185. )
  186. /*++
  187. Routine Description:
  188. work queue worker routine. actually does the write to the file.
  189. Arguments:
  190. standard ClRtl thread args; we only care about WorkItem
  191. Return Value:
  192. None
  193. --*/
  194. {
  195. DWORD fileSize;
  196. DWORD fileSizeHigh;
  197. DWORD tsBytesWritten;
  198. DWORD msgBytesWritten;
  199. POM_LOG_BUFFER_DESC bufDesc = (POM_LOG_BUFFER_DESC)(WorkItem->Context);
  200. fileSize = GetFileSize( OmpLogFileHandle, &fileSizeHigh );
  201. ASSERT( fileSizeHigh == 0 ); // We're only using DWORDs!
  202. if ( fileSize > OmpLogFileLimit ) {
  203. fileSize = OmpTruncateFile( OmpLogFileHandle, fileSize, &OmpLogFileLoWater );
  204. }
  205. SetFilePointer( OmpLogFileHandle,
  206. fileSize,
  207. &fileSizeHigh,
  208. FILE_BEGIN );
  209. WriteFile(OmpLogFileHandle,
  210. bufDesc->TimeBuffer,
  211. bufDesc->TimeBytes,
  212. &tsBytesWritten,
  213. NULL);
  214. WriteFile(OmpLogFileHandle,
  215. bufDesc->MsgBuffer,
  216. bufDesc->MsgBytes,
  217. &msgBytesWritten,
  218. NULL);
  219. //
  220. // if we haven't set the lo water mark, wait until the file size has
  221. // crossed the halfway mark and set it to the beginning of the line we
  222. // just wrote.
  223. //
  224. if ( OmpLogFileLoWater == 0 && (fileSize > (OmpLogFileLimit / 2)) ) {
  225. OmpLogFileLoWater = fileSize;
  226. ASSERT( OmpLogFileLoWater >= OmpCurrentSessionOffset );
  227. }
  228. } // OmpLoggerWorkThread
  229. VOID
  230. OmpLogPrint(
  231. LPWSTR FormatString,
  232. ...
  233. )
  234. /*++
  235. Routine Description:
  236. Prints a message to the object config log file.
  237. Arguments:
  238. FormatString - The initial message string to print.
  239. Any FormatMessage-compatible arguments to be inserted in the message
  240. before it is logged.
  241. Return Value:
  242. None.
  243. --*/
  244. {
  245. PWCHAR unicodeOutput = NULL;
  246. PCHAR timestampBuffer;
  247. DWORD timestampBytes;
  248. PCHAR utf8Buffer;
  249. DWORD utf8Bytes;
  250. PWCHAR unicodeBuffer;
  251. DWORD unicodeBytes;
  252. DWORD status = ERROR_SUCCESS;
  253. SYSTEMTIME Time;
  254. ULONG_PTR ArgArray[9];
  255. va_list ArgList;
  256. //
  257. // init the variable arg list
  258. //
  259. va_start(ArgList, FormatString);
  260. if ( !OmpLogToFile ) {
  261. va_end(ArgList);
  262. return;
  263. }
  264. GetSystemTime(&Time);
  265. ArgArray[0] = OmpProcessId;
  266. ArgArray[1] = GetCurrentThreadId();
  267. ArgArray[2] = Time.wYear;
  268. ArgArray[3] = Time.wMonth;
  269. ArgArray[4] = Time.wDay;
  270. ArgArray[5] = Time.wHour;
  271. ArgArray[6] = Time.wMinute;
  272. ArgArray[7] = Time.wSecond;
  273. ArgArray[8] = Time.wMilliseconds;
  274. //
  275. // we can get away with formatting it as ANSI since our data is all numbers
  276. //
  277. timestampBytes = FormatMessageA(FORMAT_MESSAGE_FROM_STRING |
  278. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  279. FORMAT_MESSAGE_ALLOCATE_BUFFER,
  280. "%1!08lx!.%2!08lx!::%3!02d!/%4!02d!/%5!02d!-%6!02d!:%7!02d!:%8!02d!.%9!03d! ",
  281. 0,
  282. 0,
  283. (LPSTR)&timestampBuffer,
  284. 50,
  285. (va_list*)&ArgArray);
  286. if ( timestampBytes == 0 ) {
  287. va_end(ArgList);
  288. // WmiTrace("Prefix format failed, %d: %!ARSTR!", GetLastError(), FormatString);
  289. return;
  290. }
  291. //
  292. // format the message in unicode
  293. //
  294. try {
  295. unicodeBytes = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
  296. | FORMAT_MESSAGE_FROM_STRING,
  297. FormatString,
  298. 0,
  299. 0,
  300. (LPWSTR)&unicodeOutput,
  301. 512,
  302. &ArgList);
  303. }
  304. except ( EXCEPTION_EXECUTE_HANDLER ) {
  305. unicodeBytes = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
  306. | FORMAT_MESSAGE_FROM_STRING
  307. | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  308. L"LOGERROR(exception): Could not print message: %1!ws!",
  309. 0,
  310. 0,
  311. (LPWSTR)&unicodeOutput,
  312. 512,
  313. (va_list *) &FormatString );
  314. }
  315. va_end(ArgList);
  316. if (unicodeBytes != 0) {
  317. PCLRTL_WORK_ITEM workQItem;
  318. //
  319. // convert the output to UTF-8; first get the size to see if it will
  320. // fit in our stack buffer.
  321. //
  322. utf8Bytes = WideCharToMultiByte(CP_UTF8,
  323. 0, // dwFlags
  324. unicodeOutput,
  325. unicodeBytes,
  326. NULL,
  327. 0,
  328. NULL, // lpDefaultChar
  329. NULL); // lpUsedDefaultChar
  330. utf8Buffer = LocalAlloc( LMEM_FIXED, utf8Bytes );
  331. if ( utf8Buffer == NULL ) {
  332. status = ERROR_NOT_ENOUGH_MEMORY;
  333. goto error_exit;
  334. }
  335. utf8Bytes = WideCharToMultiByte(CP_UTF8,
  336. 0, // dwFlags
  337. unicodeOutput,
  338. unicodeBytes,
  339. utf8Buffer,
  340. utf8Bytes,
  341. NULL, // lpDefaultChar
  342. NULL); // lpUsedDefaultChar
  343. workQItem = (PCLRTL_WORK_ITEM)LocalAlloc(LMEM_FIXED,
  344. sizeof( CLRTL_WORK_ITEM ) + sizeof( OM_LOG_BUFFER_DESC ));
  345. if ( workQItem != NULL ) {
  346. POM_LOG_BUFFER_DESC bufDesc = (POM_LOG_BUFFER_DESC)(workQItem + 1);
  347. bufDesc->TimeBytes = timestampBytes;
  348. bufDesc->TimeBuffer = timestampBuffer;
  349. bufDesc->MsgBytes = utf8Bytes;
  350. bufDesc->MsgBuffer = utf8Buffer;
  351. ClRtlInitializeWorkItem( workQItem, OmpLoggerWorkThread, bufDesc );
  352. status = ClRtlPostItemWorkQueue( OmpLoggerWorkQueue, workQItem, 0, 0 );
  353. } else {
  354. status = ERROR_NOT_ENOUGH_MEMORY;
  355. goto error_exit;
  356. }
  357. // WmiTrace("%!level! %!ARSTR!", *(UCHAR*)&LogLevel, AnsiString.Buffer + timestampBytes);
  358. } else {
  359. // WmiTrace("Format returned 0 bytes: %!ARSTR!", FormatString);
  360. status = GetLastError();
  361. }
  362. error_exit:
  363. if ( unicodeOutput != NULL ) {
  364. LocalFree( unicodeOutput );
  365. }
  366. return;
  367. } // OmpLogPrint
  368. //
  369. // exported (within OM) functions
  370. //
  371. VOID
  372. OmpOpenObjectLog(
  373. VOID
  374. )
  375. /*++
  376. Routine Description:
  377. Use the clusterlog environment variable to open another file that contains
  378. object mgr name to ID mapping info. If the routine fails, the failure is
  379. logged in the cluster log but no logging will be done to the object log
  380. file.
  381. NOTE: access to the file is synchronized since this routine is assumed to
  382. be called only once by OmInit. Arguments:
  383. Arguments:
  384. None
  385. Return Value:
  386. None
  387. --*/
  388. {
  389. WCHAR logFileBuffer[MAX_PATH];
  390. LPWSTR logFileName = NULL;
  391. LPWSTR objectLogExtension = L".obj";
  392. DWORD status = ERROR_SUCCESS;
  393. DWORD defaultLogSize = 1; // in MB
  394. DWORD envLength;
  395. WCHAR logFileSize[MAX_NUMBER_LENGTH];
  396. DWORD logSize;
  397. LPWSTR lpszBakFileName = NULL;
  398. DWORD fileSizeHigh = 0;
  399. DWORD fileSizeLow;
  400. DWORD bytesWritten;
  401. PWCHAR dot;
  402. UNICODE_STRING logFileString;
  403. //
  404. // see if logging has been specified; get a buffer big enough that will
  405. // hold the object log name
  406. //
  407. envLength = GetEnvironmentVariable(L"ClusterLog",
  408. logFileBuffer,
  409. sizeof(logFileBuffer)/sizeof(WCHAR));
  410. if ( envLength > (( sizeof(logFileBuffer) + sizeof(objectLogExtension)) / sizeof(WCHAR)) ) {
  411. //
  412. // allocate a larger buffer since our static one wasn't big enough
  413. //
  414. logFileName = LocalAlloc( LMEM_FIXED,
  415. envLength * sizeof( WCHAR ) );
  416. if ( logFileName == NULL ) {
  417. ClRtlLogPrint(LOG_UNUSUAL,
  418. "[OM] Unable to get memory for Object log filename buffer\n");
  419. return;
  420. }
  421. envLength = GetEnvironmentVariable(L"ClusterLog",
  422. logFileName,
  423. envLength);
  424. if ( envLength == 0 ) {
  425. ClRtlLogPrint(LOG_UNUSUAL,
  426. "[OM] Unable to read ClusterLog environment variable\n");
  427. goto error_exit;
  428. }
  429. } else if ( envLength != 0 ) {
  430. logFileName = logFileBuffer;
  431. }
  432. if ( logFileName == NULL ) {
  433. //
  434. // logging is turned off or we can't determine where to put the file.
  435. //
  436. goto error_exit;
  437. }
  438. //
  439. // Try to get a limit on the log file size. This number is the number of
  440. // MB.
  441. //
  442. envLength = GetEnvironmentVariable(L"ClusterLogSize",
  443. logFileSize,
  444. sizeof(logFileSize)/sizeof(WCHAR));
  445. if ( envLength != 0 && envLength < MAX_NUMBER_LENGTH ) {
  446. RtlInitUnicodeString( &logFileString, logFileSize );
  447. status = RtlUnicodeStringToInteger( &logFileString,
  448. 10,
  449. &logSize );
  450. if ( NT_SUCCESS( status ) ) {
  451. OmpLogFileLimit = logSize;
  452. }
  453. } else {
  454. OmpLogFileLimit = defaultLogSize;
  455. }
  456. status = ERROR_SUCCESS;
  457. if ( OmpLogFileLimit == 0 ) {
  458. goto error_exit;
  459. }
  460. //
  461. // make the file size no bigger than one-eighth the size of the normal log
  462. // file but no less than 256KB
  463. //
  464. if ( OmpLogFileLimit > MAX_FILE_SIZE ) {
  465. OmpLogFileLimit = MAX_FILE_SIZE;
  466. }
  467. OmpLogFileLimit = ( OmpLogFileLimit * ( 1024 * 1024 )) / 8;
  468. if ( OmpLogFileLimit < ( 256 * 1024 )) {
  469. OmpLogFileLimit = 256 * 1024;
  470. }
  471. //
  472. // replace the filename with the object log name; deal with the use of
  473. // forward slashes
  474. //
  475. dot = wcsrchr( logFileName, L'.' );
  476. if ( dot != NULL ) {
  477. wcscpy( dot, objectLogExtension );
  478. } else {
  479. wcscat( logFileName, objectLogExtension );
  480. }
  481. OmpLogFileHandle = CreateFile(logFileName,
  482. GENERIC_READ | GENERIC_WRITE,
  483. FILE_SHARE_READ | FILE_SHARE_WRITE,
  484. NULL,
  485. OPEN_ALWAYS,
  486. 0,
  487. NULL );
  488. if ( OmpLogFileHandle == INVALID_HANDLE_VALUE ) {
  489. status = GetLastError();
  490. ClRtlLogPrint(LOG_UNUSUAL,
  491. "[OM] Open of object log file failed. Error %1!u!\n",
  492. status);
  493. goto error_exit;
  494. } else {
  495. //
  496. // write UTF-8 header to beginning of file and get the offset of the
  497. // EOF; we never want to reset the start of the file after this point.
  498. //
  499. WriteFile( OmpLogFileHandle, UTF8_BOM, sizeof( UTF8_BOM ) - 1, &bytesWritten, NULL );
  500. OmpCurrentSessionOffset = SetFilePointer( OmpLogFileHandle, 0, NULL, FILE_END );
  501. if ( OmpCurrentSessionOffset == INVALID_SET_FILE_POINTER ) {
  502. ClRtlLogPrint(LOG_UNUSUAL,
  503. "[OM] Unable to get object log end of file position. error %1!u!.\n",
  504. GetLastError());
  505. CloseHandle( OmpLogFileHandle );
  506. goto error_exit;
  507. }
  508. OmpLogToFile = TRUE;
  509. OmpProcessId = GetCurrentProcessId();
  510. //
  511. // determine the initial low water mark. We have 3 cases
  512. // we need to handle:
  513. // 1) log size is less than 1/2 limit
  514. // 2) log size is within limit but more than 1/2 limit
  515. // 3) log size is greater than limit
  516. //
  517. // case 1 requires nothing special; the low water mark will be updated
  518. // on the next log write.
  519. //
  520. // for case 2, we need to find the beginning of a line near 1/2 the
  521. // current limit. for case 3, the place to start looking is current
  522. // log size - 1/2 limit. In this case, the log will be truncated
  523. // before the first write occurs, so we need to take the last 1/2
  524. // limit bytes and copy them down to the front.
  525. //
  526. //
  527. // For now, set the low water mark to be the current offset. When it
  528. // is time to wrap, we'll lose everything but the current session.
  529. //
  530. // the problem is that we're dealing with UTF8 and we can't just jump
  531. // in the middle of the file and start looking around (we might hit
  532. // the 2nd byte of a DBCS sequence). For now, we'll leave
  533. // OmpLogFileLoWater set to zero. It will get updated when the 1/2 way
  534. // threshold is crossed.
  535. //
  536. OmpLogFileLoWater = OmpCurrentSessionOffset;
  537. #if 0
  538. fileSizeLow = GetFileSize( OmpLogFileHandle, &fileSizeHigh );
  539. if ( fileSizeLow < ( OmpLogFileLimit / 2 )) {
  540. //
  541. // case 1: leave low water at zero; it will be updated with next
  542. // log write
  543. //
  544. ;
  545. } else {
  546. #define LOGBUF_SIZE 1024
  547. CHAR buffer[LOGBUF_SIZE];
  548. LONG currentPosition;
  549. DWORD bytesRead;
  550. if ( fileSizeLow < OmpLogFileLimit ) {
  551. //
  552. // case 2; start looking at the 1/2 the current limit to find
  553. // the starting position
  554. //
  555. currentPosition = OmpLogFileLimit / 2;
  556. } else {
  557. //
  558. // case 3: start at current size minus 1/2 limit to find our
  559. // starting position.
  560. //
  561. currentPosition = fileSizeLow - ( OmpLogFileLimit / 2 );
  562. }
  563. //
  564. // backup from the initial file position, read in a block and look
  565. // for the start of a session. When we find one, backup to the
  566. // beginning of that line. Use that as the initial starting
  567. // position when we finally truncate the file.
  568. //
  569. OmpLogFileLoWater = 0;
  570. currentPosition -= LOGBUF_SIZE;
  571. SetFilePointer(OmpLogFileHandle,
  572. currentPosition,
  573. &fileSizeHigh,
  574. FILE_BEGIN);
  575. do {
  576. if ( ReadFile(OmpLogFileHandle,
  577. buffer,
  578. LOGBUF_SIZE - 1,
  579. &bytesRead,
  580. NULL ) )
  581. {
  582. PCHAR p = buffer;
  583. PCHAR newp;
  584. buffer[ bytesRead ] = NULL;
  585. while ( *p != 'S' && bytesRead-- != 0 ) {
  586. newp = CharNextExA( CP_UTF8, p, 0 );
  587. if ( newp == p ) {
  588. break;
  589. }
  590. p = newp;
  591. }
  592. if ( p != newp ) {
  593. if ( strchr( p, "START" )) {
  594. //
  595. // set pointer to beginning of line
  596. //
  597. p = currentLine;
  598. break;
  599. }
  600. } else {
  601. //
  602. // not found in this block; read in the next one
  603. //
  604. }
  605. }
  606. } while ( TRUE );
  607. if ( *p == '\n' ) {
  608. OmpLogFileLoWater = (DWORD)(currentPosition + ( p - buffer + 1 ));
  609. }
  610. if ( OmpLogFileLoWater == 0 ) {
  611. //
  612. // couldn't find any reasonable data. just set it to
  613. // initial current position.
  614. //
  615. OmpLogFileLoWater = currentPosition + LOGBUF_SIZE;
  616. }
  617. }
  618. #endif
  619. }
  620. //
  621. // finally, create the threadq that will handle the IO to the file
  622. //
  623. OmpLoggerWorkQueue = ClRtlCreateWorkQueue( 1, THREAD_PRIORITY_BELOW_NORMAL );
  624. if ( OmpLoggerWorkQueue == NULL ) {
  625. CloseHandle( OmpLogFileHandle );
  626. ClRtlLogPrint(LOG_UNUSUAL,
  627. "[OM] Unable to logger work queue. error %1!u!.\n",
  628. GetLastError());
  629. }
  630. error_exit:
  631. if ( logFileName != logFileBuffer && logFileName != NULL ) {
  632. LocalFree( logFileName );
  633. }
  634. } // OmpOpenObjectLog
  635. VOID
  636. OmpLogStartRecord(
  637. VOID
  638. )
  639. /*++
  640. Routine Description:
  641. Description
  642. Arguments:
  643. None
  644. Return Value:
  645. None
  646. --*/
  647. {
  648. OSVERSIONINFOEXW version;
  649. BOOL success;
  650. PWCHAR suiteAbbrev;
  651. SYSTEMTIME localTime;
  652. GetLocalTime( &localTime );
  653. version.dwOSVersionInfoSize = sizeof(version);
  654. success = GetVersionExW((POSVERSIONINFOW)&version);
  655. if ( success ) {
  656. //
  657. // Log the System version number
  658. //
  659. if ( version.wSuiteMask & VER_SUITE_DATACENTER ) {
  660. suiteAbbrev = L"DTC";
  661. } else if ( version.wSuiteMask & VER_SUITE_ENTERPRISE ) {
  662. suiteAbbrev = L"ADS";
  663. } else if ( version.wSuiteMask & VER_SUITE_EMBEDDEDNT ) {
  664. suiteAbbrev = L"EMB";
  665. } else if ( version.wProductType & VER_NT_WORKSTATION ) {
  666. suiteAbbrev = L"WS";
  667. } else if ( version.wProductType & VER_NT_DOMAIN_CONTROLLER ) {
  668. suiteAbbrev = L"DC";
  669. } else if ( version.wProductType & VER_NT_SERVER ) {
  670. suiteAbbrev = L"SRV"; // otherwise - some non-descript Server
  671. } else {
  672. suiteAbbrev = L"";
  673. }
  674. OmpLogPrint(L"START %1!02d!/%2!02d!/%3!02d!-%4!02d!:%5!02d!:%6!02d!.%7!03d! %8!u! %9!u! "
  675. L"%10!u! %11!u! %12!u! %13!u! \"%14!ws!\" "
  676. L"%15!u! %16!u! %17!04X! (%18!ws!) %19!u!\n",
  677. localTime.wYear,
  678. localTime.wMonth,
  679. localTime.wDay,
  680. localTime.wHour,
  681. localTime.wMinute,
  682. localTime.wSecond,
  683. localTime.wMilliseconds,
  684. CLUSTER_GET_MAJOR_VERSION( CsMyHighestVersion ),
  685. CLUSTER_GET_MINOR_VERSION( CsMyHighestVersion ),
  686. version.dwMajorVersion, // param 10
  687. version.dwMinorVersion,
  688. version.dwBuildNumber,
  689. version.dwPlatformId,
  690. version.szCSDVersion,
  691. version.wServicePackMajor, // param 15
  692. version.wServicePackMinor,
  693. version.wSuiteMask,
  694. suiteAbbrev,
  695. version.wProductType);
  696. }
  697. } // OmpLogStartRecord
  698. VOID
  699. OmpLogStopRecord(
  700. VOID
  701. )
  702. /*++
  703. Routine Description:
  704. Description
  705. Arguments:
  706. None
  707. Return Value:
  708. None
  709. --*/
  710. {
  711. OmpLogPrint( L"STOP\n" );
  712. } // OmpLogStopRecord
  713. /* end omlog.c */