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

 #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();
}

比如:
使用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. c++ 定义Logger 日志

    2024-02-15 23:12:01       58 阅读
  2. c# 一个定义日志

    2024-02-15 23:12:01       16 阅读
  3. 实现C++定义的String

    2024-02-15 23:12:01       33 阅读
  4. C++学习——模板的使用:定义数组

    2024-02-15 23:12:01       56 阅读
  5. C# Newtonsoft.Json解析json到定义实体

    2024-02-15 23:12:01       54 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-02-15 23:12:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-02-15 23:12:01       100 阅读
  3. 在Django里面运行非项目文件

    2024-02-15 23:12:01       82 阅读
  4. Python语言-面向对象

    2024-02-15 23:12:01       91 阅读

热门阅读

  1. 个人浅见之程序员为什么不喜欢关电脑

    2024-02-15 23:12:01       55 阅读
  2. 跨域问题浅析

    2024-02-15 23:12:01       59 阅读
  3. Python概率建模算法和图示

    2024-02-15 23:12:01       54 阅读
  4. 自动化专业英语词汇积累【第一期】

    2024-02-15 23:12:01       48 阅读
  5. 011axios

    2024-02-15 23:12:01       43 阅读
  6. 广度优先搜索:一层一层探索

    2024-02-15 23:12:01       62 阅读
  7. vivado HDL编码技术

    2024-02-15 23:12:01       47 阅读
  8. 树形DP,P2279 [HNOI2003] 消防局的设立

    2024-02-15 23:12:01       58 阅读