C++日志类

我们在写一些小项目时,封装一个log类,无论是在debug,还是运行信息输出,都可以带来不小的便利。

1. 信息分类

我们的输出信息可能时debug信息,错误信息,或者是运行状态信息,所以,我们可以利用enum来对信息分类,方便后续的日志打印。

enum class LogLevel : int
{
    Debug = 0,
    Info = 1,
    Error = 2,
    Fatal = 3
};

2. 主体功能实现

主体功能放在Logger类中实现

class Logger
{
    friend class Log;

public:
    explicit Logger(LogLevel level = LogLevel::Info);
    void ResetLogLevel(LogLevel level)
    {
        level_ = level;
    }

    void Write(LogLevel level, const char *format, ...);
    void Debug(const char *format, ...);
    void Info(const char *format, ...);
    void Error(const char *format, ...);
    void Fatal(const char *format, ...);

private:
    void WriteImpl(LogLevel level, const char *format, va_list *val);
    std::string GetSystemTime();
    std::string GetLevelStr(LogLevel level);
    LogLevel level_;
    Logger(const Logger &);
    void operator=(const Logger &);
};

其中,构造函数只是指明日志的内别,是Debug信息,Error信息亦或者其他信息。另外,真正的输出打印工作放在WriteImpl函数中,其实现如下:

inline void Logger::WriteImpl(LogLevel level, const char *format, va_list *val)
{

    std::string level_str = GetLevelStr(level);
    std::string time_str = GetSystemTime();
    va_list val_copy;
    va_copy(val_copy, *val);
    printf("[%s] [%s] ", level_str.c_str(), time_str.c_str());
    vprintf(format, *val);
    fflush(stdout);
    va_end(val_copy);
}

其中,所用到的GetLevelStr与GetSystemTime函数的函数名便描述了函数的功能。

3. 顶层接口

用户通过顶层类的接口,直接打印日志信息。

class Log
{
public:
    static void ResetLogLevel(LogLevel level);
    static void Write(LogLevel level, const char *format, ...);
    static void Debug(const char *format, ...);
    static void Info(const char *format, ...);
    static void Error(const char *format, ...);
    static void Fatal(const char *format, ...);
private:
    static Logger logger_;
};

4. 代码实现

1. log.h

enum class LogLevel : int
{
    Debug = 0,
    Info = 1,
    Error = 2,
    Fatal = 3
};

class Logger
{
    friend class Log;

public:
    explicit Logger(LogLevel level = LogLevel::Info);
    void ResetLogLevel(LogLevel level)
    {
        level_ = level;
    }

    void Write(LogLevel level, const char *format, ...);
    void Debug(const char *format, ...);
    void Info(const char *format, ...);
    void Error(const char *format, ...);
    void Fatal(const char *format, ...);

private:
    void WriteImpl(LogLevel level, const char *format, va_list *val);
    std::string GetSystemTime();
    std::string GetLevelStr(LogLevel level);
    LogLevel level_;
    Logger(const Logger &);
    void operator=(const Logger &);
};

class Log
{
public:
    static void ResetLogLevel(LogLevel level);
    static void Write(LogLevel level, const char *format, ...);
    static void Debug(const char *format, ...);
    static void Info(const char *format, ...);
    static void Error(const char *format, ...);
    static void Fatal(const char *format, ...);
private:
    static Logger logger_;
};

2. log.cpp

Logger::Logger(LogLevel level) : level_(level)
{
}

void Logger::Write(LogLevel level, const char *format, ...)
{
    va_list val;
    va_start(val, format);
    WriteImpl(level, format, &val);
    va_end(val);
}

inline void Logger::WriteImpl(LogLevel level, const char *format, va_list *val)
{

    std::string level_str = GetLevelStr(level);
    std::string time_str = GetSystemTime();
    va_list val_copy;
    va_copy(val_copy, *val);
    printf("[%s] [%s] ", level_str.c_str(), time_str.c_str());
    vprintf(format, *val);
    fflush(stdout);
    va_end(val_copy);
}

std::string Logger::GetSystemTime()
{
    time_t t = time(0);
    char str[64];
    strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", localtime(&t));
    return str;
}

std::string Logger::GetLevelStr(LogLevel level)
{
    switch (level)
    {
    case LogLevel::Debug:
        return "DEBUG";
    case LogLevel::Info:
        return "INFO";
    case LogLevel::Error:
        return "ERROR";
    case LogLevel::Fatal:
        return "FATAL";
    default:
        return "UNKNOW";
    }
}

Logger Log::logger_;

void Log::ResetLogLevel(LogLevel level)
{
    logger_.ResetLogLevel(level);
}

void Log::Write(LogLevel level, const char *format, ...)
{
    va_list val;
    va_start(val, format);
    logger_.WriteImpl(level, format, &val);
    va_end(val);
}

void Log::Info(const char *format, ...)
{
    va_list val;
    va_start(val, format);
    logger_.WriteImpl(LogLevel::Info, format, &val);
    va_end(val);
}

void Log::Error(const char *format, ...)
{
    va_list val;
    va_start(val, format);
    logger_.WriteImpl(LogLevel::Error, format, &val);
    va_end(val);
}

void Log::Fatal(const char *format, ...)
{
    va_list val;
    va_start(val, format);
    logger_.WriteImpl(LogLevel::Fatal, format, &val);
    va_end(val);
}


void Log::Debug(const char *format, ...)
{
    va_list val;
    va_start(val, format);
    logger_.WriteImpl(LogLevel::Debug, format, &val);
    va_end(val);
}
posted @   caieleven  阅读(619)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示