一个小而美的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();
}

 

posted @ 2018-08-09 10:10  探索者软件  阅读(314)  评论(0编辑  收藏  举报