Team Fortress 2 Source Code as on 22/4/2020
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.

766 lines
34 KiB

  1. //============ Copyright (c) Valve Corporation, All rights reserved. ============
  2. //
  3. // Logging system declarations.
  4. //
  5. // The logging system is a channel-based output mechanism which allows
  6. // subsystems to route their text/diagnostic output to various listeners
  7. //
  8. //===============================================================================
  9. #ifndef LOGGING_H
  10. #define LOGGING_H
  11. #if defined( COMPILER_MSVC )
  12. #pragma once
  13. #endif
  14. #include "color.h"
  15. #include "icommandline.h"
  16. #include <stdio.h>
  17. // For XBX_** functions
  18. #if defined( _X360 )
  19. #include "xbox/xbox_console.h"
  20. #endif
  21. // Used by CColorizedLoggingListener
  22. #if defined( _WIN32 ) || (defined(POSIX) && !defined(_GAMECONSOLE))
  23. #include "tier0/win32consoleio.h"
  24. #endif
  25. /*
  26. ---- Logging System ----
  27. The logging system is a channel-based mechanism for all code (engine,
  28. mod, tool) across all platforms to output information, warnings,
  29. errors, etc.
  30. This system supersedes the existing Msg(), Warning(), Error(), DevMsg(), ConMsg() etc. functions.
  31. There are channels defined in the new system through which all old messages are routed;
  32. see LOG_GENERAL, LOG_CONSOLE, LOG_DEVELOPER, etc.
  33. To use the system, simply call one of the predefined macros:
  34. Log_Msg( ChannelID, [Color], Message, ... )
  35. Log_Warning( ChannelID, [Color], Message, ... )
  36. Log_Error( ChannelID, [Color], Message, ... )
  37. A ChannelID is typically created by defining a logging channel with the
  38. log channel macros:
  39. DEFINE_LOGGING_CHANNEL_NO_TAGS( LOG_ChannelName, "ChannelName", [Flags], [MinimumSeverity], [Color] );
  40. or
  41. BEGIN_DEFINE_LOGGING_CHANNEL( LOG_ChannelName, "ChannelName", [Flags], [MinimumSeverity], [Color] );
  42. ADD_LOGGING_CHANNEL_TAG( "Tag1" );
  43. ADD_LOGGING_CHANNEL_TAG( "Tag2" );
  44. END_DEFINE_LOGGING_CHANNEL();
  45. These macros create a global channel ID variable with the name specified
  46. by the first parameter (in this example, LOG_ChannelName). This channel ID
  47. can be used by various LoggingSystem_** functions to manipulate the channel settings.
  48. The optional [Flags] parameter is an OR'd together set of LoggingChannelFlags_t
  49. values (default: 0).
  50. The optional [MinimumSeverity] parameter is the lowest threshold
  51. above which messages will be processed (inclusive). The default is LS_MESSAGE,
  52. which results in all messages, warnings, and errors being logged.
  53. Variadic parameters to the Log_** functions will be ignored if a channel
  54. is not enabled for a given severity (for performance reasons).
  55. Logging channels can have their minimum severity modified by name, ID, or tag.
  56. Logging channels are not hierarchical since there are situations in which
  57. a channel needs to belong to multiple hierarchies. Use tags to create
  58. categories or shallow hierarchies.
  59. @TODO (Feature wishlist):
  60. 1) Callstack logging support
  61. 2) Registering dynamic channels and unregistering channels at runtime
  62. 3) Sentient robot to clean up the thousands of places using the old/legacy logging system.
  63. */
  64. //////////////////////////////////////////////////////////////////////////
  65. // Constants, Types, Forward Declares
  66. //////////////////////////////////////////////////////////////////////////
  67. class CLoggingSystem;
  68. class CThreadFastMutex;
  69. //-----------------------------------------------------------------------------
  70. // Maximum length of a sprintf'ed logging message.
  71. //-----------------------------------------------------------------------------
  72. const int MAX_LOGGING_MESSAGE_LENGTH = 2048;
  73. //-----------------------------------------------------------------------------
  74. // Maximum length of a channel or tag name.
  75. //-----------------------------------------------------------------------------
  76. const int MAX_LOGGING_IDENTIFIER_LENGTH = 32;
  77. //-----------------------------------------------------------------------------
  78. // Maximum number of logging channels. Increase if needed.
  79. //-----------------------------------------------------------------------------
  80. const int MAX_LOGGING_CHANNEL_COUNT = 256;
  81. //-----------------------------------------------------------------------------
  82. // Maximum number of logging tags across all channels. Increase if needed.
  83. //-----------------------------------------------------------------------------
  84. const int MAX_LOGGING_TAG_COUNT = 1024;
  85. //-----------------------------------------------------------------------------
  86. // Maximum number of characters across all logging tags. Increase if needed.
  87. //-----------------------------------------------------------------------------
  88. const int MAX_LOGGING_TAG_CHARACTER_COUNT = 8192;
  89. //-----------------------------------------------------------------------------
  90. // Maximum number of concurrent logging listeners in a given logging state.
  91. //-----------------------------------------------------------------------------
  92. const int MAX_LOGGING_LISTENER_COUNT = 16;
  93. //-----------------------------------------------------------------------------
  94. // An invalid color set on a channel to imply that it should use
  95. // a device-dependent default color where applicable.
  96. //-----------------------------------------------------------------------------
  97. const Color UNSPECIFIED_LOGGING_COLOR( 0, 0, 0, 0 );
  98. //-----------------------------------------------------------------------------
  99. // An ID returned by the logging system to refer to a logging channel.
  100. //-----------------------------------------------------------------------------
  101. typedef int LoggingChannelID_t;
  102. //-----------------------------------------------------------------------------
  103. // A sentinel value indicating an invalid logging channel ID.
  104. //-----------------------------------------------------------------------------
  105. const LoggingChannelID_t INVALID_LOGGING_CHANNEL_ID = -1;
  106. //-----------------------------------------------------------------------------
  107. // The severity of a logging operation.
  108. //-----------------------------------------------------------------------------
  109. enum LoggingSeverity_t
  110. {
  111. //-----------------------------------------------------------------------------
  112. // An informative logging message.
  113. //-----------------------------------------------------------------------------
  114. LS_MESSAGE = 0,
  115. //-----------------------------------------------------------------------------
  116. // A warning, typically non-fatal
  117. //-----------------------------------------------------------------------------
  118. LS_WARNING = 1,
  119. //-----------------------------------------------------------------------------
  120. // A message caused by an Assert**() operation.
  121. //-----------------------------------------------------------------------------
  122. LS_ASSERT = 2,
  123. //-----------------------------------------------------------------------------
  124. // An error, typically fatal/unrecoverable.
  125. //-----------------------------------------------------------------------------
  126. LS_ERROR = 3,
  127. //-----------------------------------------------------------------------------
  128. // A placeholder level, higher than any legal value.
  129. // Not a real severity value!
  130. //-----------------------------------------------------------------------------
  131. LS_HIGHEST_SEVERITY = 4,
  132. };
  133. //-----------------------------------------------------------------------------
  134. // Action which should be taken by logging system as a result of
  135. // a given logged message.
  136. //
  137. // The logging system invokes ILoggingResponsePolicy::OnLog() on
  138. // the specified policy object, which returns a LoggingResponse_t.
  139. //-----------------------------------------------------------------------------
  140. enum LoggingResponse_t
  141. {
  142. LR_CONTINUE,
  143. LR_DEBUGGER,
  144. LR_ABORT,
  145. };
  146. //-----------------------------------------------------------------------------
  147. // Logging channel behavior flags, set on channel creation.
  148. //-----------------------------------------------------------------------------
  149. enum LoggingChannelFlags_t
  150. {
  151. //-----------------------------------------------------------------------------
  152. // Indicates that the spew is only relevant to interactive consoles.
  153. //-----------------------------------------------------------------------------
  154. LCF_CONSOLE_ONLY = 0x00000001,
  155. //-----------------------------------------------------------------------------
  156. // Indicates that spew should not be echoed to any output devices.
  157. // A suitable logging listener must be registered which respects this flag
  158. // (e.g. a file logger).
  159. //-----------------------------------------------------------------------------
  160. LCF_DO_NOT_ECHO = 0x00000002,
  161. };
  162. //-----------------------------------------------------------------------------
  163. // A callback function used to register tags on a logging channel
  164. // during initialization.
  165. //-----------------------------------------------------------------------------
  166. typedef void ( *RegisterTagsFunc )();
  167. //-----------------------------------------------------------------------------
  168. // A context structure passed to logging listeners and response policy classes.
  169. //-----------------------------------------------------------------------------
  170. struct LoggingContext_t
  171. {
  172. // ID of the channel being logged to.
  173. LoggingChannelID_t m_ChannelID;
  174. // Flags associated with the channel.
  175. LoggingChannelFlags_t m_Flags;
  176. // Severity of the logging event.
  177. LoggingSeverity_t m_Severity;
  178. // Color of logging message if one was specified to Log_****() macro.
  179. // If not specified, falls back to channel color.
  180. // If channel color is not specified, this value is UNSPECIFIED_LOGGING_COLOR
  181. // and indicates that a suitable default should be chosen.
  182. Color m_Color;
  183. };
  184. //-----------------------------------------------------------------------------
  185. // Interface for classes to handle logging output.
  186. //
  187. // The Log() function of this class is called synchronously and serially
  188. // by the logging system on all registered instances of ILoggingListener
  189. // in the current "logging state".
  190. //
  191. // Derived classes may do whatever they want with the message (write to disk,
  192. // write to console, send over the network, drop on the floor, etc.).
  193. //
  194. // In general, derived classes should do one, simple thing with the output
  195. // to allow callers to register multiple, orthogonal logging listener classes.
  196. //-----------------------------------------------------------------------------
  197. class ILoggingListener
  198. {
  199. public:
  200. virtual void Log( const LoggingContext_t *pContext, const tchar *pMessage ) = 0;
  201. };
  202. //-----------------------------------------------------------------------------
  203. // Interface for policy classes which determine how to behave when a
  204. // message is logged.
  205. //
  206. // Can return:
  207. // LR_CONTINUE (continue execution)
  208. // LR_DEBUGGER (break into debugger if one is present, otherwise continue)
  209. // LR_ABORT (terminate process immediately with a failure code of 1)
  210. //-----------------------------------------------------------------------------
  211. class ILoggingResponsePolicy
  212. {
  213. public:
  214. virtual LoggingResponse_t OnLog( const LoggingContext_t *pContext ) = 0;
  215. };
  216. //////////////////////////////////////////////////////////////////////////
  217. // Common Logging Listeners & Logging Response Policies
  218. //////////////////////////////////////////////////////////////////////////
  219. //-----------------------------------------------------------------------------
  220. // A basic logging listener which prints to stdout and the debug channel.
  221. //-----------------------------------------------------------------------------
  222. class CSimpleLoggingListener : public ILoggingListener
  223. {
  224. public:
  225. CSimpleLoggingListener( bool bQuietPrintf = false, bool bQuietDebugger = false ) :
  226. m_bQuietPrintf( bQuietPrintf ),
  227. m_bQuietDebugger( bQuietDebugger )
  228. {
  229. }
  230. virtual void Log( const LoggingContext_t *pContext, const tchar *pMessage )
  231. {
  232. #ifdef _X360
  233. if ( !m_bQuietDebugger && XBX_IsConsoleConnected() )
  234. {
  235. // send to console
  236. XBX_DebugString( XMAKECOLOR( 0,0,0 ), pMessage );
  237. }
  238. else
  239. #endif
  240. {
  241. #if !defined( _CERT ) && !defined( DBGFLAG_STRINGS_STRIP )
  242. if ( !m_bQuietPrintf )
  243. {
  244. _tprintf( _T("%s"), pMessage );
  245. }
  246. #endif
  247. #ifdef _WIN32
  248. if ( !m_bQuietDebugger && Plat_IsInDebugSession() )
  249. {
  250. Plat_DebugString( pMessage );
  251. }
  252. #endif
  253. }
  254. }
  255. // If set to true, does not print anything to stdout.
  256. bool m_bQuietPrintf;
  257. // If set to true, does not print anything to debugger.
  258. bool m_bQuietDebugger;
  259. };
  260. //-----------------------------------------------------------------------------
  261. // A basic logging listener for GUI applications
  262. //-----------------------------------------------------------------------------
  263. class CSimpleWindowsLoggingListener : public ILoggingListener
  264. {
  265. public:
  266. virtual void Log( const LoggingContext_t *pContext, const tchar *pMessage )
  267. {
  268. if ( Plat_IsInDebugSession() )
  269. {
  270. Plat_DebugString( pMessage );
  271. }
  272. if ( pContext->m_Severity == LS_ERROR )
  273. {
  274. if ( Plat_IsInDebugSession() )
  275. DebuggerBreak();
  276. Plat_MessageBox( "Error", pMessage );
  277. }
  278. }
  279. };
  280. //-----------------------------------------------------------------------------
  281. // ** NOTE FOR INTEGRATION **
  282. // This was copied over from source 2 rather than integrated because
  283. // source 2 has more significantly refactored tier0 logging.
  284. //
  285. // A logging listener with Win32 console API color support which which prints
  286. // to stdout and the debug channel.
  287. //-----------------------------------------------------------------------------
  288. #if !defined(_GAMECONSOLE)
  289. class CColorizedLoggingListener : public CSimpleLoggingListener
  290. {
  291. public:
  292. CColorizedLoggingListener( bool bQuietPrintf = false, bool bQuietDebugger = false ) : CSimpleLoggingListener( bQuietPrintf, bQuietDebugger )
  293. {
  294. InitWin32ConsoleColorContext( &m_ColorContext );
  295. }
  296. virtual void Log( const LoggingContext_t *pContext, const tchar *pMessage )
  297. {
  298. if ( !m_bQuietPrintf )
  299. {
  300. int nPrevColor = -1;
  301. if ( pContext->m_Color != UNSPECIFIED_LOGGING_COLOR )
  302. {
  303. nPrevColor = SetWin32ConsoleColor( &m_ColorContext,
  304. pContext->m_Color.r(), pContext->m_Color.g(), pContext->m_Color.b(),
  305. MAX( MAX( pContext->m_Color.r(), pContext->m_Color.g() ), pContext->m_Color.b() ) > 128 );
  306. }
  307. _tprintf( _T("%s"), pMessage );
  308. if ( nPrevColor >= 0 )
  309. {
  310. RestoreWin32ConsoleColor( &m_ColorContext, nPrevColor );
  311. }
  312. }
  313. #ifdef _WIN32
  314. if ( !m_bQuietDebugger && Plat_IsInDebugSession() )
  315. {
  316. Plat_DebugString( pMessage );
  317. }
  318. #endif
  319. }
  320. Win32ConsoleColorContext_t m_ColorContext;
  321. };
  322. #endif // !_GAMECONSOLE
  323. //-----------------------------------------------------------------------------
  324. // Default logging response policy used when one is not specified.
  325. //-----------------------------------------------------------------------------
  326. class CDefaultLoggingResponsePolicy : public ILoggingResponsePolicy
  327. {
  328. public:
  329. virtual LoggingResponse_t OnLog( const LoggingContext_t *pContext )
  330. {
  331. if ( pContext->m_Severity == LS_ASSERT && !CommandLine()->FindParm( "-noassert" ) )
  332. {
  333. return LR_DEBUGGER;
  334. }
  335. else if ( pContext->m_Severity == LS_ERROR )
  336. {
  337. return LR_ABORT;
  338. }
  339. else
  340. {
  341. return LR_CONTINUE;
  342. }
  343. }
  344. };
  345. //-----------------------------------------------------------------------------
  346. // A logging response policy which never terminates the process, even on error.
  347. //-----------------------------------------------------------------------------
  348. class CNonFatalLoggingResponsePolicy : public ILoggingResponsePolicy
  349. {
  350. public:
  351. virtual LoggingResponse_t OnLog( const LoggingContext_t *pContext )
  352. {
  353. if ( ( pContext->m_Severity == LS_ASSERT && !CommandLine()->FindParm( "-noassert" ) ) || pContext->m_Severity == LS_ERROR )
  354. {
  355. return LR_DEBUGGER;
  356. }
  357. else
  358. {
  359. return LR_CONTINUE;
  360. }
  361. }
  362. };
  363. //////////////////////////////////////////////////////////////////////////
  364. // Central Logging System
  365. //////////////////////////////////////////////////////////////////////////
  366. //-----------------------------------------------------------------------------
  367. // The central logging system.
  368. //
  369. // Multiple instances can exist, though all exported tier0 functionality
  370. // specifically works with a single global instance
  371. // (via GetGlobalLoggingSystem()).
  372. //-----------------------------------------------------------------------------
  373. class CLoggingSystem
  374. {
  375. public:
  376. struct LoggingChannel_t;
  377. CLoggingSystem();
  378. ~CLoggingSystem();
  379. //-----------------------------------------------------------------------------
  380. // Register a logging channel with the logging system.
  381. // The same channel can be registered multiple times, but the parameters
  382. // in each call to RegisterLoggingChannel must either match across all calls
  383. // or be set to defaults on any given call
  384. //
  385. // This function is not thread-safe and should generally only be called
  386. // by a single thread. Using the logging channel definition macros ensures
  387. // that this is called on the static initialization thread.
  388. //-----------------------------------------------------------------------------
  389. LoggingChannelID_t RegisterLoggingChannel( const char *pChannelName, RegisterTagsFunc registerTagsFunc, int flags = 0, LoggingSeverity_t minimumSeverity = LS_MESSAGE, Color spewColor = UNSPECIFIED_LOGGING_COLOR );
  390. //-----------------------------------------------------------------------------
  391. // Gets a channel ID from a string name.
  392. // Performs a simple linear search; cache the value whenever possible
  393. // or re-register the logging channel to get a global ID.
  394. //-----------------------------------------------------------------------------
  395. LoggingChannelID_t FindChannel( const char *pChannelName ) const;
  396. int GetChannelCount() const { return m_nChannelCount; }
  397. //-----------------------------------------------------------------------------
  398. // Gets a pointer to the logging channel description.
  399. //-----------------------------------------------------------------------------
  400. LoggingChannel_t *GetChannel( LoggingChannelID_t channelID );
  401. const LoggingChannel_t *GetChannel( LoggingChannelID_t channelID ) const;
  402. //-----------------------------------------------------------------------------
  403. // Returns true if the given channel has the specified tag.
  404. //-----------------------------------------------------------------------------
  405. bool HasTag( LoggingChannelID_t channelID, const char *pTag ) const { return GetChannel( channelID )->HasTag( pTag ); }
  406. //-----------------------------------------------------------------------------
  407. // Returns true if the given channel has been initialized.
  408. // The main purpose is catching m_nChannelCount being zero because no channels have been registered.
  409. //-----------------------------------------------------------------------------
  410. bool IsValidChannelID( LoggingChannelID_t channelID ) const { return ( channelID >= 0 ) && ( channelID < m_nChannelCount ); }
  411. //-----------------------------------------------------------------------------
  412. // Returns true if the given channel will spew at the given severity level.
  413. //-----------------------------------------------------------------------------
  414. bool IsChannelEnabled( LoggingChannelID_t channelID, LoggingSeverity_t severity ) const { return IsValidChannelID( channelID ) && GetChannel( channelID )->IsEnabled( severity ); }
  415. //-----------------------------------------------------------------------------
  416. // Functions to set the spew level of a channel either directly by ID or
  417. // string name, or for all channels with a given tag.
  418. //
  419. // These functions are not technically thread-safe but calling them across
  420. // multiple threads should cause no significant problems
  421. // (the underlying data types being changed are 32-bit/atomic).
  422. //-----------------------------------------------------------------------------
  423. void SetChannelSpewLevel( LoggingChannelID_t channelID, LoggingSeverity_t minimumSeverity );
  424. void SetChannelSpewLevelByName( const char *pName, LoggingSeverity_t minimumSeverity );
  425. void SetChannelSpewLevelByTag( const char *pTag, LoggingSeverity_t minimumSeverity );
  426. //-----------------------------------------------------------------------------
  427. // Gets or sets the color of a logging channel.
  428. // (The functions are not thread-safe, but the consequences are not
  429. // significant.)
  430. //-----------------------------------------------------------------------------
  431. Color GetChannelColor( LoggingChannelID_t channelID ) const { return GetChannel( channelID )->m_SpewColor; }
  432. void SetChannelColor( LoggingChannelID_t channelID, Color color ) { GetChannel( channelID )->m_SpewColor = color; }
  433. //-----------------------------------------------------------------------------
  434. // Gets or sets the flags on a logging channel.
  435. // (The functions are not thread-safe, but the consequences are not
  436. // significant.)
  437. //-----------------------------------------------------------------------------
  438. LoggingChannelFlags_t GetChannelFlags( LoggingChannelID_t channelID ) const { return GetChannel( channelID )->m_Flags; }
  439. void SetChannelFlags( LoggingChannelID_t channelID, LoggingChannelFlags_t flags ) { GetChannel( channelID )->m_Flags = flags; }
  440. //-----------------------------------------------------------------------------
  441. // Adds a string tag to a channel.
  442. // This is not thread-safe and should only be called by a RegisterTagsFunc
  443. // callback passed in to RegisterLoggingChannel (via the
  444. // channel definition macros).
  445. //-----------------------------------------------------------------------------
  446. void AddTagToCurrentChannel( const char *pTagName );
  447. //-----------------------------------------------------------------------------
  448. // Functions to save/restore the current logging state.
  449. // Set bThreadLocal to true on a matching Push/Pop call if the intent
  450. // is to override the logging listeners on the current thread only.
  451. //
  452. // Pushing the current logging state onto the state stack results
  453. // in the current state being cleared by default (no listeners, default logging response policy).
  454. // Set bClearState to false to copy the existing listener pointers to the new state.
  455. //
  456. // These functions which mutate logging state ARE thread-safe and are
  457. // guarded by m_StateMutex.
  458. //-----------------------------------------------------------------------------
  459. void PushLoggingState( bool bThreadLocal = false, bool bClearState = true );
  460. void PopLoggingState( bool bThreadLocal = false );
  461. //-----------------------------------------------------------------------------
  462. // Registers a logging listener (a class which handles logged messages).
  463. //-----------------------------------------------------------------------------
  464. void RegisterLoggingListener( ILoggingListener *pListener );
  465. //-----------------------------------------------------------------------------
  466. // Removes a logging listener from the registered list
  467. //-----------------------------------------------------------------------------
  468. void UnregisterLoggingListener( ILoggingListener *pListener );
  469. //-----------------------------------------------------------------------------
  470. // Returns whether the specified logging listener is registered.
  471. //-----------------------------------------------------------------------------
  472. bool IsListenerRegistered( ILoggingListener *pListener );
  473. //-----------------------------------------------------------------------------
  474. // Clears out all of the current logging state (removes all listeners,
  475. // sets the response policy to the default).
  476. //-----------------------------------------------------------------------------
  477. void ResetCurrentLoggingState();
  478. //-----------------------------------------------------------------------------
  479. // Sets a policy class to decide what should happen when messages of a
  480. // particular severity are logged
  481. // (e.g. exit on error, break into debugger).
  482. // If pLoggingResponse is NULL, uses the default response policy class.
  483. //-----------------------------------------------------------------------------
  484. void SetLoggingResponsePolicy( ILoggingResponsePolicy *pLoggingResponse );
  485. //-----------------------------------------------------------------------------
  486. // Logs a message to the specified channel using a given severity and
  487. // spew color. Passing in UNSPECIFIED_LOGGING_COLOR for 'color' allows
  488. // the logging listeners to provide a default.
  489. // NOTE: test 'IsChannelEnabled(channelID,severity)' before calling this!
  490. //-----------------------------------------------------------------------------
  491. LoggingResponse_t LogDirect( LoggingChannelID_t channelID, LoggingSeverity_t severity, Color color, const tchar *pMessage );
  492. // Internal data to represent a logging tag
  493. struct LoggingTag_t
  494. {
  495. const char *m_pTagName;
  496. LoggingTag_t *m_pNextTag;
  497. };
  498. // Internal data to represent a logging channel.
  499. struct LoggingChannel_t
  500. {
  501. bool HasTag( const char *pTag ) const
  502. {
  503. LoggingTag_t *pCurrentTag = m_pFirstTag;
  504. while( pCurrentTag != NULL )
  505. {
  506. if ( stricmp( pCurrentTag->m_pTagName, pTag ) == 0 )
  507. {
  508. return true;
  509. }
  510. pCurrentTag = pCurrentTag->m_pNextTag;
  511. }
  512. return false;
  513. }
  514. bool IsEnabled( LoggingSeverity_t severity ) const { return severity >= m_MinimumSeverity; }
  515. void SetSpewLevel( LoggingSeverity_t severity ) { m_MinimumSeverity = severity; }
  516. LoggingChannelID_t m_ID;
  517. LoggingChannelFlags_t m_Flags; // an OR'd combination of LoggingChannelFlags_t
  518. LoggingSeverity_t m_MinimumSeverity; // The minimum severity level required to activate this channel.
  519. Color m_SpewColor;
  520. char m_Name[MAX_LOGGING_IDENTIFIER_LENGTH];
  521. LoggingTag_t *m_pFirstTag;
  522. };
  523. private:
  524. // Represents the current state of the logger (registered listeners, response policy class, etc.) and can
  525. // vary from thread-to-thread. It can also be pushed/popped to save/restore listener/response state.
  526. struct LoggingState_t
  527. {
  528. // Index of the previous entry on the listener set stack.
  529. int m_nPreviousStackEntry;
  530. // Number of active listeners in this set. Cannot exceed MAX_LOGGING_LISTENER_COUNT.
  531. // If set to -1, implies that this state structure is not in use.
  532. int m_nListenerCount;
  533. // Array of registered logging listener objects.
  534. ILoggingListener *m_RegisteredListeners[MAX_LOGGING_LISTENER_COUNT];
  535. // Specific policy class to determine behavior of logging system under specific message types.
  536. ILoggingResponsePolicy *m_pLoggingResponse;
  537. };
  538. // These state functions to assume the caller has already grabbed the mutex.
  539. LoggingState_t *GetCurrentState();
  540. const LoggingState_t *GetCurrentState() const;
  541. int FindUnusedStateIndex();
  542. LoggingTag_t *AllocTag( const char *pTagName );
  543. int m_nChannelCount;
  544. LoggingChannel_t m_RegisteredChannels[MAX_LOGGING_CHANNEL_COUNT];
  545. int m_nChannelTagCount;
  546. LoggingTag_t m_ChannelTags[MAX_LOGGING_TAG_COUNT];
  547. // Index to first free character in name pool.
  548. int m_nTagNamePoolIndex;
  549. // Pool of character data used for tag names.
  550. char m_TagNamePool[MAX_LOGGING_TAG_CHARACTER_COUNT];
  551. // Protects all data in this class except the registered channels
  552. // (which are supposed to be registered using the macros at static/global init time).
  553. // It is assumed that this mutex is reentrant safe on all platforms.
  554. CThreadFastMutex *m_pStateMutex;
  555. // The index of the current "global" state of the logging system. By default, all threads use this state
  556. // for logging unless a given thread has pushed the logging state with bThreadLocal == true.
  557. // If a thread-local state has been pushed, g_nThreadLocalStateIndex (a global thread-local integer) will be non-zero.
  558. // By default, g_nThreadLocalStateIndex is 0 for all threads.
  559. int m_nGlobalStateIndex;
  560. // A pool of logging states used to store a stack (potentially per-thread).
  561. static const int MAX_LOGGING_STATE_COUNT = 16;
  562. LoggingState_t m_LoggingStates[MAX_LOGGING_STATE_COUNT];
  563. // Default policy class which determines behavior.
  564. CDefaultLoggingResponsePolicy m_DefaultLoggingResponse;
  565. // Default spew function.
  566. CSimpleLoggingListener m_DefaultLoggingListener;
  567. };
  568. //////////////////////////////////////////////////////////////////////////
  569. // Logging Macros
  570. //////////////////////////////////////////////////////////////////////////
  571. // This macro will resolve to the most appropriate overload of LoggingSystem_Log() depending on the number of parameters passed in.
  572. #ifdef DBGFLAG_STRINGS_STRIP
  573. #define InternalMsg( Channel, Severity, /* [Color], Message, */ ... ) do { if ( Severity == LS_ERROR && LoggingSystem_IsChannelEnabled( Channel, Severity ) ) LoggingSystem_Log( Channel, Severity, /* [Color], Message, */ ##__VA_ARGS__ ); } while( 0 )
  574. #else
  575. #define InternalMsg( Channel, Severity, /* [Color], Message, */ ... ) do { if ( LoggingSystem_IsChannelEnabled( Channel, Severity ) ) LoggingSystem_Log( Channel, Severity, /* [Color], Message, */ ##__VA_ARGS__ ); } while( 0 )
  576. #endif
  577. //-----------------------------------------------------------------------------
  578. // New macros, use these!
  579. //
  580. // The macros take an optional Color parameter followed by the message
  581. // and the message formatting.
  582. // We rely on the variadic macro (__VA_ARGS__) operator to paste in the
  583. // extra parameters and resolve to the appropriate overload.
  584. //-----------------------------------------------------------------------------
  585. #define Log_Msg( Channel, /* [Color], Message, */ ... ) InternalMsg( Channel, LS_MESSAGE, /* [Color], Message, */ ##__VA_ARGS__ )
  586. #define Log_Warning( Channel, /* [Color], Message, */ ... ) InternalMsg( Channel, LS_WARNING, /* [Color], Message, */ ##__VA_ARGS__ )
  587. #define Log_Error( Channel, /* [Color], Message, */ ... ) InternalMsg( Channel, LS_ERROR, /* [Color], Message, */ ##__VA_ARGS__ )
  588. #ifdef DBGFLAG_STRINGS_STRIP
  589. #define Log_Assert( ... ) LR_CONTINUE
  590. #else
  591. #define Log_Assert( Message, ... ) LoggingSystem_LogAssert( Message, ##__VA_ARGS__ )
  592. #endif
  593. #define DECLARE_LOGGING_CHANNEL( Channel ) extern LoggingChannelID_t Channel
  594. #define DEFINE_LOGGING_CHANNEL_NO_TAGS( Channel, ChannelName, /* [Flags], [Severity], [Color] */ ... ) \
  595. LoggingChannelID_t Channel = LoggingSystem_RegisterLoggingChannel( ChannelName, NULL, ##__VA_ARGS__ )
  596. #define BEGIN_DEFINE_LOGGING_CHANNEL( Channel, ChannelName, /* [Flags], [Severity], [Color] */ ... ) \
  597. static void Register_##Channel##_Tags(); \
  598. LoggingChannelID_t Channel = LoggingSystem_RegisterLoggingChannel( ChannelName, Register_##Channel##_Tags, ##__VA_ARGS__ ); \
  599. void Register_##Channel##_Tags() \
  600. {
  601. #define ADD_LOGGING_CHANNEL_TAG( Tag ) LoggingSystem_AddTagToCurrentChannel( Tag )
  602. #define END_DEFINE_LOGGING_CHANNEL() \
  603. }
  604. //////////////////////////////////////////////////////////////////////////
  605. // DLL Exports
  606. //////////////////////////////////////////////////////////////////////////
  607. // For documentation on these functions, please look at the corresponding function
  608. // in CLoggingSystem (unless otherwise specified).
  609. PLATFORM_INTERFACE LoggingChannelID_t LoggingSystem_RegisterLoggingChannel( const char *pName, RegisterTagsFunc registerTagsFunc, int flags = 0, LoggingSeverity_t severity = LS_MESSAGE, Color color = UNSPECIFIED_LOGGING_COLOR );
  610. PLATFORM_INTERFACE void LoggingSystem_RegisterLoggingListener( ILoggingListener *pListener );
  611. PLATFORM_INTERFACE void LoggingSystem_UnregisterLoggingListener( ILoggingListener *pListener );
  612. PLATFORM_INTERFACE void LoggingSystem_ResetCurrentLoggingState();
  613. PLATFORM_INTERFACE void LoggingSystem_SetLoggingResponsePolicy( ILoggingResponsePolicy *pResponsePolicy );
  614. // NOTE: PushLoggingState() saves the current logging state on a stack and results in a new clear state
  615. // (no listeners, default logging response policy).
  616. PLATFORM_INTERFACE void LoggingSystem_PushLoggingState( bool bThreadLocal = false, bool bClearState = true );
  617. PLATFORM_INTERFACE void LoggingSystem_PopLoggingState( bool bThreadLocal = false );
  618. PLATFORM_INTERFACE void LoggingSystem_AddTagToCurrentChannel( const char *pTagName );
  619. // Returns INVALID_LOGGING_CHANNEL_ID if not found
  620. PLATFORM_INTERFACE LoggingChannelID_t LoggingSystem_FindChannel( const char *pChannelName );
  621. PLATFORM_INTERFACE int LoggingSystem_GetChannelCount();
  622. PLATFORM_INTERFACE LoggingChannelID_t LoggingSystem_GetFirstChannelID();
  623. // Returns INVALID_LOGGING_CHANNEL_ID when there are no channels remaining.
  624. PLATFORM_INTERFACE LoggingChannelID_t LoggingSystem_GetNextChannelID( LoggingChannelID_t channelID );
  625. PLATFORM_INTERFACE const CLoggingSystem::LoggingChannel_t *LoggingSystem_GetChannel( LoggingChannelID_t channelID );
  626. PLATFORM_INTERFACE bool LoggingSystem_HasTag( LoggingChannelID_t channelID, const char *pTag );
  627. PLATFORM_INTERFACE bool LoggingSystem_IsChannelEnabled( LoggingChannelID_t channelID, LoggingSeverity_t severity );
  628. PLATFORM_INTERFACE void LoggingSystem_SetChannelSpewLevel( LoggingChannelID_t channelID, LoggingSeverity_t minimumSeverity );
  629. PLATFORM_INTERFACE void LoggingSystem_SetChannelSpewLevelByName( const char *pName, LoggingSeverity_t minimumSeverity );
  630. PLATFORM_INTERFACE void LoggingSystem_SetChannelSpewLevelByTag( const char *pTag, LoggingSeverity_t minimumSeverity );
  631. // Color is represented as an int32 due to C-linkage restrictions
  632. PLATFORM_INTERFACE int32 LoggingSystem_GetChannelColor( LoggingChannelID_t channelID );
  633. PLATFORM_INTERFACE void LoggingSystem_SetChannelColor( LoggingChannelID_t channelID, int color );
  634. PLATFORM_INTERFACE LoggingChannelFlags_t LoggingSystem_GetChannelFlags( LoggingChannelID_t channelID );
  635. PLATFORM_INTERFACE void LoggingSystem_SetChannelFlags( LoggingChannelID_t channelID, LoggingChannelFlags_t flags );
  636. //-----------------------------------------------------------------------------
  637. // Logs a variable-argument to a given channel with the specified severity.
  638. // NOTE: if adding overloads to this function, remember that the Log_***
  639. // macros simply pass their variadic parameters through to LoggingSystem_Log().
  640. // Therefore, you need to ensure that the parameters are in the same general
  641. // order and that there are no ambiguities with the overload.
  642. //-----------------------------------------------------------------------------
  643. PLATFORM_INTERFACE LoggingResponse_t LoggingSystem_Log( LoggingChannelID_t channelID, LoggingSeverity_t severity, const char *pMessageFormat, ... ) FMTFUNCTION( 3, 4 );
  644. PLATFORM_OVERLOAD LoggingResponse_t LoggingSystem_Log( LoggingChannelID_t channelID, LoggingSeverity_t severity, Color spewColor, const char *pMessageFormat, ... ) FMTFUNCTION( 4, 5 );
  645. PLATFORM_INTERFACE LoggingResponse_t LoggingSystem_LogDirect( LoggingChannelID_t channelID, LoggingSeverity_t severity, Color spewColor, const char *pMessage );
  646. PLATFORM_INTERFACE LoggingResponse_t LoggingSystem_LogAssert( const char *pMessageFormat, ... ) FMTFUNCTION( 1, 2 );
  647. #endif // LOGGING_H