使用了Loki(http://sourceforge.net/projects/loki-lib/)和boost(http://www.boost.org/),在MS VC++ 2008上编译通过。
Log.h
// Log.h: interface for the ILog class.
#pragma once
#include <cstdarg>
#include <fstream>
#include <boost/thread.hpp>
#include <loki/Singleton.h>
// =============================================================================
// class ILog
// =============================================================================
class ILog
{
public:
// iLogLevel parameter for ForceWrite() and Write()
enum { LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_CRITICAL, LOG_SEVERE, };
private:
int m_iLogLevel;
boost::mutex m_lock;
std::ofstream m_ostream;
private:
// PROHIBITED, DO NOT DEFINE
ILog(const ILog &);
ILog &operator =(const ILog &);
// non-const method
void DoWrite(int iLogLevel, const char *pszModule, const char *fmt, va_list &ap);
public:
// creator
ILog(void);
~ ILog();
// non-const method
void Flush(void);
void ForceWrite(int iLogLevel, const char *pszModule, const char *fmt, ...);
void SetLogLevel(int iLogLevel);
void Write(int iLogLevel, const char *pszModule, const char *fmt, ...);
};
typedef Loki::SingletonHolder<ILog, Loki::CreateUsingNew, Loki::PhoenixSingleton> CLogHolder;
#define g_log CLogHolder::Instance()
Log.cpp
// Log.cpp: implementation of the ILog class.
#include <stdafx.h>
#include <cassert>
#include <cstdio>
#include <ctime>
#include <tchar.h>
#include <strsafe.h>
#include <Log.h>
// =============================================================================
// ILog constructor
// =============================================================================
ILog::ILog(void)
{
m_iLogLevel = LOG_WARNING;
}
// =============================================================================
// ILog destructor
// =============================================================================
ILog::~ILog()
{
boost::lock_guard < boost::mutex > guard(m_lock);
m_ostream.close();
}
// =============================================================================
// ILog::DoWrite
// =============================================================================
void ILog::DoWrite(int iLogLevel, const char *pszModule, const char *fmt, va_list &ap)
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static int s_iTimes = 0;
static const char *const s_ppszLogLevel[] = { "DEBUG ", "INFO ", "WARNING ", "CRITICAL ", "SEVERE ", };
tm tmLocal;
time_t tmGeneral;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
assert(LOG_DEBUG <= iLogLevel && iLogLevel <= LOG_SEVERE);
assert(pszModule);
assert(fmt);
time(&tmGeneral);
localtime_s(&tmLocal, &tmGeneral);
boost::lock_guard < boost::mutex > guard(m_lock);
if (!m_ostream.is_open()) {
//~~~~~~~~~~~~~~~~~~~~~~~
DWORD ret;
TCHAR szFilePath[MAX_PATH];
//~~~~~~~~~~~~~~~~~~~~~~~
ret = GetEnvironmentVariable(TEXT("APPDATA"), szFilePath, _countof(szFilePath));
if (!ret || ret >= _countof(szFilePath)) {
return;
}
if (FAILED(StringCchCat(szFilePath, _countof(szFilePath), TEXT("\\")))) {
return;
}
//~~~~~~~~~~~~~~~~~~~~~~~
extern TCHAR g_szAppName[];
//~~~~~~~~~~~~~~~~~~~~~~~
if (FAILED(StringCchCat(szFilePath, _countof(szFilePath), g_szAppName))) {
return;
}
if (!CreateDirectory(szFilePath, NULL)) {
if (ERROR_ALREADY_EXISTS != GetLastError()) {
return;
}
}
//~~~~~~~~~~~~~~~~~
TCHAR szFileName[32];
//~~~~~~~~~~~~~~~~~
_tcsftime(szFileName, _countof(szFileName), TEXT("\\%Y%m\\"), &tmLocal);
if (FAILED(StringCchCat(szFilePath, _countof(szFilePath), szFileName))) {
return;
}
if (!CreateDirectory(szFilePath, NULL)) {
if (ERROR_ALREADY_EXISTS != GetLastError()) {
return;
}
}
_tcsftime(szFileName, _countof(szFileName), TEXT("%Y%m%d-%H%M%S.log"), &tmLocal);
if (FAILED(StringCchCat(szFilePath, _countof(szFilePath), szFileName))) {
return;
}
m_ostream.open(szFilePath, std::ios_base::app | std::ios_base::out);
if (!m_ostream.is_open()) {
return;
}
}
//~~~~~~~~~~~~~
char szLog[2048];
char szTime[32];
//~~~~~~~~~~~~~
strftime(szTime, sizeof(szTime), "%Y%m%d:%H%M%S ", &tmLocal);
vsnprintf_s(szLog, sizeof(szLog), _TRUNCATE, fmt, ap);
m_ostream << szTime << s_ppszLogLevel[iLogLevel] << "(" << pszModule << ") " << szLog << std::endl;
// truncate each log file to max 0x10000(65536) lines
if (++s_iTimes >> 16) {
s_iTimes = 0;
m_ostream.close();
}
}
// =============================================================================
// ILog::Flush
// =============================================================================
void ILog::Flush(void)
{
boost::lock_guard < boost::mutex > guard(m_lock);
if (m_ostream.is_open()) {
m_ostream.flush();
}
}
// =============================================================================
// ILog::ForceWrite
// =============================================================================
void ILog::ForceWrite(int iLogLevel, const char *pszModule, const char *fmt, ...)
{
assert(LOG_DEBUG <= iLogLevel && iLogLevel <= LOG_SEVERE);
assert(pszModule);
assert(fmt);
//~~~~~~~
va_list ap;
//~~~~~~~
va_start(ap, fmt);
DoWrite(iLogLevel, pszModule, fmt, ap);
va_end(ap);
}
// =============================================================================
// ILog::SetLogLevel
// =============================================================================
void ILog::SetLogLevel(int iLogLevel)
{
assert(LOG_DEBUG <= iLogLevel && iLogLevel <= LOG_SEVERE);
m_iLogLevel = iLogLevel;
}
// =============================================================================
// ILog::Write
// =============================================================================
void ILog::Write(int iLogLevel, const char *pszModule, const char *fmt, ...)
{
assert(LOG_DEBUG <= iLogLevel && iLogLevel <= LOG_SEVERE);
assert(pszModule);
assert(fmt);
if (m_iLogLevel <= iLogLevel) {
//~~~~~~~
va_list ap;
//~~~~~~~
va_start(ap, fmt);
DoWrite(iLogLevel, pszModule, fmt, ap);
va_end(ap);
}
}
用法
#include <Log.h>
TCHAR g_szAppName[] = TEXT("MyAppName");
...
g_log.Write(ILog::LOG_WARNING, "main", "Test string %s", "0123456789");
对Loki进行了一些设置修改:
--- Singleton.h Thu Aug 02 20:36:10 2007
+++ Singleton.h Mon Sep 12 09:20:51 2011
@@ -29,6 +29,8 @@
#include <list>
#include <memory>
+#define ATEXIT_FIXED
+
#ifdef _MSC_VER
#define LOKI_C_CALLING_CONVENTION_QUALIFIER __cdecl
#else
--- Threads.h Mon Nov 10 06:47:06 2008
+++ Threads.h Mon Sep 12 09:09:54 2011
@@ -52,6 +52,8 @@
#include <cassert>
+#define LOKI_CLASS_LEVEL_THREADING
+
#if defined(LOKI_CLASS_LEVEL_THREADING) || defined(LOKI_OBJECT_LEVEL_THREADING)
#define LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL ::Loki::ClassLevelLockable