二 log4qt介绍与用法

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
### 回答1: 自启exe程序无法写入log4qt的原因可能有以下几点: 1. 权限不足:自启动程序可能以较低的权限运行,而log4qt需要写入系统文件或文件夹,因此可能因权限问题而无法写入。解决方法是以管理员权限运行自启动程序,或者修改文件夹权限以允许程序写入log4qt日志文件。 2. 文件路径错误:自启动程序使用的文件路径可能与log4qt配置文件中的路径不一致,导致无法找到或写入日志文件。解决方法是检查自启动程序中使用的文件路径是否正确,并确保与log4qt配置文件中的路径一致。 3. 初始化顺序问题:可能在自启动程序运行时,log4qt的初始化尚未完成,导致无法写入日志。解决方法是在自启动程序中延迟初始化log4qt,等待其完全初始化后再进行日志写入操作。 4. log4qt配置错误:检查log4qt的配置文件是否正确,包括日志文件路径、日志级别等配置项是否正确设置。确保配置文件的正确性可以通过手动运行程序进行验证。 综上所述,解决自启exe程序无法写入log4qt的问题,需要检查权限、文件路径、初始化顺序和配置文件等方面的问题,并逐步进行排查和修复。 ### 回答2: 自启exe程序无法写入log4qt的原因可能有以下几点: 1. 权限问题:自启动程序可能以不同的权限运行,可能对目标文件夹没有写入权限。你可以检查目标文件夹的权限设置,确保程序以足够的权限运行。 2. 文件路径问题:log4qt可能配置了特定的文件路径,而自启动程序的当前目录可能与你预期的不一致。你需要确认自启动程序的当前目录,并根据需要修改log4qt的文件路径配置。 3. 屏幕输出问题:如果你的自启动程序以服务或后台运行的方式启动,可能无法将日志输出到屏幕。在这种情况下,你可以尝试将日志输出到一个指定的文件,然后通过其他方式查看日志内容。 4. 配置问题:log4qt的配置文件可能存在问题,导致无法正常写入日志。你可以检查配置文件的语法、路径等相关配置,确保其正确性。 针对以上问题,你可以按照以下步骤进行排查和解决: 1. 确认自启动程序的权限是否足够,如果不足,可以尝试提升其权限。 2. 检查log4qt的文件路径配置,确保其与自启动程序的当前目录一致。 3. 尝试将日志输出到指定文件,或通过其他方式查看日志内容。 4. 检查log4qt的配置文件,确保其正确配置。 如果问题仍然存在,请提供更多详细信息,以便进一步分析和解决。 ### 回答3: 自启exe程序无法写入log4qt可能是由于以下几个原因导致的: 1. 权限问题:自启动程序可能没有足够的权限来写入log4qt。在某些操作系统中,自启动程序以较低权限运行,可能无法访问或写入特定目录或文件。请确保自启动程序具有足够的权限来写入log4qt。 2. 路径问题:自启动程序可能无法正确设置log4qt的写入路径。log4qt通常需要指定写入日志的目录或文件的路径。确保自启动程序正确设置了log4qt的写入路径,并且该路径是有效的。 3. 环境问题:自启动程序可能无法正确设置环境变量或加载所需的库文件。log4qt可能依赖于其他库文件,或者需要特定的环境变量才能正常工作。请确保自启动程序正确设置了所需的环境变量,并且加载了所有必要的库文件。 4. 代码问题:自启动程序可能存在与log4qt集成的代码问题。请检查自启动程序的代码,确保正确初始化并使用log4qt。可能需要阅读log4qt的文档或寻求相关技术支持来解决问题。 需要根据具体情况进行排查和调试,可以逐步验证以上可能导致问题的原因,并根据具体的错误信息或日志进行进一步的排查和修复。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值