qt 程序中,有简单的调试信息,又有重要的日志信息,如何把qDebug()、qWarning()等调试信息输出到文件?又如何即输出在终端又同时输出在文件呢?
log4qt给你灵活自由配置!
完整代码在下面。
log4qt封装

1 简单日志系统qInstallMessageHandler

实现自定义的qInstallMessageHandler
实现不同等级的日志打印,每天产生一个新的日志文件,当然也可以都打印在一个文件里面,简单改下即可

#include <QApplication>
#include <iostream>
#include <QDebug>
#include <QtMessageHandler>
#include <QFile>
#include <QDir>
using namespace std;
//写入信息到文件
void WriteLog(QString str, QString LogType)
{
    QString fileFolder= qApp->applicationDirPath()+"/log/"+QDateTime::currentDateTime().toString("yyyy-MM-dd");
    QDir dir(fileFolder);
    if(!dir.exists())
    {
        dir.mkpath(fileFolder);
    }
    QString filePath=QString("%1/%2.log").arg(fileFolder).arg(LogType);
    QString strToWrite=QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
    strToWrite.append(str);

    QFile file(filePath);
    file.open(QIODevice::WriteOnly | QIODevice::Append);
    QTextStream text_stream(&file);
    text_stream <<strToWrite;
    file.flush();
    file.close();
    //打印到控制台
    std::cout << strToWrite.toLocal8Bit().constData() << std::endl;
}
//注册函数
void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    QString txtMessage = "";
    QString messageType = "";
    switch (type)    {
    case QtDebugMsg:    //调试信息提示
        messageType = "Debug";
        txtMessage = QString("Debug: %1 (%2:%3, %4)\n").arg(msg).arg(context.file).arg(QString::number(context.line)).arg(context.function);
        break;
    case QtInfoMsg:
        messageType = "Info";
        txtMessage = QString("Warning: %1 (%2:%3, %4)\n").arg(msg).arg(context.file).arg(QString::number(context.line)).arg(context.function);
        break;
    case QtWarningMsg:    //一般的warning提示
        messageType = "Waring";
        txtMessage = QString("Warning: %1 (%2:%3, %4)\n").arg(msg).arg(context.file).arg(QString::number(context.line)).arg(context.function);
        break;
    case QtCriticalMsg:    //严重错误提示
        messageType = "Critical";
        txtMessage = QString("Critical: %1 (%2:%3, %4)\n").arg(msg).arg(context.file).arg(QString::number(context.line)).arg(context.function);
        //PostErrorMessage(txtMessage,messageType);
        break;
    case QtFatalMsg:    //致命错误提示
        messageType = "Fatal";
        txtMessage = QString("Fatal: %1 (%2:%3, %4)\n").arg(msg).arg(context.file).arg(QString::number(context.line)).arg(context.function);
        abort();
    }
    WriteLog(txtMessage, messageType);
}
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    //注册监听级别函数
    qInstallMessageHandler(myMessageOutput);
    qDebug() << "debug1";
    qInfo() <<"info1";
    qWarning() << "warni";
    qFatal("error");

    return a.exec();
}

qtcreater 输出如下:
在这里插入图片描述

日志文件如下:
在这里插入图片描述

2 log4qt简单使用

  1. 下载
    Log4Qt官网下载(版本很老)
    GitHub(推荐)
  2. 加载到项目
    可以用源码自行编译成库使用,或直接在项目内添加源码。
    1 解压log4qt到目标文件夹,如D:\Qt\下;
    2 qt项目的pro文件中加入一行:include(D:\Qt\log4qt\src\log4qt\log4qt.pri),
    pri文件会将需要的h文件和cpp文件加入到qt项目中;
  3. 简单使用
#include "logger.h"
#include "basicconfigurator.h" 

Log4Qt::BasicConfigurator::configure();
Log4Qt::Logger * log = Log4Qt::Logger::rootLogger();
log->debug("debug!");
log->info("information!");
log->warn("warn"); 
log->log(logLevel, data); 
//logLevel可以是上面的warn,info,debug等,data是需要输出的数据
  1. 配置Log4Qt
#include <QApplication>
#include "logger.h"
#include "propertyconfigurator.h" 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv); 
    //配置文件路径
    Log4Qt::PropertyConfigurator::configure(a.applicationDirPath()  
    + "/log4qt.conf");  
    Log4Qt::Logger *a1 = Log4Qt::Logger::logger("A1");
    a1->debug("the message of log");
    return a.exec();
}

log4qt.conf是配置文件,里面存放Log4Qt的配置信息

指定扩展器

log4j.logger.A1=DEBUG,CONSOLE,A1
####每天生产一个文件
log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender

日志文件路径

log4j.appender.A1.File=logs/a1.txt

输出DEBUG级别以上的日志

log4j.appender.D.Threshold = DEBUG

日志布局类型(自由模式)

log4j.appender.A1.layout=org.apache.log4j.PatternLayout

日志格式

log4j.appender.A1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c] [%p] - %m%n

2 log4qt定制用法

配置了终端和日志文件同时输出
main.cpp

#include <QApplication>
#include "qblog4qt.h"
#include <QDebug>
#include <QJsonObject>
#include <QJsonDocument>
int main(int argc, char* argv[])
{
    QApplication a(argc,argv);

    QString str = "String";
    char* p = "char*";
    int i = 1;
    Log4Info(str);
    Log4Info(str,p);
    Log4Info(str,p,i);

    QVariantMap dataMap;
    QVariantMap binaryMap;
    binaryMap.insert("completeBinarysId","m_curUUid");
    dataMap.insert("binarysState",binaryMap);
    QJsonObject dataobject = QJsonObject::fromVariantMap(dataMap);
    QByteArray t("zzzzzzz");
    qDebug() << "test";
    Log4qt << str;
    Log4qt << QString(QJsonDocument(dataobject).toJson());
    Log4qt << QString(t);
    return 0;
}

log4qt类封装:
qblog4qt.h

#ifndef QBLOG4QT_H
#define QBLOG4QT_H

#include <QObject>
#include "log4qt/logger.h"
#include "log4qt_global.h"
#include "log4qt/logmanager.h"
#include "log4qt/propertyconfigurator.h"

#define Log4Debug QBLog4Helper(__FILE__, __LINE__, Q_FUNC_INFO).debug
#define Log4Info  QBLog4Helper(__FILE__, __LINE__, Q_FUNC_INFO).info
#define Log4Warn  QBLog4Helper(__FILE__, __LINE__, Q_FUNC_INFO).warn
#define Log4Error QBLog4Helper(__FILE__, __LINE__, Q_FUNC_INFO).error
#define Log4Fatal QBLog4Helper(__FILE__, __LINE__, Q_FUNC_INFO).fatal
#define Log4qt    QBLog4Helper(__FILE__, __LINE__, Q_FUNC_INFO)


class QBLog4Qt : public QObject
{
    Q_OBJECT
    LOG4QT_DECLARE_QCLASS_LOGGER

public:
    explicit QBLog4Qt(QObject *parent = 0);
    ~QBLog4Qt();

    static QBLog4Qt *instance();
    virtual void debug(const QString& log){logger()->debug(log);}
    virtual void info (const QString& log){logger()->info(log);}
    virtual void warn (const QString& log){logger()->warn(log);}
    virtual void error(const QString& log){logger()->error(log);}
    virtual void fatal(const QString& log){logger()->fatal(log);}
};


class QBLog4Helper{
    Q_DISABLE_COPY(QBLog4Helper)

public:
    Q_DECL_CONSTEXPR QBLog4Helper() : version(1), line(0), file(0), function(0) {}
    QBLog4Helper(const char *fileName, int lineNumber, const char *functionName);
    enum LogType{LGDebugMsg, LGInfoMsg, LGWarningMsg, LGErrorMsg, LGFatalMsg};

    QString TemplateParameter (){ return ""; }
    template <typename T, typename ... Args>
    QString TemplateParameter(T head, Args ... args) { return QString("%1 ").arg(head) + TemplateParameter(args...); }

    template <typename T, typename ... Args>
    void debug(T head, Args ... args){
        QString logmsg = QString("%1 ").arg(head) + TemplateParameter(args...);
        writelogToLocal(LGDebugMsg,logmsg);
    }

    template <typename T, typename ... Args>
    void info(T head, Args ... args){
        QString logmsg = QString("%1 ").arg(head) + TemplateParameter(args...);
        writelogToLocal(LGInfoMsg,logmsg);
    }

    template <typename T, typename ... Args>
    void warn(T head, Args ... args){
        QString logmsg = QString("%1 ").arg(head) + TemplateParameter(args...);
        writelogToLocal(LGWarningMsg,logmsg);
    }

    template <typename T, typename ... Args>
    void error(T head, Args ... args){
        QString logmsg = QString("%1 ").arg(head) + TemplateParameter(args...);
        writelogToLocal(LGErrorMsg,logmsg);
    }

    template <typename T, typename ... Args>
    void fatal(T head, Args ... args){
        QString logmsg = QString("%1 ").arg(head) + TemplateParameter(args...);
        writelogToLocal(LGFatalMsg,logmsg);
    }

    virtual void writelogToLocal(LogType logtype, const QString& logmsg);
    virtual void copy(const QBLog4Helper &logContext){}

    template <typename T>
    inline QBLog4Helper &operator<<(T logmsg) {
        writelogToLocal(LGInfoMsg,QString("%1").arg(logmsg));
        return *this;
    }

    int version;
    int line;
    const char *file;
    const char *function;
};

#endif // QBLOG4QT_H

qblog4qt.cpp

#include "qblog4qt.h"
#include <QApplication>
#include <QStandardPaths>
#include <QSettings>
#include <QDir>
#include <QThread>
#include <QFileInfo>
QBLog4Qt::QBLog4Qt(QObject *parent) :
    QObject(parent)
{
    QString outpath = QCoreApplication::applicationDirPath() + "/z021.log";
    QString configPath = QApplication::applicationDirPath() + "/log4qt.conf";
    if(!QFile::exists(configPath)){//不存在配置文件 创建默认配配置文件
        QSettings configSet(configPath,QSettings::IniFormat);
        configSet.setIniCodec("UTF-8");
        //console
        configSet.setValue("log4j.rootLogger",QStringList()<<"INFO"<<"A1"<<"A2");
        configSet.setValue("log4j.appender.A1","org.apache.log4j.ConsoleAppender");
        configSet.setValue("log4j.appender.A1.layout","org.apache.log4j.PatternLayout");
        configSet.setValue("log4j.appender.A1.layout.ConversionPattern","%d{yyyy-MM-dd HH:mm:ss} %m%n");
        //file
        configSet.setValue("log4j.appender.A2","org.apache.log4j.FileAppender");
        configSet.setValue("log4j.appender.A2","org.apache.log4j.RollingFileAppender");
        configSet.setValue("log4j.appender.A2.File",outpath);
        configSet.setValue("log4j.appender.A2.AppendFile","true");
        configSet.setValue("log4j.appender.A2.MaxFileSize","4096KB");
        configSet.setValue("log4j.appender.A2.MaxBackupIndex","3");
        configSet.setValue("log4j.appender.A2.layout","org.apache.log4j.PatternLayout");
        configSet.setValue("log4j.appender.A2.layout.ConversionPattern","%d{yyyy-MM-dd HH:mm:ss} %m%n");
        configSet.sync();
    }else{// 存在修改日志保存路径
        QSettings configSet(configPath,QSettings::IniFormat);
        configSet.setIniCodec("UTF-8");
        configSet.setValue("log4j.appender.A2.File",outpath);
        configSet.sync();
    }

    Log4Qt::PropertyConfigurator::configure(configPath);
    Log4Qt::LogManager::setHandleQtMessages(true);
    logger()->info("start used log4qt!");
}

QBLog4Qt::~QBLog4Qt()
{
    logger()->info("stop used log4qt!");
}

QBLog4Qt *QBLog4Qt::instance()
{
    static QBLog4Qt obj;
    return &obj;
}


QBLog4Helper::QBLog4Helper(const char *fileName, int lineNumber, const char *functionName)
       : version(1)
       , line(lineNumber)
       , file(fileName)
       , function(functionName)
{
}

void QBLog4Helper::writelogToLocal(QBLog4Helper::LogType logtype, const QString &log)
{
    QString threadText = QStringLiteral("0x%1").arg(quintptr(QThread::currentThreadId()));
    QString sfile(file);
#ifdef Q_OS_WIN
    sfile = sfile.right(sfile.length() - (sfile.lastIndexOf("\\")+1));
#endif

#ifdef Q_OS_LINUX
    sfile = sfile.right(sfile.length() - (sfile.lastIndexOf("/")+1));
#endif

    QString sFun(function);
    sFun = sFun.mid(sFun.indexOf(" ")+1,sFun.indexOf("(")-sFun.indexOf(" ")-1);
    QString filter = QString("[%1] [%2 line(%3) pid(%4)] ").arg(sfile).arg(sFun).arg(line).arg(threadText);

    switch (logtype) {
    case LGDebugMsg: QBLog4Qt::instance()->debug(filter+log);
        break;
    case LGInfoMsg: QBLog4Qt::instance()->info(filter+log);
        break;
    case LGWarningMsg: QBLog4Qt::instance()->warn(filter+log);
        break;
    case LGErrorMsg: QBLog4Qt::instance()->error(filter+log);
        break;
    case LGFatalMsg: QBLog4Qt::instance()->fatal(filter+log);
        break;
    default: QBLog4Qt::instance()->info(filter+log);
        break;
    }
}

3 log4qt类说明

  1. Layout简介
    Log4Qt提供了多种Layout对象,用于格式化日志输出,指定日志级别、线程名称、Logger名称、日期时间等信息。

Layout类是Log4Qt API中的抽象类。 PatternLayout:根据一个模式字符串输出日志事件;
SimpleLayout:输出日志事件的级别和消息;
TTCCLayout:输出日志事件的时间、线程名称、Logger名称和嵌套的诊断上下文信息。
PatternLayout和TTCCLayout通过PatternFormatter来实现格式化。当PatternFormatter解析模式字符串时,会根据发现的信息创建一个PatternConverter链,每个PatternConverter会处理LoggingEvent的某个成员。
转换字符:用于指定数据的类型,例如:类别、级别、日期、线程名称。Log4Qt中的转换字符有: c:Logger 名称。
d{format_string}:日期。参数 format_string 可选,用于格式化日期。 m:消息内容 p:消息级别
r:启动程序的相对时间 t:线程名称 x:NDC(嵌套的诊断上下文)名称 X:MDC(映射的诊断上下文)名称 F:文件名称 M:方法名称
L:行号 l:位置信息 n:平台相关的行分隔符,Windows:\r\n,Linux:\n

  1. NDC简介

NDC(Nested Diagnostic Context)即嵌套诊断上下文,是log4J用于存储上下文信息(context
information)的类,NDC采用栈的机制push和pop上下文,每个线程有独立的上下文,如果要存储的上下文信息是堆栈式的在选择NDC。

  1. MDC简介

MDC(Mapped Diagnositc Context)即映射诊断上下文,是log4J用于存储上下文信息(context
information)的类,MDC内部采用Hash容器实现,是线程独立的,但一个子线程会自动获得一个父线程MDC的copy,如果要存储的上下文信息是key/value式的选择MDC。

  1. PatternLayout

PatternLayout是Layout的一个派生类,如果想生成基于模式匹配的特定格式的日志信息,可以使用PatternLayout来进行格式化。
PatternLayout的枚举ConversionPattern定义了两个常用的模式

enum ConversionPattern
{
    DEFAULT_CONVERSION_PATTERN,// "%m,%n"
    TTCC_CONVERSION_PATTERN,//"%r [%t] %p %c %x - %m%n"
};
  1. SimpleLayout

SimpleLayout 是Layout的一个派生类,对日志消息的格式化只包含日志的级别和消息内容。

SimpleLayout示例

#include <QCoreApplication>
#include <log4qt/logger.h>
#include <log4qt/simplelayout.h>
#include <log4qt/consoleappender.h>
#include <log4qt/loggerrepository.h>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 创建SimpleLayout
    Log4Qt::Logger *logger = Log4Qt::Logger::rootLogger();
    Log4Qt::SimpleLayout *layout = new Log4Qt::SimpleLayout();
    layout->setFooter("end");
    layout->setHeader("start");
    layout->activateOptions();

    // 创建ConsoleAppender
    Log4Qt::ConsoleAppender *appender = new Log4Qt::ConsoleAppender(layout, Log4Qt::ConsoleAppender::STDOUT_TARGET);
    appender->activateOptions();
    logger->addAppender(appender);

    logger->setLevel(Log4Qt::Level::DEBUG_INT);
    logger->debug("Debug, Log4Qt!");
    logger->info("Info, Log4Qt!");

    // 关闭 logger
    logger->removeAllAppenders();
    logger->loggerRepository()->shutdown();

    return a.exec();
}
// output:
// start
// DEBUG - Debug, Log4Qt!
// INFO - Info, Log4Qt!
// end
  1. TTCCLayout
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐