Qt的简易日志库实现及封装

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: Qt的简易日志库实现及封装

用于QT的一个简易日志功能模块封装。算不上强大和多高的性能,但是足够简单小巧。用于记录日志到文件够用了。单独的一个文件模块,使用时直接引入源码。想要其他功能,直接改代码即可。


C++的下的日志库有很多,如log4cpp、Easylogging++,eplog,g3log,Qt下也有log4qt。


还有简单小巧的QsLog,它是一个基于Qt的轻量级开源日志库。


QsLog的git地址:https://github.com/victronenergy/QsLog


log4qt的git地址:https://github.com/devbean/log4qt


如果这些都不想用,还想更简单小巧的,可以看以下这个简易模块封装。


查看日志推荐用baretailpro工具。



使用方法


使用时只需工程文件.pro中包含模块源码即可。


include(Logger/MessageLogger.pri)


MessageLogger.pri文件内容:


#ifndef MESSAGELOGGER_H
#define MESSAGELOGGER_H
/** @description 用于Qt项目的一个简单的日志库,将日志存入日志文件(文本文件)中。
 *   典型用法示例:
 *   第一个 FileLogger 将日志输出到 stderr 上。
 *   第二个 FileLogger 将日志输出到文件。
 *   建议将这段代码放到 main 函数的开头处,但是要在 QCoreApplication 或 QApplication 之后。
 *     LoggerController logger;
 *     logger.attach(new FileLogger("stderr",
 *                               FileLogger::E_DEBUG |
 *                               FileLogger::E_INFO |
 *                               FileLogger::E_WARNING |
 *                               FileLogger::E_CRITICAL |
 *                               FileLogger::E_FATAL));
 *  logger.attach(new FileLogger("d:/log2.txt"));
 *  logger.startLogging();
*/
#include <QtCore/QString>
#include <QtCore/QFile>
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QDebug>
#include <QtCore/QMessageLogContext>
class FileLogger
{
public:
    enum LEVEL{E_DEBUG = 1, E_INFO = 2, E_WARNING = 4, E_CRITICAL = 8, E_FATAL = 16};
    FileLogger(QString name, LEVEL level);
    FileLogger(QString name = "stderr", bool debug=false, bool info=true, bool warning=true, bool critical=true, bool fatal=true);
    virtual ~FileLogger();
    /**
     * @brief setFileName 设置日志存储的文件名
     * @param name 日志存储的文件名,如果为 "stderr" 则输出到 stderr
     * @return
     */
    bool setFileName(QString name = "stderr");
    /**
     * @brief setLogLevel 设置哪些级别的信息要输出到文件
     * @param level 可以为 E_DEBUG、E_INFO、E_WARNING、E_CRITICAL、E_FATAL 或者这些项的组合(bit or)
     *              没有设置的 level 则不输出日志
     */
    void setLogLevel(LEVEL level);
    /**
     * @brief setLogLevel 设置哪些级别的信息要输出到文件
     * @param debug  true 表示 qDebug 信息输出到日志
     * @param info   true 表示 qInfo 信息输出到日志
     * @param warning  true 表示 qWarning 信息输出到日志
     * @param critical true 表示 qCritical 信息输出到日志
     * @param fatal    true 表示 qFatal 信息输出到日志
     */
    void setLogLevel(bool debug = false, bool info = true, bool warning = true, bool critical= true, bool fatal = true);
    virtual void writeLog(QtMsgType type, const QMessageLogContext &context, const QString &msg);
private:
    QString messageType(QtMsgType type);
    FileLogger(FileLogger &f) {Q_UNUSED(f);} // 不能被拷贝
    FileLogger& operator=( FileLogger &f) {Q_UNUSED(f);} // 不能被拷贝
private:
    QFile m_file;
    QMap<QtMsgType, bool> m_level;
    bool m_where;
};
class LoggerController
{
public:
    LoggerController(){}
    ~LoggerController();
    /**
     * @brief startLogging 启动日志系统,在这之后所有的调试信息发送到对应的 FileLogger
     */
    void startLogging();
    /**
     * @brief attach 在日志系统中注册一个新的 FileLogger
     * @param m_currentLogger
     */
    void attach(FileLogger *m_currentLogger);
    void detach(FileLogger *m_currentLogger);
private:
    static void writeLog(QtMsgType type, const QMessageLogContext &context, const QString &msg);
    static LoggerController * m_currentLogger;
    QList<FileLogger *> m_list;
};
#endif // MESSAGELOGGER_H


#include "MessageLogger.h"
#include <QtCore/QDateTime>
#include <QtCore/QTextStream>
FileLogger::FileLogger(QString name, bool debug, bool info, bool warning, bool critical, bool fatal)
    :m_where(true)
{
    setFileName(name);
    setLogLevel(debug, info, warning, critical, fatal);
}
FileLogger::FileLogger(QString name, LEVEL level)
:m_where(false)
{
    setFileName(name);
    setLogLevel(level);
}
FileLogger::~FileLogger()
{
    m_file.close();
}
bool FileLogger::setFileName(QString name)
{
    m_file.close();
    if(name == "stderr")
    {
        return m_file.open(stderr, QIODevice::WriteOnly);
    }
    else
    {
        m_file.setFileName(name);
        return m_file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text);
    }
}
void FileLogger::setLogLevel(LEVEL level)
{
    m_level[QtDebugMsg] = static_cast<bool> (level & E_DEBUG);
    m_level[QtInfoMsg] = static_cast<bool> (level & E_INFO);
    m_level[QtWarningMsg] = static_cast<bool> (level & E_WARNING);
    m_level[QtCriticalMsg] = static_cast<bool> (level & E_CRITICAL);
    m_level[QtFatalMsg] = static_cast<bool> (level & E_FATAL);
}
void FileLogger::setLogLevel(bool debug, bool info, bool warning, bool critical, bool fatal)
{
    m_level[QtDebugMsg] = debug;
    m_level[QtInfoMsg] = info;
    m_level[QtWarningMsg] = warning;
    m_level[QtCriticalMsg] = critical;
    m_level[QtFatalMsg] = fatal;
}
void FileLogger::writeLog(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    if(!m_level[type])
    {
        return;
    }
    QString strTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
    QTextStream logfile(&m_file);
    logfile << strTime << ", ";
    logfile << messageType(type) << ", ";
    logfile << msg;
    if(context.file && m_where)
    {
        logfile <<  ", (" << context.file << ":" << context.line << ", " << context.function << ")\n";
    }
    else
    {
        logfile << endl;
    }
    if(type == QtFatalMsg)
    {
        abort();
    }
}
QString FileLogger::messageType(QtMsgType type)
{
    QString str;
    switch (type)
    {
    case QtDebugMsg:
        str = "[D]";
        break;
    case QtInfoMsg:
        str = "[I]";
        break;
    case QtWarningMsg:
        str = "[W]";
        break;
    case QtCriticalMsg:
        str = "[C]";
        break;
    case QtFatalMsg:
        str = "[F]";
    }
    return str;
}
void LoggerController::attach(FileLogger *logger)
{
    m_list.append(logger);
}
void LoggerController::detach(FileLogger *logger)
{
    if(logger)
    {
        m_list.removeOne(logger);
        delete logger;
    }
}
void LoggerController::startLogging()
{
    m_currentLogger = this;
    qInstallMessageHandler(LoggerController::writeLog);
}
LoggerController::~LoggerController()
{
    qDeleteAll(m_list);
}
LoggerController* LoggerController::m_currentLogger = nullptr;
void LoggerController::writeLog(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    if( m_currentLogger )
    {
        QList<FileLogger *> &list = m_currentLogger->m_list;
        QList<FileLogger *>::const_iterator i;
        for (i = list.cbegin(); i != list.cend(); ++i)
        {
            (*i)->writeLog(type, context, msg);
        }
    }
}


简单使用


#include "mainwindow.h"
#include <QApplication>
#include <QSettings>
#include <QString>
#include <QFileInfo>
#include <QTime>
#include <QDir>
#include "cglobal.h"
#include "MessageLogger.h"
#include "utils.h"
int main(int argc, char *argv[])
{
     //自适应高分辨率(DPI),不确定是否管用
     #if (QT_VERSION >= QT_VERSION_CHECK(5,9,0))
         QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
         QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
     #endif
    QApplication a(argc, argv);
    a.setFont(QFont("Microsoft Yahei", 9));//设置应用程序字体
    a.setWindowIcon(QIcon(":/main.ico"));//设置应用程序图标
    mkDirIfNotExist();
    //打印日志到文件中
    LoggerController logger;
    logger.attach(new FileLogger("stderr",
                               FileLogger::E_DEBUG,
                               FileLogger::E_INFO ,
                               FileLogger::E_WARNING ,
                               FileLogger::E_CRITICAL,
                               FileLogger::E_FATAL));
    QString dateTime = QDateTime::currentDateTime().toString("yyyy-MM-dd_hhmmss");
    QString logName = LOG_PATH+dateTime+"_log.txt";
    //日志文件输入以下级别的日志
    FileLogger::LEVEL level =  (FileLogger::LEVEL)(FileLogger::E_INFO | FileLogger::E_WARNING);
    FileLogger *lg = new FileLogger(logName,level);
    logger.attach(lg);
    logger.startLogging();
    qInfo("程序启动...");
    qInfo(APP_VERION);
    MainWindow w;
    w.show();
    return a.exec();
}
void mkDirIfNotExist(){
    QDir *folder = new QDir;
    bool exist,ok = false;
    exist = folder->exists(LOG_PATH);
    if(!exist){
        ok = folder->mkdir(LOG_PATH);
        if(!ok){
            qDebug("Error,创建日志文件夹失败");
        }
    }
    exist = folder->exists(PIC_PATH);
    if(!exist){
        ok = folder->mkdir(PIC_PATH);
        if(!ok){
            qDebug("Error,创建图片文件夹失败");
        }
    }
}


引用


QT 轻量级的LOG日志库_Duffy_Gallagher的博客-CSDN博客_qt日志库


Qt轻量级日志库QsLog的使用_百里杨的博客-CSDN博客_qt 日志库

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
5月前
|
Linux iOS开发 开发者
Qt问题(二):无法定位程序输入点于动态链接库
动态链接库(Dynamic Link Library,简称DLL)是一种可执行文件格式,常见于Windows操作系统中,而在Linux和macOS等其他操作系统中,相似的概念通常被称为共享库(Shared Library)。动态链接库允许程序在运行时加载所需的代码和数据,而不是在编译时静态链接到应用程序中。这种方式带来了几个重要的优点:
517 3
|
4月前
|
前端开发 C语言 开发者
领导被我的花式console.log吸引了!直接写入公司公共库!
【8月更文挑战第23天】领导被我的花式console.log吸引了!直接写入公司公共库!
45 2
领导被我的花式console.log吸引了!直接写入公司公共库!
|
4月前
|
JSON 中间件 Go
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
本文详细介绍了如何在Go项目中集成并配置Zap日志库。首先通过`go get -u go.uber.org/zap`命令安装Zap,接着展示了`Logger`与`Sugared Logger`两种日志记录器的基本用法。随后深入探讨了Zap的高级配置,包括如何将日志输出至文件、调整时间格式、记录调用者信息以及日志分割等。最后,文章演示了如何在gin框架中集成Zap,通过自定义中间件实现了日志记录和异常恢复功能。通过这些步骤,读者可以掌握Zap在实际项目中的应用与定制方法
156 1
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
|
3月前
|
存储 运维 监控
超级好用的C++实用库之日志类
超级好用的C++实用库之日志类
49 0
|
4月前
|
Linux API
在Linux中,程序产生了库日志虽然删除了,但磁盘空间未更新是什么原因?
在Linux中,程序产生了库日志虽然删除了,但磁盘空间未更新是什么原因?
|
4月前
|
存储 JSON 前端开发
一文搞懂 Go 1.21 的日志标准库 - slog
一文搞懂 Go 1.21 的日志标准库 - slog
157 2
|
4月前
|
JSON Go API
一文搞懂 Golang 高性能日志库 - Zap
一文搞懂 Golang 高性能日志库 - Zap
334 2
|
5月前
|
Oracle 关系型数据库 Linux
讲解linux下的Qt如何编译oracle的驱动库libqsqloci.so
通过这一连串的步骤,可以专业且有效地在Linux下为Qt编译Oracle驱动库 `libqsqloci.so`,使得Qt应用能够通过OCI与Oracle数据库进行交互。这些步骤适用于具备一定Linux和Qt经验的开发者,并且能够为需要使用Qt开发数据库应用的专业人士提供指导。
172 1
讲解linux下的Qt如何编译oracle的驱动库libqsqloci.so
|
4月前
|
存储 安全 Python
[python]使用标准库logging实现多进程安全的日志模块
[python]使用标准库logging实现多进程安全的日志模块
|
5月前
|
测试技术 UED 存储
SLS Prometheus存储问题之在使用内置降采样时,SLS自动选择适配的指标库该如何解决
SLS Prometheus存储问题之在使用内置降采样时,SLS自动选择适配的指标库该如何解决