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.
 
 
 
 
 
 

211 lines
5.7 KiB

////////////////////////////////////////////////////////////////////
// Log.h
//
// Copyright 2007 cDc@seacave
// Distributed under the Boost Software License, Version 1.0
// (See http://www.boost.org/LICENSE_1_0.txt)
#ifndef __SEACAVE_LOG_H__
#define __SEACAVE_LOG_H__
// I N C L U D E S /////////////////////////////////////////////////
// D E F I N E S ///////////////////////////////////////////////////
// use file handles to access console
#define _USE_COSOLEFILEHANDLES
//#define LOG_DATE // add date info for every log
#define LOG_TIME // add time info for every log
#define LOG_THREAD // make log multi-thread safe
#define LOG_STREAM // add stream support (operator <<)
#define LOGTYPE_SIZE 8
#define DEFAULT_LOGTYPE _T("App ")
#define DECLARE_LOG() \
protected: static const Log::Idx ms_nLogType;
#define DEFINE_LOG(classname, log) \
const Log::Idx classname::ms_nLogType(REGISTER_LOG(log));
#ifdef LOG_THREAD
#include "CriticalSection.h"
#endif
namespace SEACAVE {
// S T R U C T S ///////////////////////////////////////////////////
class GENERAL_API Log
{
DECLARE_SINGLETON(Log);
public:
typedef uint32_t Idx;
typedef DELEGATE<void (const String&)> ClbkRecordMsg;
typedef cList<ClbkRecordMsg> ClbkRecordMsgArray;
typedef CSharedPtr<ClbkRecordMsgArray> ClbkRecordMsgArrayPtr;
public:
// log methods
void Open() { m_arrRecordClbk = new ClbkRecordMsgArray; }
void Close() { m_arrRecordClbk = NULL; }
void Join(Log& log) { m_arrRecordClbk = log.m_arrRecordClbk; }
void RegisterListener(ClbkRecordMsg);
void UnregisterListener(ClbkRecordMsg);
Idx RegisterType(LPCTSTR);
void ResetTypes();
void Write(LPCTSTR, ...);
void Write(Idx, LPCTSTR, ...);
#ifdef LOG_STREAM
template<class T> inline Log& operator<<(const T& val) {
#ifdef LOG_THREAD
Lock l(m_cs);
std::ostringstream& ostr = m_streams[__THREAD__];
#else
std::ostringstream& ostr = m_stream;
#endif
ostr << val;
const std::string& line = ostr.str();
if (!line.empty() && *(line.end()-1) == _T('\n')) {
Write(line.substr(0, line.size()-1).c_str());
ostr.str(_T(""));
}
return *this;
}
// the type of std::cout
typedef std::basic_ostream<char, std::char_traits<char> > CoutType;
// the function signature of std::endl
typedef CoutType& (*StandardEndLine)(CoutType&);
// define an operator<< to take in std::endl
inline Log& operator<<(StandardEndLine) {
#ifdef LOG_THREAD
Lock l(m_cs);
std::ostringstream& ostr = m_streams[__THREAD__];
#else
std::ostringstream& ostr = m_stream;
#endif
Write(ostr.str().c_str());
ostr.str(_T(""));
return *this;
}
#endif
protected:
// write a message of a certain type to the log
void _Record(Idx, LPCTSTR, va_list);
protected:
struct LogType {
TCHAR szName[LOGTYPE_SIZE+1];
inline operator LPCTSTR () const { return szName; }
inline operator LPTSTR () { return szName; }
};
typedef cList<LogType, const LogType&, 0, 8> LogTypeArr;
// log members
String m_message; // last recorded message
ClbkRecordMsgArrayPtr m_arrRecordClbk;// the array with all registered listeners
LogTypeArr m_arrLogTypes; // the array with all the registered log types
#ifdef LOG_THREAD
// threading
RWLock m_lock; // mutex used to ensure multi-thread safety
#endif
#ifdef LOG_STREAM
// streaming
#ifdef LOG_THREAD
typedef std::unordered_map<unsigned,std::ostringstream> StreamMap;
StreamMap m_streams; // stream object used to handle one log with operator << (one for each thread)
CriticalSection m_cs; // mutex used to ensure multi-thread safety for accessing m_streams
#else
std::ostringstream m_stream; // stream object used to handle one log with operator <<
#endif
#endif
// static
#ifndef DEFAULT_LOGTYPE
static LogType g_appType;
#endif
};
#define GET_LOG() SEACAVE::Log::GetInstance()
#define OPEN_LOG() GET_LOG().Open()
#define CLOSE_LOG() GET_LOG().Close()
#define JOIN_LOG(log) GET_LOG().Join(log)
#define REGISTER_LOG(lt) GET_LOG().RegisterType(lt)
#define LOG GET_LOG().Write
#define SLOG(msg) GET_LOG() << msg
#ifndef _RELEASE
#define LOGV LOG // include extra details in the log
#else
#define LOGV(...)
#endif
/*----------------------------------------------------------------*/
class GENERAL_API LogFile
{
DECLARE_SINGLETON(LogFile);
public:
~LogFile() { Close(); }
// log methods
bool Open(LPCTSTR);
void Close();
void Pause();
void Play();
void Record(const String&);
protected:
FilePtr m_ptrFile; // the log file
};
#define GET_LOGFILE() LogFile::GetInstance()
#define OPEN_LOGFILE(log) GET_LOGFILE().Open(log)
#define CLOSE_LOGFILE() GET_LOGFILE().Close()
/*----------------------------------------------------------------*/
class GENERAL_API LogConsole
{
DECLARE_SINGLETON(LogConsole);
public:
~LogConsole() { Close(); }
bool IsOpen() const;
// log methods
void Open();
void Close();
void Pause();
void Play();
void Record(const String&);
protected:
#ifdef _USE_COSOLEFILEHANDLES
typedef FILE* StreamHandle;
#else
typedef int StreamHandle;
#endif
StreamHandle m_fileIn; // the log file in
StreamHandle m_fileOut; // the log file out
StreamHandle m_fileErr; // the log file error
std::streambuf* m_cout; // the redirected cout stream
std::streambuf* m_coutOld; // the original cout stream
std::streambuf* m_cerr; // the redirected cerr stream
std::streambuf* m_cerrOld; // the original cout stream
bool bManageConsole; // remember if the console is created here or is an existing console
};
#define GET_LOGCONSOLE() LogConsole::GetInstance()
#define OPEN_LOGCONSOLE() GET_LOGCONSOLE().Open()
#define CLOSE_LOGCONSOLE() GET_LOGCONSOLE().Close()
/*----------------------------------------------------------------*/
} // namespace SEACAVE
#endif // __SEACAVE_LOG_H__