当前位置:   article > 正文

c++ 自定义Logger 日志类

c++ 自定义Logger 日志类

Logger 日志类

线程安全的日志组件

默认保存到文件,并支持回调函数,比如显示到界面

#ifndef LOGGER_H
#define LOGGER_H

#include <iostream>
#include <sstream>
#include <mutex>
#include <thread>
#include <iomanip>
#include <fstream>
#include <string>
#include <condition_variable>
#include <thread>
#include <queue>
#include <chrono>
#include <ctime>
#include <functional>

// 线程安全的日志组件
class  Logger
{
public:

    enum class LogLevel
    {
        Unknown=0,  //未知信息
        Debug,      //调试信息
        Info,       //普通信息
        Trace,      //详细信息
        Warning,    //警告信息
        Error,      //错误信息,但程序可以继续运行。
        Fatal,      //出现无法恢复的错误,可能导致程序崩溃。
        Panic      //出现严重错误,必须立即停止程序运行。
    };

    Logger();
    Logger(const std::string& path);
    ~Logger();
    void set_file_name(const std::string& path);
    //添加回调函数
    void set_callback(const std::function<void(std::pair<LogLevel, std::string>)>& func);

    //输出日志
    void add_log(LogLevel level, const std::string& message);

    //转字符串
    static std::string level2string(LogLevel level);
private:
    //工作线程
    void worker();
    //获取当前时间
    std::string get_current_timestamp();

    //结束线程
    void stop();
private:
    std::mutex _mutex;
    std::condition_variable _condition;
    std::queue<std::pair<LogLevel, std::string>> _queue;
    std::thread _worker;
    std::string _path;
    std::ofstream _file;
    bool _stop;

    std::function<void(std::pair<LogLevel, std::string>)> _unction;
};


#endif // LOGGER_H

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
 #include "logger.h"

Logger::Logger(){}
Logger::Logger(const std::string& path) : _path(path),_stop(false), _worker(&Logger::worker, this)
{
    _file.open(_path, std::ios_base::app);
}

void Logger::set_file_name(const std::string& path)
{
    _path = path;
    _file.open(_path, std::ios_base::app);
}
Logger::~Logger()
{
    stop();
    _worker.join();

    //关闭文件
    if (_file.is_open())
    {
        _file.close();
    }
}
//添加回调函数 输出
void Logger::set_callback(const std::function<void(std::pair<LogLevel, std::string>)>& func)
{
    _unction = func;
}
std::string Logger::level2string(LogLevel level)
{
    switch (level)
    {
    case LogLevel::Debug: return "Debug";
    case LogLevel::Info: return "Info";
    case LogLevel::Trace: return "Trace";
    case LogLevel::Warning: return "Warning";
    case LogLevel::Error: return "Error";
    case LogLevel::Fatal: return "Fatal";
    case LogLevel::Panic: return "Panic";
    default: return "Unknown";
    }
}
//输出日志
void Logger::add_log(LogLevel level, const std::string& message)
{
    std::lock_guard<std::mutex> lock(_mutex);
    _queue.emplace(level, message);
    _condition.notify_one();
}


//工作线程
void Logger::worker()
{
    for(;;)
    {
        std::pair<LogLevel, std::string> pair;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _condition.wait(lock, [this] { return _stop || !_queue.empty(); });
            if (_stop && _queue.empty())
            {
                break;
            }
            pair = _queue.front();
            _queue.pop();
        }

        // //输出到文件
        // std::ofstream out(_path, std::ios_base::app);
        // if (!out.good())
        // {
        //     continue;
        // }
        // out << get_current_timestamp() <<"  "<<level2string(pair.first) <<":"<< pair.second << std::endl;
        // out.close();


        // 如果文件流不可用,则重新尝试打开
        if (!_file.is_open())
        {
            _file.open(_path, std::ios_base::app);
            if (!_file.is_open())
            {
                // 打开文件失败,继续下一个循环
                continue;
            }
        }

        // 输出日志消息到文件流
        _file << get_current_timestamp() << "  " << level2string(pair.first) << ":" << pair.second << std::endl;
        _file.flush(); // 刷新缓冲区
        if(_unction)
        {
            _unction(pair);
        }
    }
}
//获取当前时间
std::string Logger::get_current_timestamp()
{
    auto now = std::chrono::system_clock::now();
    auto time = std::chrono::system_clock::to_time_t(now);
    auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;

    std::stringstream ss;
    ss << std::put_time(std::localtime(&time), "%Y-%m-%d %H:%M:%S") << '.' << std::setfill('0') << std::setw(3) << ms.count();
    return ss.str();
}

//结束线程
void Logger::stop()
{
    std::lock_guard<std::mutex> lock(_mutex);
    _stop = true;
    _condition.notify_one();
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119

比如:
使用qt界面,接收日志,,通过接收 logReceived 信号,获取日志信息显示。这里QtConcurrent::run 可以方便接收信息,触发异步信号,不阻塞界面。不然界面会卡死,更新UI只能在一个线程中


// 增加日志回调
void StreamManagerWidget::log_function(std::pair<Logger::LogLevel, std::string> pair)
{
    // 在后台线程执行日志记录任务
    QtConcurrent::run(&_threadPool,[this, pair](){
        // 将日志信息格式化为 QString
        QString logMessage = QString::fromStdString(Logger::level2string(pair.first) +": "+ pair.second);
        // 发送信号,在主线程中更新 UI
        emit logReceived(logMessage);
    });
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/97355
推荐阅读
相关标签
  

闽ICP备14008679号