一个小而美的C++日志类
废话少说,先看东西。
//log.h #pragma once #define LOG_BUFSIZE 1024 enum LogLevel { LV_DEBUG = 1, LV_INFO = 2, LV_WARN = 4, LV_ERROR = 8, LV_ALL = 15 }; class Log { public: static bool CreateInst(const char * p_logdir = 0, const char * p_logname = 0, bool append = true, LogLevel level = LV_ALL); static void DestroyInst(); static void DEBUG(const char * logformat, ...); static void INFO(const char * logformat, ...); static void WARN(const char * logformat, ...); static void Error(const char * logformat, ...); static void SetLoggerLevel(LogLevel level); private: Log(const char * filelocation); bool write(LogLevel level, const char * logformat, ...); ~Log(); private: static int preMakeStr(LogLevel level, char * buffer); private: FILE * fp; char m_buffer[LOG_BUFSIZE]; LogLevel m_level; static Log * p_instance; }; #ifdef _DEBUG #define LOG_DEBUG(log_fmt, ...) do { Log::DEBUG(log_fmt, __VA_ARGS__); } while (0) #else #define LOG_DEBUG() #endif #define LOG_INFO(log_fmt, ...) do { Log::INFO(log_fmt, __VA_ARGS__); } while (0)
//log.cpp #include "StdAfx.h" #include "log.h"#include <direct.h> #include <set> #include <map> bool Log::CreateInst(const char * p_logdir, const char * p_logname, bool append, LogLevel level) { if (p_instance) return true; std::string name; if (p_logname == 0) { time_t curTime; time(&curTime); tm tm1; localtime_s(&tm1, &curTime); char buffer[MAX_PATH]; memset(buffer, 0, MAX_PATH); _snprintf(buffer, MAX_PATH, "%04d%02d%02d_%02d%02d%02d.log", tm1.tm_year + 1900, tm1.tm_mon + 1, tm1.tm_mday, tm1.tm_hour, tm1.tm_min, tm1.tm_sec); name = buffer; } else { name = p_logname; } std::string path; if (p_logdir == 0) { TCHAR tmpP[MAX_PATH]; GetEnvironmentVariable(_T("APPDATA"), tmpP, MAX_PATH); path = String::ToString(tmpP); path += "\\TSZ\\log"; } else { path = p_logdir; } if (*path.rbegin() != '\\') path += '\\'; if (access(path.c_str(), 0) == -1) { if (mkdir(path.c_str()) < 0) { fprintf(stderr, "create folder failed\n"); return false; } } char buffer[MAX_PATH]; memset(buffer, 0, MAX_PATH); _snprintf(buffer, MAX_PATH, "%s%s", path.c_str(), name.c_str()); if (!append) DeleteFile(String::ToCString(buffer)); p_instance = new Log(buffer); p_instance->SetLoggerLevel(level); return p_instance != 0; } void Log::DestroyInst() { delete p_instance; p_instance = 0; } void Log::DEBUG(const char * logformat, ...) { if (!p_instance) return; if ((p_instance->m_level & LV_DEBUG) == 0) return; va_list args; va_start(args, logformat); p_instance->write(LV_INFO, logformat, args); va_end(args); } void Log::INFO(const char * logformat, ...) { if (!p_instance) return; if ((p_instance->m_level & LV_INFO) == 0) return; va_list args; va_start(args, logformat); p_instance->write(LV_INFO, logformat, args); va_end(args); } void Log::WARN(const char * logformat, ...) { if (!p_instance) return; if ((p_instance->m_level & LV_WARN) == 0) return; va_list args; va_start(args, logformat); p_instance->write(LV_INFO, logformat, args); va_end(args); } void Log::Error(const char * logformat, ...) { if (!p_instance) return; if ((p_instance->m_level & LV_ERROR) == 0) return; va_list args; va_start(args, logformat); p_instance->write(LV_INFO, logformat, args); va_end(args); } void Log::SetLoggerLevel(LogLevel level) { if (!p_instance) return; p_instance->m_level = level; } Log::Log(const char * filelocation) { fp = _fsopen(filelocation, "a+", _SH_DENYNO); m_level = LV_ALL; memset(m_buffer, 0, LOG_BUFSIZE); } bool Log::write(LogLevel level, const char * logformat, ...) { if (fp == NULL) { return false; } memset(m_buffer, 0, LOG_BUFSIZE); int nsize = 0; int prestrlen = 0; char * str = m_buffer; prestrlen = preMakeStr(level, str); str += prestrlen; va_list args; va_start(args, logformat); nsize = _vsnprintf(str, LOG_BUFSIZE - prestrlen, logformat, args); va_end(args); if (level == LV_ERROR) { str += nsize; nsize = _snprintf(str, LOG_BUFSIZE - prestrlen - nsize, "[%s - %s - %d]", __FILE__, __FUNCTION__, __LINE__); } fprintf(fp, "%s\n", m_buffer); fflush(fp); return true; } Log::~Log() { if (fp) { fclose(fp); fp = NULL; } } int Log::preMakeStr(LogLevel level, char * buffer) { const char * lv = 0; switch (level) { case LV_DEBUG: lv = "debug"; break; case LV_INFO: lv = "info"; break; case LV_WARN: lv = "warn"; break; case LV_ERROR: lv = "error"; break; default: lv = "info"; break; } time_t now; now = time(&now); struct tm vtm = *localtime(&now); return _snprintf(buffer, LOG_BUFSIZE, "[%04d-%02d-%02d %02d:%02d:%02d][%s] ", vtm.tm_year + 1900, vtm.tm_mon + 1, vtm.tm_mday, vtm.tm_hour, vtm.tm_min, vtm.tm_sec, lv); } Log * Log::p_instance = 0;
由于实现过程用了单例模式,所以在构造对象的时候需要调用类提供的相应函数。
下面是使用用例:
int main() { Log::CreateInst(); Log::INFO("Everything is OK!"); Log::DestroyInst(); }