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.

526 lines
12 KiB

  1. /************************************************************************
  2. Copyright (c) 2000 - 2000 Microsoft Corporation
  3. Module Name :
  4. log.cpp
  5. Abstract :
  6. Log controller functions.
  7. Author :
  8. Revision History :
  9. ***********************************************************************/
  10. #include "qmgrlibp.h"
  11. #include <wmistr.h>
  12. #include <initguid.h>
  13. #include <guiddef.h>
  14. #include <evntrace.h>
  15. #if !defined(BITS_V12_ON_NT4)
  16. #include "log.tmh"
  17. #endif
  18. TRACEHANDLE hTraceSessionHandle = NULL;
  19. EVENT_TRACE_PROPERTIES *pTraceProperties = NULL;
  20. LPCTSTR BITSLoggerName = _T("BITS");
  21. LPCTSTR BITSLogFileName = _T("BITS.log");
  22. LPCTSTR BITSLogFileNameBackup = _T("BITS.bak");
  23. const ULONG MAX_STRLEN = 1024;
  24. ULONG BITSMaxLogSize = C_QMGR_LOGFILE_SIZE_DEFAULT; // Size in MB
  25. ULONG BITSFlags = C_QMGR_LOGFILE_FLAGS_DEFAULT;
  26. ULONG BITSLogMinMemory = C_QMGR_LOGFILE_MINMEMORY_DEFAULT; // Size in MB
  27. const ULONG BITSDefaultLevel = 0;
  28. const ULONG BITSLogFileMode = EVENT_TRACE_FILE_MODE_CIRCULAR |
  29. EVENT_TRACE_USE_LOCAL_SEQUENCE;
  30. #if !defined(BITS_V12_ON_NT4)
  31. // Compatibility wrappers since these arn't in WIN2k
  32. ULONG
  33. BITSStopTrace(
  34. TRACEHANDLE TraceHandle,
  35. LPCWSTR InstanceName,
  36. PEVENT_TRACE_PROPERTIES Properties
  37. )
  38. {
  39. return
  40. ControlTraceW(
  41. TraceHandle,
  42. InstanceName,
  43. Properties,
  44. EVENT_TRACE_CONTROL_STOP
  45. );
  46. }
  47. ULONG
  48. BITSQueryTrace(
  49. TRACEHANDLE TraceHandle,
  50. LPCWSTR InstanceName,
  51. PEVENT_TRACE_PROPERTIES Properties
  52. )
  53. {
  54. return
  55. ControlTraceW(
  56. TraceHandle,
  57. InstanceName,
  58. Properties,
  59. EVENT_TRACE_CONTROL_QUERY
  60. );
  61. }
  62. #endif
  63. bool Log_LoadSetting()
  64. {
  65. // returns true is a logger should be
  66. // started if it isn't already started
  67. HKEY hBITSKey;
  68. LONG lResult = RegOpenKey( HKEY_LOCAL_MACHINE, C_QMGR_REG_KEY, &hBITSKey );
  69. if ( ERROR_SUCCESS == lResult )
  70. {
  71. BITSMaxLogSize =
  72. GlobalInfo::RegGetDWORD( hBITSKey,
  73. C_QMGR_LOGFILE_SIZE,
  74. C_QMGR_LOGFILE_SIZE_DEFAULT );
  75. BITSFlags =
  76. GlobalInfo::RegGetDWORD( hBITSKey,
  77. C_QMGR_LOGFILE_FLAGS,
  78. C_QMGR_LOGFILE_FLAGS_DEFAULT );
  79. BITSLogMinMemory =
  80. GlobalInfo::RegGetDWORD( hBITSKey,
  81. C_QMGR_LOGFILE_MINMEMORY,
  82. C_QMGR_LOGFILE_MINMEMORY_DEFAULT );
  83. RegCloseKey( hBITSKey );
  84. }
  85. // Determine if the settings justify starting the logger
  86. if ( !BITSMaxLogSize || !BITSFlags)
  87. return false; // 0 size or no flags
  88. MEMORYSTATUS MemoryStatus;
  89. GlobalMemoryStatus( &MemoryStatus );
  90. SIZE_T MemorySize = MemoryStatus.dwTotalPhys / 0x100000;
  91. if ( MemorySize < BITSLogMinMemory )
  92. return false;
  93. return true; //enable the logger if it isn't already started
  94. }
  95. #if !defined(BITS_V12_ON_NT4)
  96. void Log_StartLogger()
  97. {
  98. try
  99. {
  100. if (!Log_LoadSetting())
  101. {
  102. return;
  103. }
  104. // Allocate trace properties
  105. ULONG SizeNeeded =
  106. sizeof(EVENT_TRACE_PROPERTIES) +
  107. (2 * MAX_STRLEN * sizeof(TCHAR));
  108. pTraceProperties = (PEVENT_TRACE_PROPERTIES) new char[SizeNeeded];
  109. memset( pTraceProperties, 0, SizeNeeded ); // SEC: REVIEWED 2002-03-28
  110. pTraceProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
  111. pTraceProperties->LogFileNameOffset =
  112. sizeof(EVENT_TRACE_PROPERTIES) + (MAX_STRLEN * sizeof(TCHAR));
  113. pTraceProperties->Wnode.BufferSize = SizeNeeded;
  114. pTraceProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
  115. // Setup trace session properties
  116. TCHAR *LoggerName = (LPTSTR)((char*)pTraceProperties + pTraceProperties->LoggerNameOffset);
  117. TCHAR *LogFileName = (LPTSTR)((char*)pTraceProperties + pTraceProperties->LogFileNameOffset);
  118. THROW_HRESULT( StringCchCopy( LoggerName, MAX_STRLEN, BITSLoggerName ));
  119. _tfullpath(LogFileName, BITSLogFileName, MAX_STRLEN);
  120. pTraceProperties->LogFileMode |= BITSLogFileMode;
  121. pTraceProperties->MaximumFileSize = BITSMaxLogSize;
  122. ULONG Status;
  123. // if an existing session is started, if so just use that
  124. // session unmodified
  125. Status =
  126. BITSQueryTrace(
  127. NULL,
  128. LoggerName,
  129. pTraceProperties);
  130. if ( ERROR_SUCCESS == Status)
  131. {
  132. LogInfo("Using existing BITS logger session");
  133. return;
  134. }
  135. MoveFileEx( BITSLogFileName, BITSLogFileNameBackup, MOVEFILE_REPLACE_EXISTING );
  136. Status =
  137. StartTrace(
  138. &hTraceSessionHandle,
  139. LoggerName,
  140. pTraceProperties);
  141. if ( ERROR_SUCCESS != Status )
  142. {
  143. hTraceSessionHandle = NULL;
  144. return;
  145. }
  146. Status = EnableTrace(
  147. TRUE,
  148. BITSFlags,
  149. BITSDefaultLevel,
  150. &BITSCtrlGuid,
  151. hTraceSessionHandle);
  152. LogInfo("Started new logger session");
  153. LogInfo("Max log size is %u MB", BITSMaxLogSize );
  154. LogInfo("Log Flags %x", BITSFlags );
  155. LogInfo("Min Memory settings %u MB", BITSLogMinMemory );
  156. }
  157. catch ( ComError err )
  158. {
  159. delete[] pTraceProperties;
  160. pTraceProperties = NULL;
  161. }
  162. }
  163. void Log_StopLogger()
  164. {
  165. if ( !pTraceProperties )
  166. return;
  167. if ( hTraceSessionHandle )
  168. {
  169. BITSStopTrace(
  170. hTraceSessionHandle,
  171. NULL,
  172. pTraceProperties);
  173. hTraceSessionHandle = NULL;
  174. }
  175. delete[] pTraceProperties;
  176. pTraceProperties = NULL;
  177. }
  178. BOOL
  179. Log_Init(void)
  180. {
  181. WPP_INIT_TRACING(L"Microsoft\\BITS");
  182. return TRUE;
  183. }
  184. void
  185. Log_Close()
  186. {
  187. Log_StopLogger();
  188. WPP_CLEANUP();
  189. }
  190. #endif
  191. #if defined(BITS_V12_ON_NT4)
  192. #define MAX_LOG_STRING 4000
  193. #define MAX_REPLACED_FORMAT 256
  194. CRITICAL_SECTION g_LogCs;
  195. static HANDLE g_LogFile = INVALID_HANDLE_VALUE;
  196. static bool g_LogInitialized = false;
  197. struct FormatReplaceElement
  198. {
  199. DWORD SearchSize;
  200. const char *SearchString;
  201. DWORD ReplacementSize;
  202. const char *ReplacementString;
  203. };
  204. // sort table first by size, then by string
  205. FormatReplaceElement g_FormatReplaceElements[] =
  206. {
  207. { 5, "%!ts!", 3, "%ls" },
  208. { 6, "%!sid!", 2, "%p" },
  209. { 7, "%!guid!", 2, "%p" },
  210. { 7, "%!tstr!", 3, "%ls" },
  211. { 9, "%!winerr!", 7, "0x%8.8X" },
  212. { 10, "%!netrate!", 2, "%G" },
  213. { 12, "%!timestamp!", 9, "0x%16.16X" }
  214. };
  215. const DWORD NumberOfFormatReplaceElements =
  216. sizeof( g_FormatReplaceElements ) / sizeof( *g_FormatReplaceElements );
  217. int __cdecl FormatReplaceElementComparison( const void *elem1, const void *elem2 )
  218. {
  219. const FormatReplaceElement *felem1 = (const FormatReplaceElement*)elem1;
  220. const FormatReplaceElement *felem2 = (const FormatReplaceElement*)elem2;
  221. if ( felem1->SearchSize != felem2->SearchSize )
  222. return felem1->SearchSize - felem2->SearchSize;
  223. return _stricmp( felem1->SearchString, felem2->SearchString );
  224. }
  225. void
  226. LogGenerateNewFormat(
  227. char *NewFormat,
  228. const char *Format,
  229. DWORD BufferSize )
  230. {
  231. if ( !BufferSize )
  232. return;
  233. BufferSize--; // Dont count the terminating NULL
  234. while( 1 )
  235. {
  236. if ( !BufferSize || !*Format )
  237. {
  238. *NewFormat = '\0';
  239. return;
  240. }
  241. if ( '%' == Format[0] &&
  242. '!' == Format[1] )
  243. {
  244. const char *Begin = Format;
  245. const char *End = Format + 2;
  246. while( *End != '!' )
  247. {
  248. if ( '\0' == *End++ )
  249. goto NormalChar;
  250. }
  251. FormatReplaceElement Key = { (DWORD)(End - Begin) + 1, Begin, (DWORD)(End - Begin) + 1, Begin };
  252. FormatReplaceElement *Replacement = (FormatReplaceElement*)
  253. bsearch( &Key,
  254. &g_FormatReplaceElements,
  255. NumberOfFormatReplaceElements,
  256. sizeof( *g_FormatReplaceElements ),
  257. &FormatReplaceElementComparison );
  258. if ( !Replacement )
  259. goto NormalChar;
  260. if ( Replacement->ReplacementSize > BufferSize )
  261. {
  262. *NewFormat = '\0';
  263. return;
  264. }
  265. memcpy( NewFormat, Replacement->ReplacementString,
  266. sizeof( char ) * Replacement->ReplacementSize );
  267. NewFormat += Replacement->ReplacementSize;
  268. BufferSize -= Replacement->ReplacementSize;
  269. Format = End + 1;
  270. }
  271. else
  272. {
  273. NormalChar:
  274. *NewFormat++ = *Format++;
  275. BufferSize--;
  276. }
  277. }
  278. }
  279. void
  280. Log(const CHAR *Prefix,
  281. const CHAR *Format,
  282. va_list ArgList )
  283. {
  284. if ( !g_LogInitialized)
  285. return;
  286. EnterCriticalSection( &g_LogCs );
  287. if ( !g_LogInitialized)
  288. return;
  289. static char OutputString[ MAX_LOG_STRING ];
  290. DWORD ThreadId = GetCurrentThreadId();
  291. DWORD ProcessId = GetCurrentProcessId();
  292. SYSTEMTIME Time;
  293. GetSystemTime( &Time );
  294. int CharsWritten =
  295. _snprintf( OutputString,
  296. sizeof( OutputString ) - 3,
  297. "%.2u/%.2u/%.4u-%.2u:%.2u:%.2u.%.3u %X.%X ",
  298. Time.wMonth,
  299. Time.wDay,
  300. Time.wYear,
  301. Time.wHour,
  302. Time.wMinute,
  303. Time.wSecond,
  304. Time.wMilliseconds,
  305. ProcessId,
  306. ThreadId );
  307. if ( -1 != CharsWritten )
  308. {
  309. int CharsWritten2 =
  310. _snprintf( OutputString + CharsWritten,
  311. sizeof( OutputString ) - CharsWritten - 3,
  312. "%s",
  313. Prefix );
  314. if ( -1 == CharsWritten2 )
  315. goto overflow;
  316. CharsWritten += CharsWritten2;
  317. char NewFormat[ MAX_REPLACED_FORMAT ];
  318. LogGenerateNewFormat(
  319. NewFormat,
  320. Format,
  321. MAX_REPLACED_FORMAT );
  322. int CharsWritten3 =
  323. _vsnprintf( OutputString + CharsWritten,
  324. sizeof( OutputString ) - CharsWritten - 3,
  325. NewFormat,
  326. ArgList );
  327. if ( -1 == CharsWritten3 )
  328. goto overflow;
  329. CharsWritten += CharsWritten3;
  330. OutputString[ CharsWritten++ ] = '\r';
  331. OutputString[ CharsWritten++ ] = '\n';
  332. OutputString[ CharsWritten++ ] = '\0';
  333. }
  334. else
  335. {
  336. overflow:
  337. OutputString[ sizeof( OutputString ) - 3 ] = '\r';
  338. OutputString[ sizeof( OutputString ) - 2 ] = '\n';
  339. OutputString[ sizeof( OutputString ) - 1 ] = '\0';
  340. CharsWritten = sizeof( OutputString );
  341. }
  342. if ( INVALID_HANDLE_VALUE != g_LogFile )
  343. {
  344. DWORD BytesWritten;
  345. WriteFile(
  346. g_LogFile,
  347. OutputString,
  348. CharsWritten,
  349. &BytesWritten,
  350. NULL );
  351. }
  352. #if defined( DBG )
  353. OutputDebugStringA( OutputString );
  354. #endif
  355. LeaveCriticalSection( &g_LogCs );
  356. }
  357. void
  358. Log_StartLogger()
  359. {
  360. if (!Log_LoadSetting())
  361. return;
  362. if ( BITSLogFileName && BITSFlags )
  363. {
  364. g_LogFile = CreateFile(
  365. BITSLogFileName,
  366. GENERIC_WRITE,
  367. FILE_SHARE_READ,
  368. NULL,
  369. CREATE_ALWAYS, // overwrite any existing file
  370. FILE_ATTRIBUTE_NORMAL,
  371. NULL
  372. );
  373. }
  374. }
  375. void
  376. Log_StopLogger()
  377. {
  378. if ( g_LogFile )
  379. {
  380. CloseHandle( g_LogFile );
  381. }
  382. g_LogInitialized = true;
  383. }
  384. BOOL
  385. Log_Init(void)
  386. {
  387. if ( !InitializeCriticalSectionAndSpinCount( &g_LogCs, 0x80000000 ) )
  388. return FALSE;
  389. g_LogInitialized = true;
  390. return TRUE;
  391. }
  392. void
  393. Log_Close()
  394. {
  395. EnterCriticalSection( &g_LogCs );
  396. Log_StopLogger();
  397. g_LogInitialized = false;
  398. DeleteCriticalSection( &g_LogCs );
  399. }
  400. #endif