Leaked source code of windows server 2003
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.

368 lines
9.9 KiB

  1. //***************************************************************************
  2. //
  3. // Copyright � Microsoft Corporation. All rights reserved.
  4. //
  5. // BrodCast.cpp
  6. //
  7. // Purpose: Logging functions
  8. //
  9. //***************************************************************************
  10. #include "precomp.h"
  11. #include <assertbreak.h>
  12. #include <stdio.h>
  13. #include <stdarg.h>
  14. #include <conio.h>
  15. #include <Math.h>
  16. #include <multiplat.h>
  17. #include <BrodCast.h>
  18. #include <impersonaterevert.h>
  19. #include <SmartPtr.h>
  20. #include <helper.h>
  21. // a little something to make sure we don't try to access
  22. // instance variables that no longer exist
  23. bool bAlive = false;
  24. // we only need one of these lying around
  25. ProviderLog captainsLog;
  26. // so we'll build in a check...
  27. #ifdef _DEBUG
  28. bool ProviderLog::m_beenInitted = false;
  29. #endif
  30. //
  31. // neccessary for smart deletion
  32. //
  33. class CThreadBase ;
  34. typedef void ( CThreadBase:: * TBC ) ( void ) ;
  35. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  36. Function: ProviderLog ctor
  37. Description: provides initial initialization
  38. Arguments:
  39. Returns:
  40. Inputs:
  41. Outputs:
  42. Caveats:
  43. Raid:
  44. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  45. ProviderLog::ProviderLog(void) :
  46. m_lastLookedAtRegistry ( 0 ) ,
  47. m_logLevel ( ProviderLog::None )
  48. {
  49. #ifdef _DEBUG
  50. if (m_beenInitted)
  51. ASSERT_BREAK(0); // do not instanciate one of these
  52. // - use the LogMessage macro defined in the header file!
  53. #endif
  54. m_maxSize.QuadPart = 65536 ;
  55. try
  56. {
  57. //
  58. // allocations inside of function will use
  59. // framedyn!operator new which throws
  60. // CHeap_Exception
  61. //
  62. IsLoggingOn () ;
  63. }
  64. catch ( CHeap_Exception & he )
  65. {
  66. //
  67. // hitting following, we may have logging disabled
  68. // for time when framedyn.dll is loaded
  69. //
  70. // although logging is trying dynamically update
  71. // logging level, path etc so eventually it will
  72. // self repair when memory is available
  73. //
  74. // it is safer than count on undefined path and
  75. // m_path may be eventually reloaded next time when
  76. // more memory will be available ...
  77. //
  78. // we just must not re-throw here!
  79. //
  80. }
  81. #ifdef _DEBUG
  82. m_beenInitted = true;
  83. #endif
  84. }
  85. ProviderLog::~ProviderLog(void)
  86. {
  87. bAlive = false ;
  88. }
  89. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  90. Function: IsLoggingOn
  91. Description: determine whether logging is enabled, find path if it is
  92. caches info - it will only look at registry once every three minutes.
  93. Also enforces file size limit.
  94. Arguments: CHString ptr to recieve path (may be NULL)
  95. Returns: LogLevel
  96. Inputs:
  97. Outputs:
  98. Caveats: if return is zero, path is undefined
  99. Raid:
  100. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  101. ProviderLog::LogLevel ProviderLog::IsLoggingOn(CHString *pPath /* = NULL */)
  102. {
  103. union
  104. {
  105. FILETIME fileTime;
  106. unsigned __int64 now;
  107. } myTime;
  108. GetSystemTimeAsFileTime(&myTime.fileTime);
  109. // if three minutes have elapsed, check again.
  110. if ((myTime.now - m_lastLookedAtRegistry) > (180 * 10000000))
  111. {
  112. BeginWrite();
  113. OnDeleteObj0 < CThreadBase, TBC, &CThreadBase::EndWrite> SmartEndWrite ( const_cast < ProviderLog* > ( this ) ) ;
  114. bAlive = false ;
  115. CRegistry RegInfo;
  116. ProviderImpersonationRevert impSelf(FALSE); // So our registry call works.
  117. if(RegInfo.Open(HKEY_LOCAL_MACHINE,
  118. L"SOFTWARE\\Microsoft\\WBEM\\CIMOM",
  119. KEY_READ) == ERROR_SUCCESS)
  120. {
  121. DWORD flag;
  122. // see if we can find the flag
  123. if((RegInfo.GetCurrentKeyValue(L"Logging", flag) == ERROR_SUCCESS) && (flag <= (DWORD)Verbose))
  124. {
  125. // we found one & it's true so we'll try to grab the name itself
  126. if (m_logLevel = (LogLevel)flag)
  127. {
  128. // retrieve dir name or use default
  129. CHString sTemp;
  130. if ((RegInfo.GetCurrentKeyValue(L"Logging Directory", sTemp) != ERROR_SUCCESS)
  131. || (sTemp.IsEmpty()))
  132. sTemp = L"C:\\";
  133. // Expand the environment string
  134. WCHAR szPath[_MAX_PATH];
  135. if (FRExpandEnvironmentStrings(sTemp, szPath, _MAX_PATH) != 0)
  136. {
  137. sTemp = szPath;
  138. // append backslash
  139. if (sTemp[sTemp.GetLength() -1] != '\\')
  140. sTemp += '\\';
  141. }
  142. else
  143. {
  144. sTemp = L"C:\\";
  145. }
  146. // append file name
  147. m_path = sTemp + L"FrameWork.log";
  148. //
  149. // set time we get data out of registry
  150. //
  151. m_lastLookedAtRegistry = myTime.now;
  152. //
  153. // make sure live flag is set. It is safe to assume
  154. // all other member variables are set already and
  155. // worst case, size of file won't change ...
  156. //
  157. bAlive = true ;
  158. CHString maxSizeStr;
  159. if (RegInfo.GetCurrentKeyValue(L"Log File Max Size", maxSizeStr) == ERROR_SUCCESS)
  160. {
  161. m_maxSize.QuadPart = _wtoi64(maxSizeStr);
  162. if (m_maxSize.QuadPart <= 0)
  163. m_maxSize.QuadPart = 65536;
  164. }
  165. else
  166. m_maxSize.QuadPart = 65536;
  167. } // if logging on
  168. } // if reginfo get current key
  169. else
  170. m_logLevel = None;
  171. RegInfo.Close() ;
  172. } // if reginfo open
  173. } // if three minutes have elapsed, check again.
  174. // make sure some other thread doesn't step on our logic
  175. LogLevel ret = ProviderLog::None ;
  176. BeginRead();
  177. OnDeleteObj0 < CThreadBase, TBC, &CThreadBase::EndRead> SmartEndRead ( const_cast < ProviderLog* > ( this ) ) ;
  178. if ( bAlive )
  179. {
  180. if (ret = m_logLevel)
  181. {
  182. if ( NULL != pPath )
  183. {
  184. *pPath = m_path;
  185. }
  186. }
  187. }
  188. return ret;
  189. }
  190. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  191. Function: void LocalLogMessage(char *pszMessageString)
  192. Description: records message in log file
  193. Arguments:
  194. Returns:
  195. Inputs:
  196. Outputs:
  197. Caveats:
  198. Raid:
  199. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  200. void ProviderLog::LocalLogMessage(LPCWSTR pszMessageString, LPCWSTR pszFileName, int lineNo, LogLevel level)
  201. {
  202. #ifdef _DEBUG
  203. // *shouldn't* be able to get here before the static ctor fires!
  204. ASSERT_BREAK(m_beenInitted);
  205. #endif
  206. CHString path;
  207. LARGE_INTEGER liSize;
  208. liSize.QuadPart = 0;
  209. // Doing this call twice avoids the crit section for the most common case. Actually, for the
  210. // most common case, it only gets called once anyway.
  211. if ((level <= IsLoggingOn(NULL)) && (level <= IsLoggingOn(&path)) && !path.IsEmpty())
  212. {
  213. BeginWrite();
  214. OnDeleteObj0 < CThreadBase, TBC, &CThreadBase::EndWrite> SmartEndWrite ( const_cast < ProviderLog* > ( this ) ) ;
  215. if ( bAlive )
  216. {
  217. ProviderImpersonationRevert impSelf(FALSE); // So the file calls work.
  218. SmartCloseHandle hFile;
  219. hFile = ::CreateFileW(
  220. path,
  221. GENERIC_READ | GENERIC_WRITE,
  222. FILE_SHARE_READ,
  223. NULL,
  224. OPEN_ALWAYS,
  225. FILE_ATTRIBUTE_NORMAL,
  226. NULL);
  227. if(hFile != INVALID_HANDLE_VALUE)
  228. {
  229. SYSTEMTIME localTime;
  230. GetLocalTime(&localTime);
  231. CHString chstrMsg;
  232. chstrMsg.Format(
  233. L"%s\t%02d/%02d/%d %02d:%02d:%02d.%03d\tthread:%u\t[%s.%d]\r\n",
  234. pszMessageString,
  235. localTime.wMonth,
  236. localTime.wDay,
  237. localTime.wYear,
  238. localTime.wHour,
  239. localTime.wMinute,
  240. localTime.wSecond,
  241. localTime.wMilliseconds,
  242. GetCurrentThreadId(),
  243. pszFileName,
  244. lineNo);
  245. int nLen = ::WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)chstrMsg, -1, NULL, 0, NULL, NULL);
  246. CSmartBuffer pBuff(nLen);
  247. ::WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)chstrMsg, -1, (LPSTR)(LPBYTE)pBuff, nLen, NULL, NULL);
  248. ::SetFilePointer(
  249. hFile,
  250. 0,
  251. 0,
  252. FILE_END);
  253. DWORD dwNumBytesWritten = 0L;
  254. ::WriteFile(
  255. hFile,
  256. pBuff,
  257. nLen - 1,
  258. &dwNumBytesWritten,
  259. NULL);
  260. // Save the size
  261. ::GetFileSizeEx(
  262. hFile,
  263. &liSize);
  264. // Close the file in case we need to rename
  265. hFile = INVALID_HANDLE_VALUE;
  266. // Check the size against the max
  267. CheckFileSize(liSize, m_path);
  268. }
  269. }
  270. }
  271. }
  272. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  273. Function: CheckFileSize
  274. Description: determines whether the log file has exceeded the alllowable size
  275. if it has, the old one is renamed after the old old one is deleted
  276. Arguments: CRegistry& RegInfo - open registry, full path to file
  277. Returns: usually
  278. Inputs:
  279. Outputs:
  280. Caveats: expects caller to serialize access to this function.
  281. Raid:
  282. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  283. void ProviderLog::CheckFileSize(LARGE_INTEGER& nowSize, const CHString &path)
  284. {
  285. // if it's too big
  286. if (nowSize.QuadPart >= m_maxSize.QuadPart)
  287. {
  288. // generate backup file name = framework.lo_
  289. CHString oldFilePath(path);
  290. oldFilePath.SetAt(oldFilePath.GetLength() -1, L'_');
  291. // delete the old backup file - don't care if it fails
  292. #ifdef UNICODE
  293. _wunlink(oldFilePath);
  294. _wrename(path, oldFilePath);
  295. #else
  296. _unlink(bstr_t(oldFilePath));
  297. rename(bstr_t(path), bstr_t(oldFilePath));
  298. #endif
  299. }
  300. }
  301. void ProviderLog::LocalLogMessage(LPCWSTR pszFileName, int lineNo, LogLevel level, LPCWSTR pszFormatString,...)
  302. {
  303. if (level <= IsLoggingOn(NULL))
  304. {
  305. va_list argList;
  306. va_start(argList, pszFormatString);
  307. CHString sMsg;
  308. sMsg.FormatV(pszFormatString, argList);
  309. va_end(argList);
  310. LocalLogMessage(sMsg, pszFileName, lineNo, level);
  311. }
  312. }