Qt的简易日志模块封装

2022-08-11 15:15:25 浏览数 (1)

用于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中包含模块源码即可。 

代码语言:javascript复制
include(Logger/MessageLogger.pri)

MessageLogger.pri文件内容:

代码语言:javascript复制
HEADERS   = $$PWD/MessageLogger.h
SOURCES  = $$PWD/MessageLogger.cpp

INCLUDEPATH  = $$PWD

简易封装 

代码语言:javascript复制
#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
代码语言:javascript复制
#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);
        }
    }

}

简单使用

代码语言:javascript复制
#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 日志库

0 人点赞