一個基於Loki::SingletonHolder的Windows線程安全的C++日誌類實現

使用了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

發佈了43 篇原創文章 · 獲贊 2 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章