1
0
forked from 0ad/0ad
0ad/source/network/NetLog.h
janwas c0ed950657 had to remove uint and ulong from lib/types.h due to conflict with other library.
this snowballed into a massive search+destroy of the hodgepodge of
mostly equivalent types we had in use (int, uint, unsigned, unsigned
int, i32, u32, ulong, uintN).

it is more efficient to use 64-bit types in 64-bit mode, so the
preferred default is size_t (for anything remotely resembling a size or
index). tile coordinates are ssize_t to allow more efficient conversion
to/from floating point. flags are int because we almost never need more
than 15 distinct bits, bit test/set is not slower and int is fastest to
type. finally, some data that is pretty much directly passed to OpenGL
is now typed accordingly.

after several hours, the code now requires fewer casts and less
guesswork.

other changes:
- unit and player IDs now have an "invalid id" constant in the
respective class to avoid casting and -1
- fix some endian/64-bit bugs in the map (un)packing. added a
convenience function to write/read a size_t.
- ia32: change CPUID interface to allow passing in ecx (required for
cache topology detection, which I need at work). remove some unneeded
functions from asm, replace with intrinsics where possible.

This was SVN commit r5942.
2008-05-11 18:48:32 +00:00

662 lines
15 KiB
C++

/**
*-----------------------------------------------------------------------------
* FILE : NetLog.h
* PROJECT : 0 A.D.
* DESCRIPTION : Network subsystem logging classes declarations
*-----------------------------------------------------------------------------
*/
#ifndef NETLOG_H
#define NETLOG_H
// INCLUDES
#include "ps/Pyrogenesis.h"
#include "ps/ThreadUtil.h"
#include "ps/CStr.h"
#include "lib/timer.h"
#include <list>
#include <vector>
#include <fstream>
// DECLARATIONS
typedef enum
{
LOG_LEVEL_ALL = 0x0000, // Lowest level possible
LOG_LEVEL_DEBUG = 0x0001, // Informational events for app debugging
LOG_LEVEL_INFO = 0x0002, // Useful for highlighting app progress
LOG_LEVEL_WARN = 0x0004, // Potentially dangerous situations
LOG_LEVEL_ERROR = 0x0008, // Error events but the app can continue
LOG_LEVEL_FATAL = 0x0010, // Very severe errors, the app aborts
LOG_LEVEL_OFF = 0xFFFF, // The highest level possible
} LogLevel;
class CNetLogger;
class CNetLogSink;
typedef std::list< CNetLogger* > LoggerList;
typedef std::vector< CNetLogSink* > SinkList;
/*
CLASS : CNetLogEvent
DESCRIPTION : CNetLogEvent represents an object passed between
different network logging components when a decision
for logging is made
NOTES :
*/
class CNetLogEvent
{
public:
CNetLogEvent(
LogLevel level,
const CStr& message,
const CStr& loggerName );
~CNetLogEvent( void );
/**
* Returns the level of the event
*
* @return Event level;
*/
inline LogLevel GetLevel( void ) const { return m_Level; }
/**
* Returns the time of the event
*
* @return Event time
*/
inline TimerUnit GetTimeStamp( void ) const { return m_TimeStamp; }
/**
* Returns the name of the logger which logged the event
*
* @return Logger name
*/
inline const CStr& GetLoggerName( void ) const { return m_LoggerName; }
/**
* Returns the message used when the event was initialized
*
* @return Event message
*/
inline const CStr& GetMessage( void ) const { return m_Message; }
protected:
private:
// Not implemented
CNetLogEvent( const CNetLogEvent& );
CNetLogEvent& operator=( CNetLogEvent& );
LogLevel m_Level; // Current level
CStr m_LoggerName; // Logger which processed the event
CStr m_Message; // Application message for the event
TimerUnit m_TimeStamp; // Event logging time
};
/*
CLASS : CNetLogSink
DESCRIPTION : CNetLogSink is the basic interface for events logging
NOTES :
*/
class CNetLogSink
{
public:
CNetLogSink( );
virtual ~CNetLogSink( );
/**
* Set the name of the sink
*
* @param name New sink name
*/
void SetName( const CStr& name );
/**
* Retrieves the name of the sink
*
* @return Sink name
*/
inline const CStr& GetName( void ) const { return m_Name; }
/**
* Set the level of the sink
*
* @param level New sink level
*/
void SetLevel( LogLevel level );
/**
* Retrieves the current level of the sink
*
* @return Sink current level
*/
inline LogLevel GetLevel( void ) const { return m_Level; }
/**
* Retrieves the header text
*
* @return The header text
*/
inline const CStr& GetHeader( void ) const { return m_Header; }
/**
* Set header text which will be logged before an event logging
*
* @param header New header text
*/
void SetHeader( const CStr& header );
/**
* Retrieves the footer text
*
* @return The footer text
*/
inline const CStr& GetFooter( void ) const { return m_Footer; }
/**
* Set footer text which will be logged after an event logging
*
* @param footer New footer text
*/
void SetFooter( const CStr& footer );
/**
* Activates the sink
*/
void Activate( void );
/**
* Closes the sink and release any resources
*/
void Close( void );
/**
* Check if the level of the event is greater than or equal to sink level
* and if it succeeds it performs the actual logging of the event.
*
* @param event Event to log
*/
void DoSink( const CNetLogEvent& event );
/**
* For each event from the passed array, check if its level is greater than
* or equal to sink level and performs the logging for it.
*
* @param pEvents List of events to log
* @param eventCount The number of events in pEvents list
*/
void DoBulkSink( const CNetLogEvent* pEvents, size_t eventCount );
/**
* Check if the sink can log the specified event
*
* @param event Event to check
* @return true if the event can be logged,
* false otherwise
*/
virtual bool TestEvent( const CNetLogEvent& event );
protected:
/**
* Activates the sink object
*/
virtual void OnActivate( void );
/**
* Writes a header into the sink
*/
virtual void WriteHeader( void );
/**
* Writes a footer into the sink
*/
virtual void WriteFooter( void );
/**
* Writes a string message to the logging output
*
* @param message The message to log
*/
virtual void Write( const CStr& message ) = 0;
/**
* Writes a single character to the logging output
*
* @param c The character to log
*/
virtual void Write( char c ) = 0;
/**
* This is called by Close method. It can be overriden by specialized sinks
* if any resources needs to be released on close.
*/
virtual void OnClose( void );
/**
* This method is called by DoSink and DoBulkSink and it must be
* implemented by specialized sinks to perform actual logging
*
* @param event Event to log
*/
virtual void Sink( const CNetLogEvent& event ) = 0;
LogLevel m_Level; // Current level
CMutex m_Mutex; // Multithreading synchronization object
CStr m_Header; // Header text
CStr m_Footer; // Footer text
CStr m_Name; // Sink name
bool m_Closed; // Indicates whether the sink is closed
bool m_Active; // Indicates whether the sink is active
private:
// Not implemented
CNetLogSink( const CNetLogSink& );
CNetLogSink& operator=( const CNetLogSink& );
};
/*
CLASS : CNetLogFileSink
DESCRIPTION : Log network events to a file
NOTES :
*/
class CNetLogFileSink : public CNetLogSink
{
public:
CNetLogFileSink( void );
CNetLogFileSink( const CStr& filename );
CNetLogFileSink( const CStr& filename, bool append );
~CNetLogFileSink( void );
protected:
/**
* Activates the sink object and opens the file specified in constructor
*/
virtual void OnActivate( void );
/**
* Closes the log file
*/
virtual void OnClose( void );
/**
* Writes the event to the log file if opened
*
* @param event Event to log
*/
virtual void Sink( const CNetLogEvent& event );
/**
* Writes the message passed as parameter to file
*
* @param message The message to log
*/
virtual void Write( const CStr& message );
/**
* Writes the character passed as parameter to file
*
* @param c The character to log
*/
virtual void Write( char c );
private:
// Not implemented
CNetLogFileSink( const CNetLogFileSink& );
CNetLogFileSink& operator=( const CNetLogFileSink& );
/**
* Open the file where logging goes. The header text will be written each
* time the file is opened. If append parameter is true, then the file may
* contain the header many times.
*
* @param filename The path to the log file
* @param append Indicates whether logging should append to
* the file or truncate the file
*/
void OpenFile( const CStr& fileName, bool append );
/**
* Close the previously opened file. The footer text will be written each time
* the file is closed. If the file was opened for appending, the footer might
* appera many times.
*/
void CloseFile( void );
std::ofstream m_File; // The log file handle
CStr m_FileName; // The name of the log file
bool m_Append; // Logging should append to file
};
/*
CLASS : CNetLogConsoleSink
DESCRIPTION : Log network events to the game console
NOTES :
*/
class CNetLogConsoleSink : public CNetLogSink
{
public:
CNetLogConsoleSink( void );
~CNetLogConsoleSink( void );
protected:
/**
* Activates the sink object and the game console
*/
virtual void OnActivate( void );
/**
* Toggle off game console
*/
virtual void OnClose( void );
/**
* Writes the event to the game console if active
*
* @param event Event to log
*/
virtual void Sink( const CNetLogEvent& event );
/**
* Writes the message passed as parameter to game console
*
* @param message The message to log
*/
virtual void Write( const CStr& message );
/**
* Writes the character passed as parameter to game console
*
* @param c The character to log
*/
virtual void Write( char c );
private:
// Not implemented
CNetLogConsoleSink( const CNetLogConsoleSink& );
CNetLogConsoleSink& operator=( const CNetLogConsoleSink& );
};
/*
CLASS : CNetLogger
DESCRIPTION : CNetLogger serves for logging messages for network subsytem.
It contains methods for logging at different levels.
NOTES : CNetLogManager is used to obtain an instance of a logger.
*/
class CNetLogger
{
public:
CNetLogger( const CStr& name );
virtual ~CNetLogger( void );
bool IsDebugEnabled ( void ) const;
bool IsInfoEnabled ( void ) const;
bool IsWarnEnabled ( void ) const;
bool IsErrorEnabled ( void ) const;
bool IsFatalEnabled ( void ) const;
void Debug ( const CStr& message );
void Warn ( const CStr& message );
void Info ( const CStr& message );
void Error ( const CStr& message );
void Fatal ( const CStr& message );
void DebugFormat ( const char* pFormat, ... );
void WarnFormat ( const char* pFormat, ... );
void InfoFormat ( const char* pFormat, ... );
void ErrorFormat ( const char* pFormat, ... );
void FatalFormat ( const char* pFormat, ... );
/**
* Retrieves the name of the logger
*
* @return Logger name
*/
const CStr& GetName( void ) const { return m_Name; }
/**
* Retrieves the level of the logger
*
* @return Logger level
*/
LogLevel GetLevel( void ) const { return m_Level; }
/**
* Set the level for the logger
*
* @param level New logger level
*/
void SetLevel( LogLevel level );
/**
* Attaches a new sink to the list of sinks. The sink will be activated.
*
* @param pSink The sink to add
*/
void AddSink( CNetLogSink* pSink );
/**
* Removes the specified sink from the list of attached sinks. The sink
* will not be closed.
*
* @param pSink The sink to remove
* @return The removed sink or NULL if not found
*/
CNetLogSink* RemoveSink( CNetLogSink* pSink );
/**
* Remove the named sink passed as parameter. The sink will not be closed.
*
* @param name The name of sink to remove
* @return The removed sink or NULL if not found
*/
CNetLogSink* RemoveSink( const CStr& name );
/**
* Removes all attached sinks
*
*/
void RemoveAllSinks( void );
/**
* Retrieve the number of attached sinks
*
* @return The number of sink objects
*/
size_t GetSinkCount( void );
/**
* Retrieves the sink by its index
*
* @param index The index of the sink
* @return NULL if index is out of boundaries or
* the sink at the specified index
*/
CNetLogSink* GetSink( size_t index );
/**
* Retrieves a sink by its name
*
* @param name The name of the sink
* @return NULL if the sink does not exists or
* the sink with the specified name
*/
CNetLogSink* GetSink( const CStr& name );
/**
* Helper function used to retrieve local date time in a string
*/
static void GetStringDateTime( CStr& str );
/**
* Helper function used to retrieve local time in a string
*/
static void GetStringTime( CStr& str );
/**
* Helper function used to retrieve the current timestamp in a string
*/
static void GetStringTimeStamp( CStr& str );
protected:
private:
// Not implemented
CNetLogger( const CNetLogger& );
CNetLogger& operator=( const CNetLogger& );
/**
* Dispatch the event passed as parameter to all sinks
*
* @param event The event to log
*/
void CallSinks( const CNetLogEvent& event );
CMutex m_Mutex; // Multithread synchronization object
SinkList m_Sinks; // Holds the list of sink objects
LogLevel m_Level; // Logger level
CStr m_Name; // Logger name
};
/*
CLASS : CNetLogManager
DESCRIPTION : CNetLogManager serves clients requesting log instances
NOTES : The GetLogger method can be used to retrieve a log
*/
class CNetLogManager
{
public:
/**
* Shutdown the log manager, closes all sinks in the loggers.
*
*/
static void Shutdown( void );
/**
* Retrieves a named logger. If the logger does not exist, it is created.
*
* @param name Logger name
* @return A logger object
*/
static CNetLogger* GetLogger( const CStr& name );
/**
* Return the list of all defined loggers.
*
* @return The list of all loggers
*/
static const LoggerList& GetAllLoggers( void );
private:
// Not implemented
CNetLogManager( void );
~CNetLogManager( void );
CNetLogManager( const CNetLogManager& );
CNetLogManager& operator=( const CNetLogManager& );
static LoggerList m_Loggers; // Holds the list of loggers
};
// TODO: Replace with better access to log manager
#define START_LOGGER( sinkName, sinkType )\
CNetLogger *pLogger = CNetLogManager::GetLogger( "net.log" );\
if ( pLogger )\
{\
CNetLogSink* pSink = pLogger->GetSink( sinkName );\
if ( !pSink )\
{\
pSink = new sinkType();\
if ( pSink )\
{\
CStr startTime;\
CNetLogger::GetStringDateTime( startTime );\
CStr header = "***************************************************\n";\
header += "LOG STARTED: ";\
header += startTime;\
header += "\n";\
header += "Timestamps are in seconds since engine startup\n";\
pSink->SetHeader( header );\
pSink->SetName( sinkName );\
if ( strcmp(sinkName, "sink.console") == 0 )\
pSink->SetLevel( LOG_LEVEL_ERROR );\
else\
pSink->SetLevel( LOG_LEVEL_INFO );\
pLogger->AddSink( pSink );\
}\
}
#define END_LOGGER\
}
#define NET_LOG( parameter )\
{\
START_LOGGER( "sink.file", CNetLogFileSink )\
pLogger->Info( parameter );\
END_LOGGER\
}\
{\
START_LOGGER( "sink.console", CNetLogConsoleSink )\
pLogger->Info( parameter );\
END_LOGGER\
}
#define NET_LOG2( format, parameter )\
{\
START_LOGGER( "sink.file", CNetLogFileSink )\
pLogger->InfoFormat( format, parameter );\
END_LOGGER\
}\
{\
START_LOGGER( "sink.console", CNetLogConsoleSink )\
pLogger->InfoFormat( format, parameter );\
END_LOGGER\
}
#define NET_LOG3( format, parameter1, parameter2 )\
{\
START_LOGGER( "sink.file", CNetLogFileSink )\
pLogger->InfoFormat( format, parameter1, parameter2 );\
END_LOGGER\
}\
{\
START_LOGGER( "sink.console", CNetLogConsoleSink )\
pLogger->InfoFormat( format, parameter1, parameter2 );\
END_LOGGER\
}
#define NET_LOG4( format, parameter1, parameter2, parameter3 )\
{\
START_LOGGER( "sink.file", CNetLogFileSink )\
pLogger->InfoFormat( format, parameter1, parameter2, parameter3 );\
END_LOGGER\
}\
{\
START_LOGGER( "sink.console", CNetLogConsoleSink )\
pLogger->InfoFormat( format, parameter1, parameter2, parameter3 );\
END_LOGGER\
}
#endif // NETLOG_H