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.
767 lines
34 KiB
767 lines
34 KiB
//============ Copyright (c) Valve Corporation, All rights reserved. ============ |
|
// |
|
// Logging system declarations. |
|
// |
|
// The logging system is a channel-based output mechanism which allows |
|
// subsystems to route their text/diagnostic output to various listeners |
|
// |
|
//=============================================================================== |
|
|
|
#ifndef LOGGING_H |
|
#define LOGGING_H |
|
|
|
#if defined( COMPILER_MSVC ) |
|
#pragma once |
|
#endif |
|
|
|
#include "color.h" |
|
#include "icommandline.h" |
|
#include <stdio.h> |
|
|
|
// For XBX_** functions |
|
#if defined( _X360 ) |
|
#include "xbox/xbox_console.h" |
|
#endif |
|
|
|
// Used by CColorizedLoggingListener |
|
#if defined( _WIN32 ) || (defined(POSIX) && !defined(_GAMECONSOLE)) |
|
#include "tier0/win32consoleio.h" |
|
#endif |
|
|
|
/* |
|
---- Logging System ---- |
|
|
|
The logging system is a channel-based mechanism for all code (engine, |
|
mod, tool) across all platforms to output information, warnings, |
|
errors, etc. |
|
|
|
This system supersedes the existing Msg(), Warning(), Error(), DevMsg(), ConMsg() etc. functions. |
|
There are channels defined in the new system through which all old messages are routed; |
|
see LOG_GENERAL, LOG_CONSOLE, LOG_DEVELOPER, etc. |
|
|
|
To use the system, simply call one of the predefined macros: |
|
|
|
Log_Msg( ChannelID, [Color], Message, ... ) |
|
Log_Warning( ChannelID, [Color], Message, ... ) |
|
Log_Error( ChannelID, [Color], Message, ... ) |
|
|
|
A ChannelID is typically created by defining a logging channel with the |
|
log channel macros: |
|
|
|
DEFINE_LOGGING_CHANNEL_NO_TAGS( LOG_ChannelName, "ChannelName", [Flags], [MinimumSeverity], [Color] ); |
|
|
|
or |
|
|
|
BEGIN_DEFINE_LOGGING_CHANNEL( LOG_ChannelName, "ChannelName", [Flags], [MinimumSeverity], [Color] ); |
|
ADD_LOGGING_CHANNEL_TAG( "Tag1" ); |
|
ADD_LOGGING_CHANNEL_TAG( "Tag2" ); |
|
END_DEFINE_LOGGING_CHANNEL(); |
|
|
|
These macros create a global channel ID variable with the name specified |
|
by the first parameter (in this example, LOG_ChannelName). This channel ID |
|
can be used by various LoggingSystem_** functions to manipulate the channel settings. |
|
|
|
The optional [Flags] parameter is an OR'd together set of LoggingChannelFlags_t |
|
values (default: 0). |
|
|
|
The optional [MinimumSeverity] parameter is the lowest threshold |
|
above which messages will be processed (inclusive). The default is LS_MESSAGE, |
|
which results in all messages, warnings, and errors being logged. |
|
Variadic parameters to the Log_** functions will be ignored if a channel |
|
is not enabled for a given severity (for performance reasons). |
|
|
|
Logging channels can have their minimum severity modified by name, ID, or tag. |
|
|
|
Logging channels are not hierarchical since there are situations in which |
|
a channel needs to belong to multiple hierarchies. Use tags to create |
|
categories or shallow hierarchies. |
|
|
|
@TODO (Feature wishlist): |
|
1) Callstack logging support |
|
2) Registering dynamic channels and unregistering channels at runtime |
|
3) Sentient robot to clean up the thousands of places using the old/legacy logging system. |
|
*/ |
|
|
|
////////////////////////////////////////////////////////////////////////// |
|
// Constants, Types, Forward Declares |
|
////////////////////////////////////////////////////////////////////////// |
|
|
|
class CLoggingSystem; |
|
class CThreadFastMutex; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Maximum length of a sprintf'ed logging message. |
|
//----------------------------------------------------------------------------- |
|
const int MAX_LOGGING_MESSAGE_LENGTH = 2048; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Maximum length of a channel or tag name. |
|
//----------------------------------------------------------------------------- |
|
const int MAX_LOGGING_IDENTIFIER_LENGTH = 32; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Maximum number of logging channels. Increase if needed. |
|
//----------------------------------------------------------------------------- |
|
const int MAX_LOGGING_CHANNEL_COUNT = 256; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Maximum number of logging tags across all channels. Increase if needed. |
|
//----------------------------------------------------------------------------- |
|
const int MAX_LOGGING_TAG_COUNT = 1024; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Maximum number of characters across all logging tags. Increase if needed. |
|
//----------------------------------------------------------------------------- |
|
const int MAX_LOGGING_TAG_CHARACTER_COUNT = 8192; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Maximum number of concurrent logging listeners in a given logging state. |
|
//----------------------------------------------------------------------------- |
|
const int MAX_LOGGING_LISTENER_COUNT = 16; |
|
|
|
//----------------------------------------------------------------------------- |
|
// An invalid color set on a channel to imply that it should use |
|
// a device-dependent default color where applicable. |
|
//----------------------------------------------------------------------------- |
|
const Color UNSPECIFIED_LOGGING_COLOR( 0, 0, 0, 0 ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// An ID returned by the logging system to refer to a logging channel. |
|
//----------------------------------------------------------------------------- |
|
typedef int LoggingChannelID_t; |
|
|
|
//----------------------------------------------------------------------------- |
|
// A sentinel value indicating an invalid logging channel ID. |
|
//----------------------------------------------------------------------------- |
|
const LoggingChannelID_t INVALID_LOGGING_CHANNEL_ID = -1; |
|
|
|
//----------------------------------------------------------------------------- |
|
// The severity of a logging operation. |
|
//----------------------------------------------------------------------------- |
|
enum LoggingSeverity_t |
|
{ |
|
//----------------------------------------------------------------------------- |
|
// An informative logging message. |
|
//----------------------------------------------------------------------------- |
|
LS_MESSAGE = 0, |
|
|
|
//----------------------------------------------------------------------------- |
|
// A warning, typically non-fatal |
|
//----------------------------------------------------------------------------- |
|
LS_WARNING = 1, |
|
|
|
//----------------------------------------------------------------------------- |
|
// A message caused by an Assert**() operation. |
|
//----------------------------------------------------------------------------- |
|
LS_ASSERT = 2, |
|
|
|
//----------------------------------------------------------------------------- |
|
// An error, typically fatal/unrecoverable. |
|
//----------------------------------------------------------------------------- |
|
LS_ERROR = 3, |
|
|
|
//----------------------------------------------------------------------------- |
|
// A placeholder level, higher than any legal value. |
|
// Not a real severity value! |
|
//----------------------------------------------------------------------------- |
|
LS_HIGHEST_SEVERITY = 4, |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Action which should be taken by logging system as a result of |
|
// a given logged message. |
|
// |
|
// The logging system invokes ILoggingResponsePolicy::OnLog() on |
|
// the specified policy object, which returns a LoggingResponse_t. |
|
//----------------------------------------------------------------------------- |
|
enum LoggingResponse_t |
|
{ |
|
LR_CONTINUE, |
|
LR_DEBUGGER, |
|
LR_ABORT, |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Logging channel behavior flags, set on channel creation. |
|
//----------------------------------------------------------------------------- |
|
enum LoggingChannelFlags_t |
|
{ |
|
//----------------------------------------------------------------------------- |
|
// Indicates that the spew is only relevant to interactive consoles. |
|
//----------------------------------------------------------------------------- |
|
LCF_CONSOLE_ONLY = 0x00000001, |
|
|
|
//----------------------------------------------------------------------------- |
|
// Indicates that spew should not be echoed to any output devices. |
|
// A suitable logging listener must be registered which respects this flag |
|
// (e.g. a file logger). |
|
//----------------------------------------------------------------------------- |
|
LCF_DO_NOT_ECHO = 0x00000002, |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// A callback function used to register tags on a logging channel |
|
// during initialization. |
|
//----------------------------------------------------------------------------- |
|
typedef void ( *RegisterTagsFunc )(); |
|
|
|
//----------------------------------------------------------------------------- |
|
// A context structure passed to logging listeners and response policy classes. |
|
//----------------------------------------------------------------------------- |
|
struct LoggingContext_t |
|
{ |
|
// ID of the channel being logged to. |
|
LoggingChannelID_t m_ChannelID; |
|
// Flags associated with the channel. |
|
LoggingChannelFlags_t m_Flags; |
|
// Severity of the logging event. |
|
LoggingSeverity_t m_Severity; |
|
// Color of logging message if one was specified to Log_****() macro. |
|
// If not specified, falls back to channel color. |
|
// If channel color is not specified, this value is UNSPECIFIED_LOGGING_COLOR |
|
// and indicates that a suitable default should be chosen. |
|
Color m_Color; |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Interface for classes to handle logging output. |
|
// |
|
// The Log() function of this class is called synchronously and serially |
|
// by the logging system on all registered instances of ILoggingListener |
|
// in the current "logging state". |
|
// |
|
// Derived classes may do whatever they want with the message (write to disk, |
|
// write to console, send over the network, drop on the floor, etc.). |
|
// |
|
// In general, derived classes should do one, simple thing with the output |
|
// to allow callers to register multiple, orthogonal logging listener classes. |
|
//----------------------------------------------------------------------------- |
|
class ILoggingListener |
|
{ |
|
public: |
|
virtual void Log( const LoggingContext_t *pContext, const tchar *pMessage ) = 0; |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Interface for policy classes which determine how to behave when a |
|
// message is logged. |
|
// |
|
// Can return: |
|
// LR_CONTINUE (continue execution) |
|
// LR_DEBUGGER (break into debugger if one is present, otherwise continue) |
|
// LR_ABORT (terminate process immediately with a failure code of 1) |
|
//----------------------------------------------------------------------------- |
|
class ILoggingResponsePolicy |
|
{ |
|
public: |
|
virtual LoggingResponse_t OnLog( const LoggingContext_t *pContext ) = 0; |
|
}; |
|
|
|
////////////////////////////////////////////////////////////////////////// |
|
// Common Logging Listeners & Logging Response Policies |
|
////////////////////////////////////////////////////////////////////////// |
|
|
|
//----------------------------------------------------------------------------- |
|
// A basic logging listener which prints to stdout and the debug channel. |
|
//----------------------------------------------------------------------------- |
|
class CSimpleLoggingListener : public ILoggingListener |
|
{ |
|
public: |
|
CSimpleLoggingListener( bool bQuietPrintf = false, bool bQuietDebugger = false ) : |
|
m_bQuietPrintf( bQuietPrintf ), |
|
m_bQuietDebugger( bQuietDebugger ) |
|
{ |
|
} |
|
|
|
virtual void Log( const LoggingContext_t *pContext, const tchar *pMessage ) |
|
{ |
|
#ifdef _X360 |
|
if ( !m_bQuietDebugger && XBX_IsConsoleConnected() ) |
|
{ |
|
// send to console |
|
XBX_DebugString( XMAKECOLOR( 0,0,0 ), pMessage ); |
|
} |
|
else |
|
#endif |
|
{ |
|
#if !defined( _CERT ) && !defined( DBGFLAG_STRINGS_STRIP ) |
|
if ( !m_bQuietPrintf ) |
|
{ |
|
_tprintf( _T("%s"), pMessage ); |
|
} |
|
#endif |
|
|
|
#ifdef _WIN32 |
|
if ( !m_bQuietDebugger && Plat_IsInDebugSession() ) |
|
{ |
|
Plat_DebugString( pMessage ); |
|
} |
|
#endif |
|
} |
|
} |
|
|
|
// If set to true, does not print anything to stdout. |
|
bool m_bQuietPrintf; |
|
// If set to true, does not print anything to debugger. |
|
bool m_bQuietDebugger; |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// A basic logging listener for GUI applications |
|
//----------------------------------------------------------------------------- |
|
class CSimpleWindowsLoggingListener : public ILoggingListener |
|
{ |
|
public: |
|
virtual void Log( const LoggingContext_t *pContext, const tchar *pMessage ) |
|
{ |
|
if ( Plat_IsInDebugSession() ) |
|
{ |
|
Plat_DebugString( pMessage ); |
|
} |
|
if ( pContext->m_Severity == LS_ERROR ) |
|
{ |
|
if ( Plat_IsInDebugSession() ) |
|
DebuggerBreak(); |
|
|
|
Plat_MessageBox( "Error", pMessage ); |
|
} |
|
} |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// ** NOTE FOR INTEGRATION ** |
|
// This was copied over from source 2 rather than integrated because |
|
// source 2 has more significantly refactored tier0 logging. |
|
// |
|
// A logging listener with Win32 console API color support which which prints |
|
// to stdout and the debug channel. |
|
//----------------------------------------------------------------------------- |
|
#if !defined(_GAMECONSOLE) |
|
class CColorizedLoggingListener : public CSimpleLoggingListener |
|
{ |
|
public: |
|
CColorizedLoggingListener( bool bQuietPrintf = false, bool bQuietDebugger = false ) : CSimpleLoggingListener( bQuietPrintf, bQuietDebugger ) |
|
{ |
|
InitWin32ConsoleColorContext( &m_ColorContext ); |
|
} |
|
|
|
virtual void Log( const LoggingContext_t *pContext, const tchar *pMessage ) |
|
{ |
|
if ( !m_bQuietPrintf ) |
|
{ |
|
int nPrevColor = -1; |
|
|
|
if ( pContext->m_Color != UNSPECIFIED_LOGGING_COLOR ) |
|
{ |
|
nPrevColor = SetWin32ConsoleColor( &m_ColorContext, |
|
pContext->m_Color.r(), pContext->m_Color.g(), pContext->m_Color.b(), |
|
MAX( MAX( pContext->m_Color.r(), pContext->m_Color.g() ), pContext->m_Color.b() ) > 128 ); |
|
} |
|
|
|
_tprintf( _T("%s"), pMessage ); |
|
|
|
if ( nPrevColor >= 0 ) |
|
{ |
|
RestoreWin32ConsoleColor( &m_ColorContext, nPrevColor ); |
|
} |
|
} |
|
|
|
#ifdef _WIN32 |
|
if ( !m_bQuietDebugger && Plat_IsInDebugSession() ) |
|
{ |
|
Plat_DebugString( pMessage ); |
|
} |
|
#endif |
|
} |
|
|
|
Win32ConsoleColorContext_t m_ColorContext; |
|
}; |
|
#endif // !_GAMECONSOLE |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Default logging response policy used when one is not specified. |
|
//----------------------------------------------------------------------------- |
|
class CDefaultLoggingResponsePolicy : public ILoggingResponsePolicy |
|
{ |
|
public: |
|
virtual LoggingResponse_t OnLog( const LoggingContext_t *pContext ) |
|
{ |
|
if ( pContext->m_Severity == LS_ASSERT && !CommandLine()->FindParm( "-noassert" ) ) |
|
{ |
|
return LR_DEBUGGER; |
|
} |
|
else if ( pContext->m_Severity == LS_ERROR ) |
|
{ |
|
return LR_ABORT; |
|
} |
|
else |
|
{ |
|
return LR_CONTINUE; |
|
} |
|
} |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// A logging response policy which never terminates the process, even on error. |
|
//----------------------------------------------------------------------------- |
|
class CNonFatalLoggingResponsePolicy : public ILoggingResponsePolicy |
|
{ |
|
public: |
|
virtual LoggingResponse_t OnLog( const LoggingContext_t *pContext ) |
|
{ |
|
if ( ( pContext->m_Severity == LS_ASSERT && !CommandLine()->FindParm( "-noassert" ) ) || pContext->m_Severity == LS_ERROR ) |
|
{ |
|
return LR_DEBUGGER; |
|
} |
|
else |
|
{ |
|
return LR_CONTINUE; |
|
} |
|
} |
|
}; |
|
|
|
////////////////////////////////////////////////////////////////////////// |
|
// Central Logging System |
|
////////////////////////////////////////////////////////////////////////// |
|
|
|
//----------------------------------------------------------------------------- |
|
// The central logging system. |
|
// |
|
// Multiple instances can exist, though all exported tier0 functionality |
|
// specifically works with a single global instance |
|
// (via GetGlobalLoggingSystem()). |
|
//----------------------------------------------------------------------------- |
|
class CLoggingSystem |
|
{ |
|
public: |
|
struct LoggingChannel_t; |
|
|
|
CLoggingSystem(); |
|
~CLoggingSystem(); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Register a logging channel with the logging system. |
|
// The same channel can be registered multiple times, but the parameters |
|
// in each call to RegisterLoggingChannel must either match across all calls |
|
// or be set to defaults on any given call |
|
// |
|
// This function is not thread-safe and should generally only be called |
|
// by a single thread. Using the logging channel definition macros ensures |
|
// that this is called on the static initialization thread. |
|
//----------------------------------------------------------------------------- |
|
LoggingChannelID_t RegisterLoggingChannel( const char *pChannelName, RegisterTagsFunc registerTagsFunc, int flags = 0, LoggingSeverity_t minimumSeverity = LS_MESSAGE, Color spewColor = UNSPECIFIED_LOGGING_COLOR ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Gets a channel ID from a string name. |
|
// Performs a simple linear search; cache the value whenever possible |
|
// or re-register the logging channel to get a global ID. |
|
//----------------------------------------------------------------------------- |
|
LoggingChannelID_t FindChannel( const char *pChannelName ) const; |
|
|
|
int GetChannelCount() const { return m_nChannelCount; } |
|
|
|
//----------------------------------------------------------------------------- |
|
// Gets a pointer to the logging channel description. |
|
//----------------------------------------------------------------------------- |
|
LoggingChannel_t *GetChannel( LoggingChannelID_t channelID ); |
|
const LoggingChannel_t *GetChannel( LoggingChannelID_t channelID ) const; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Returns true if the given channel has the specified tag. |
|
//----------------------------------------------------------------------------- |
|
bool HasTag( LoggingChannelID_t channelID, const char *pTag ) const { return GetChannel( channelID )->HasTag( pTag ); } |
|
|
|
//----------------------------------------------------------------------------- |
|
// Returns true if the given channel has been initialized. |
|
// The main purpose is catching m_nChannelCount being zero because no channels have been registered. |
|
//----------------------------------------------------------------------------- |
|
bool IsValidChannelID( LoggingChannelID_t channelID ) const { return ( channelID >= 0 ) && ( channelID < m_nChannelCount ); } |
|
|
|
//----------------------------------------------------------------------------- |
|
// Returns true if the given channel will spew at the given severity level. |
|
//----------------------------------------------------------------------------- |
|
bool IsChannelEnabled( LoggingChannelID_t channelID, LoggingSeverity_t severity ) const { return IsValidChannelID( channelID ) && GetChannel( channelID )->IsEnabled( severity ); } |
|
|
|
//----------------------------------------------------------------------------- |
|
// Functions to set the spew level of a channel either directly by ID or |
|
// string name, or for all channels with a given tag. |
|
// |
|
// These functions are not technically thread-safe but calling them across |
|
// multiple threads should cause no significant problems |
|
// (the underlying data types being changed are 32-bit/atomic). |
|
//----------------------------------------------------------------------------- |
|
void SetChannelSpewLevel( LoggingChannelID_t channelID, LoggingSeverity_t minimumSeverity ); |
|
void SetChannelSpewLevelByName( const char *pName, LoggingSeverity_t minimumSeverity ); |
|
void SetChannelSpewLevelByTag( const char *pTag, LoggingSeverity_t minimumSeverity ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Gets or sets the color of a logging channel. |
|
// (The functions are not thread-safe, but the consequences are not |
|
// significant.) |
|
//----------------------------------------------------------------------------- |
|
Color GetChannelColor( LoggingChannelID_t channelID ) const { return GetChannel( channelID )->m_SpewColor; } |
|
void SetChannelColor( LoggingChannelID_t channelID, Color color ) { GetChannel( channelID )->m_SpewColor = color; } |
|
|
|
//----------------------------------------------------------------------------- |
|
// Gets or sets the flags on a logging channel. |
|
// (The functions are not thread-safe, but the consequences are not |
|
// significant.) |
|
//----------------------------------------------------------------------------- |
|
LoggingChannelFlags_t GetChannelFlags( LoggingChannelID_t channelID ) const { return GetChannel( channelID )->m_Flags; } |
|
void SetChannelFlags( LoggingChannelID_t channelID, LoggingChannelFlags_t flags ) { GetChannel( channelID )->m_Flags = flags; } |
|
|
|
//----------------------------------------------------------------------------- |
|
// Adds a string tag to a channel. |
|
// This is not thread-safe and should only be called by a RegisterTagsFunc |
|
// callback passed in to RegisterLoggingChannel (via the |
|
// channel definition macros). |
|
//----------------------------------------------------------------------------- |
|
void AddTagToCurrentChannel( const char *pTagName ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Functions to save/restore the current logging state. |
|
// Set bThreadLocal to true on a matching Push/Pop call if the intent |
|
// is to override the logging listeners on the current thread only. |
|
// |
|
// Pushing the current logging state onto the state stack results |
|
// in the current state being cleared by default (no listeners, default logging response policy). |
|
// Set bClearState to false to copy the existing listener pointers to the new state. |
|
// |
|
// These functions which mutate logging state ARE thread-safe and are |
|
// guarded by m_StateMutex. |
|
//----------------------------------------------------------------------------- |
|
void PushLoggingState( bool bThreadLocal = false, bool bClearState = true ); |
|
void PopLoggingState( bool bThreadLocal = false ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Registers a logging listener (a class which handles logged messages). |
|
//----------------------------------------------------------------------------- |
|
void RegisterLoggingListener( ILoggingListener *pListener ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Removes a logging listener from the registered list |
|
//----------------------------------------------------------------------------- |
|
void UnregisterLoggingListener( ILoggingListener *pListener ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Returns whether the specified logging listener is registered. |
|
//----------------------------------------------------------------------------- |
|
bool IsListenerRegistered( ILoggingListener *pListener ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Clears out all of the current logging state (removes all listeners, |
|
// sets the response policy to the default). |
|
//----------------------------------------------------------------------------- |
|
void ResetCurrentLoggingState(); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Sets a policy class to decide what should happen when messages of a |
|
// particular severity are logged |
|
// (e.g. exit on error, break into debugger). |
|
// If pLoggingResponse is NULL, uses the default response policy class. |
|
//----------------------------------------------------------------------------- |
|
void SetLoggingResponsePolicy( ILoggingResponsePolicy *pLoggingResponse ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Logs a message to the specified channel using a given severity and |
|
// spew color. Passing in UNSPECIFIED_LOGGING_COLOR for 'color' allows |
|
// the logging listeners to provide a default. |
|
// NOTE: test 'IsChannelEnabled(channelID,severity)' before calling this! |
|
//----------------------------------------------------------------------------- |
|
LoggingResponse_t LogDirect( LoggingChannelID_t channelID, LoggingSeverity_t severity, Color color, const tchar *pMessage ); |
|
|
|
// Internal data to represent a logging tag |
|
struct LoggingTag_t |
|
{ |
|
const char *m_pTagName; |
|
LoggingTag_t *m_pNextTag; |
|
}; |
|
|
|
// Internal data to represent a logging channel. |
|
struct LoggingChannel_t |
|
{ |
|
bool HasTag( const char *pTag ) const |
|
{ |
|
LoggingTag_t *pCurrentTag = m_pFirstTag; |
|
while( pCurrentTag != NULL ) |
|
{ |
|
if ( stricmp( pCurrentTag->m_pTagName, pTag ) == 0 ) |
|
{ |
|
return true; |
|
} |
|
pCurrentTag = pCurrentTag->m_pNextTag; |
|
} |
|
return false; |
|
} |
|
bool IsEnabled( LoggingSeverity_t severity ) const { return severity >= m_MinimumSeverity; } |
|
void SetSpewLevel( LoggingSeverity_t severity ) { m_MinimumSeverity = severity; } |
|
|
|
LoggingChannelID_t m_ID; |
|
LoggingChannelFlags_t m_Flags; // an OR'd combination of LoggingChannelFlags_t |
|
LoggingSeverity_t m_MinimumSeverity; // The minimum severity level required to activate this channel. |
|
Color m_SpewColor; |
|
char m_Name[MAX_LOGGING_IDENTIFIER_LENGTH]; |
|
LoggingTag_t *m_pFirstTag; |
|
}; |
|
|
|
private: |
|
// Represents the current state of the logger (registered listeners, response policy class, etc.) and can |
|
// vary from thread-to-thread. It can also be pushed/popped to save/restore listener/response state. |
|
struct LoggingState_t |
|
{ |
|
// Index of the previous entry on the listener set stack. |
|
int m_nPreviousStackEntry; |
|
|
|
// Number of active listeners in this set. Cannot exceed MAX_LOGGING_LISTENER_COUNT. |
|
// If set to -1, implies that this state structure is not in use. |
|
int m_nListenerCount; |
|
// Array of registered logging listener objects. |
|
ILoggingListener *m_RegisteredListeners[MAX_LOGGING_LISTENER_COUNT]; |
|
|
|
// Specific policy class to determine behavior of logging system under specific message types. |
|
ILoggingResponsePolicy *m_pLoggingResponse; |
|
}; |
|
|
|
// These state functions to assume the caller has already grabbed the mutex. |
|
LoggingState_t *GetCurrentState(); |
|
const LoggingState_t *GetCurrentState() const; |
|
|
|
int FindUnusedStateIndex(); |
|
LoggingTag_t *AllocTag( const char *pTagName ); |
|
|
|
int m_nChannelCount; |
|
LoggingChannel_t m_RegisteredChannels[MAX_LOGGING_CHANNEL_COUNT]; |
|
|
|
int m_nChannelTagCount; |
|
LoggingTag_t m_ChannelTags[MAX_LOGGING_TAG_COUNT]; |
|
|
|
// Index to first free character in name pool. |
|
int m_nTagNamePoolIndex; |
|
// Pool of character data used for tag names. |
|
char m_TagNamePool[MAX_LOGGING_TAG_CHARACTER_COUNT]; |
|
|
|
// Protects all data in this class except the registered channels |
|
// (which are supposed to be registered using the macros at static/global init time). |
|
// It is assumed that this mutex is reentrant safe on all platforms. |
|
CThreadFastMutex *m_pStateMutex; |
|
|
|
// The index of the current "global" state of the logging system. By default, all threads use this state |
|
// for logging unless a given thread has pushed the logging state with bThreadLocal == true. |
|
// If a thread-local state has been pushed, g_nThreadLocalStateIndex (a global thread-local integer) will be non-zero. |
|
// By default, g_nThreadLocalStateIndex is 0 for all threads. |
|
int m_nGlobalStateIndex; |
|
|
|
// A pool of logging states used to store a stack (potentially per-thread). |
|
static const int MAX_LOGGING_STATE_COUNT = 16; |
|
LoggingState_t m_LoggingStates[MAX_LOGGING_STATE_COUNT]; |
|
|
|
// Default policy class which determines behavior. |
|
CDefaultLoggingResponsePolicy m_DefaultLoggingResponse; |
|
|
|
// Default spew function. |
|
CSimpleLoggingListener m_DefaultLoggingListener; |
|
|
|
}; |
|
|
|
////////////////////////////////////////////////////////////////////////// |
|
// Logging Macros |
|
////////////////////////////////////////////////////////////////////////// |
|
|
|
// This macro will resolve to the most appropriate overload of LoggingSystem_Log() depending on the number of parameters passed in. |
|
#ifdef DBGFLAG_STRINGS_STRIP |
|
#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 ) |
|
#else |
|
#define InternalMsg( Channel, Severity, /* [Color], Message, */ ... ) do { if ( LoggingSystem_IsChannelEnabled( Channel, Severity ) ) LoggingSystem_Log( Channel, Severity, /* [Color], Message, */ ##__VA_ARGS__ ); } while( 0 ) |
|
#endif |
|
|
|
//----------------------------------------------------------------------------- |
|
// New macros, use these! |
|
// |
|
// The macros take an optional Color parameter followed by the message |
|
// and the message formatting. |
|
// We rely on the variadic macro (__VA_ARGS__) operator to paste in the |
|
// extra parameters and resolve to the appropriate overload. |
|
//----------------------------------------------------------------------------- |
|
#define Log_Msg( Channel, /* [Color], Message, */ ... ) InternalMsg( Channel, LS_MESSAGE, /* [Color], Message, */ ##__VA_ARGS__ ) |
|
#define Log_Warning( Channel, /* [Color], Message, */ ... ) InternalMsg( Channel, LS_WARNING, /* [Color], Message, */ ##__VA_ARGS__ ) |
|
#define Log_Error( Channel, /* [Color], Message, */ ... ) InternalMsg( Channel, LS_ERROR, /* [Color], Message, */ ##__VA_ARGS__ ) |
|
#ifdef DBGFLAG_STRINGS_STRIP |
|
#define Log_Assert( ... ) LR_CONTINUE |
|
#else |
|
#define Log_Assert( Message, ... ) LoggingSystem_LogAssert( Message, ##__VA_ARGS__ ) |
|
#endif |
|
|
|
|
|
#define DECLARE_LOGGING_CHANNEL( Channel ) extern LoggingChannelID_t Channel |
|
|
|
#define DEFINE_LOGGING_CHANNEL_NO_TAGS( Channel, ChannelName, /* [Flags], [Severity], [Color] */ ... ) \ |
|
LoggingChannelID_t Channel = LoggingSystem_RegisterLoggingChannel( ChannelName, NULL, ##__VA_ARGS__ ) |
|
|
|
#define BEGIN_DEFINE_LOGGING_CHANNEL( Channel, ChannelName, /* [Flags], [Severity], [Color] */ ... ) \ |
|
static void Register_##Channel##_Tags(); \ |
|
LoggingChannelID_t Channel = LoggingSystem_RegisterLoggingChannel( ChannelName, Register_##Channel##_Tags, ##__VA_ARGS__ ); \ |
|
void Register_##Channel##_Tags() \ |
|
{ |
|
|
|
#define ADD_LOGGING_CHANNEL_TAG( Tag ) LoggingSystem_AddTagToCurrentChannel( Tag ) |
|
|
|
#define END_DEFINE_LOGGING_CHANNEL() \ |
|
} |
|
|
|
////////////////////////////////////////////////////////////////////////// |
|
// DLL Exports |
|
////////////////////////////////////////////////////////////////////////// |
|
|
|
// For documentation on these functions, please look at the corresponding function |
|
// in CLoggingSystem (unless otherwise specified). |
|
PLATFORM_INTERFACE LoggingChannelID_t LoggingSystem_RegisterLoggingChannel( const char *pName, RegisterTagsFunc registerTagsFunc, int flags = 0, LoggingSeverity_t severity = LS_MESSAGE, Color color = UNSPECIFIED_LOGGING_COLOR ); |
|
|
|
PLATFORM_INTERFACE void LoggingSystem_RegisterLoggingListener( ILoggingListener *pListener ); |
|
PLATFORM_INTERFACE void LoggingSystem_UnregisterLoggingListener( ILoggingListener *pListener ); |
|
PLATFORM_INTERFACE void LoggingSystem_ResetCurrentLoggingState(); |
|
PLATFORM_INTERFACE void LoggingSystem_SetLoggingResponsePolicy( ILoggingResponsePolicy *pResponsePolicy ); |
|
// NOTE: PushLoggingState() saves the current logging state on a stack and results in a new clear state |
|
// (no listeners, default logging response policy). |
|
PLATFORM_INTERFACE void LoggingSystem_PushLoggingState( bool bThreadLocal = false, bool bClearState = true ); |
|
PLATFORM_INTERFACE void LoggingSystem_PopLoggingState( bool bThreadLocal = false ); |
|
|
|
PLATFORM_INTERFACE void LoggingSystem_AddTagToCurrentChannel( const char *pTagName ); |
|
|
|
// Returns INVALID_LOGGING_CHANNEL_ID if not found |
|
PLATFORM_INTERFACE LoggingChannelID_t LoggingSystem_FindChannel( const char *pChannelName ); |
|
PLATFORM_INTERFACE int LoggingSystem_GetChannelCount(); |
|
PLATFORM_INTERFACE LoggingChannelID_t LoggingSystem_GetFirstChannelID(); |
|
// Returns INVALID_LOGGING_CHANNEL_ID when there are no channels remaining. |
|
PLATFORM_INTERFACE LoggingChannelID_t LoggingSystem_GetNextChannelID( LoggingChannelID_t channelID ); |
|
PLATFORM_INTERFACE const CLoggingSystem::LoggingChannel_t *LoggingSystem_GetChannel( LoggingChannelID_t channelID ); |
|
|
|
PLATFORM_INTERFACE bool LoggingSystem_HasTag( LoggingChannelID_t channelID, const char *pTag ); |
|
|
|
PLATFORM_INTERFACE bool LoggingSystem_IsChannelEnabled( LoggingChannelID_t channelID, LoggingSeverity_t severity ); |
|
PLATFORM_INTERFACE void LoggingSystem_SetChannelSpewLevel( LoggingChannelID_t channelID, LoggingSeverity_t minimumSeverity ); |
|
PLATFORM_INTERFACE void LoggingSystem_SetChannelSpewLevelByName( const char *pName, LoggingSeverity_t minimumSeverity ); |
|
PLATFORM_INTERFACE void LoggingSystem_SetChannelSpewLevelByTag( const char *pTag, LoggingSeverity_t minimumSeverity ); |
|
|
|
// Color is represented as an int32 due to C-linkage restrictions |
|
PLATFORM_INTERFACE int32 LoggingSystem_GetChannelColor( LoggingChannelID_t channelID ); |
|
PLATFORM_INTERFACE void LoggingSystem_SetChannelColor( LoggingChannelID_t channelID, int color ); |
|
|
|
PLATFORM_INTERFACE LoggingChannelFlags_t LoggingSystem_GetChannelFlags( LoggingChannelID_t channelID ); |
|
PLATFORM_INTERFACE void LoggingSystem_SetChannelFlags( LoggingChannelID_t channelID, LoggingChannelFlags_t flags ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Logs a variable-argument to a given channel with the specified severity. |
|
// NOTE: if adding overloads to this function, remember that the Log_*** |
|
// macros simply pass their variadic parameters through to LoggingSystem_Log(). |
|
// Therefore, you need to ensure that the parameters are in the same general |
|
// order and that there are no ambiguities with the overload. |
|
//----------------------------------------------------------------------------- |
|
PLATFORM_INTERFACE LoggingResponse_t LoggingSystem_Log( LoggingChannelID_t channelID, LoggingSeverity_t severity, const char *pMessageFormat, ... ) FMTFUNCTION( 3, 4 ); |
|
PLATFORM_OVERLOAD LoggingResponse_t LoggingSystem_Log( LoggingChannelID_t channelID, LoggingSeverity_t severity, Color spewColor, const char *pMessageFormat, ... ) FMTFUNCTION( 4, 5 ); |
|
|
|
PLATFORM_INTERFACE LoggingResponse_t LoggingSystem_LogDirect( LoggingChannelID_t channelID, LoggingSeverity_t severity, Color spewColor, const char *pMessage ); |
|
PLATFORM_INTERFACE LoggingResponse_t LoggingSystem_LogAssert( const char *pMessageFormat, ... ) FMTFUNCTION( 1, 2 ); |
|
|
|
#endif // LOGGING_H
|