QT随手记:log4qt在多进程的应用程序中输出多个日志文件

一、背景

本文适合使用过log4qt的同学阅读。log4qt的使用是很简单的,但某天遇到一个比较少见的需求,应用程序中创建了两个进程,而新的进程的日志期望输出到不同文件名的日志中。本文记录了解决此需求的过程,顺带阅读了部分log4qt的源码。使用的是2021年9月的log4qt主版本,下载地址 https://github.com/MEONMedical/Log4Qt

二、单进程输出日志的情况

先了解原来单进程输出日志的方法,才好理解多进程的不同。原先是通过配置文件log4qt.properties进行文件的生成配置

#设置储存log文件的根目录
logpath=./logs

log4j.reset=true
log4j.Debug=WARN
log4j.threshold=NULL
#设置是否监听QDebug输出的字符串
log4j.handleQtMessages=true
#在运行中,是否监视此文件配置的变化
log4j.watchThisFile=false

#设置终端打印记录器
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.target=STDOUT_TARGET
log4j.appender.console.layout=org.apache.log4j.TTCCLayout
log4j.appender.console.layout.dateFormat=dd.MM.yyyy hh:mm:ss.zzz
log4j.appender.console.layout.contextPrinting=true
log4j.appender.console.threshold=ALL

#设置一个每日储存一个log文件的记录器
log4j.appender.daily=org.apache.log4j.DailyFileAppender
log4j.appender.daily.file=${logpath}/propertyconfigurator.log
log4j.appender.daily.appendFile=true
log4j.appender.daily.datePattern=_yyyy_MM_dd
log4j.appender.daily.keepDays=7
log4j.appender.daily.layout=${log4j.appender.console.layout}
log4j.appender.daily.layout.dateFormat=${log4j.appender.console.layout.dateFormat}
log4j.appender.daily.layout.contextPrinting=${log4j.appender.console.layout.contextPrinting}

# 配置一个滚动文件记录器
log4j.appender.rolling=org.apache.log4j.RollingFileAppender
log4j.appender.rolling.file= ${logpath}/propertyconfigurator_rolling.log
log4j.appender.rolling.appendFile=true
log4j.appender.rolling.maxFileSize= 20MB
log4j.appender.rolling.maxBackupIndex= 2
log4j.appender.rolling.layout=${log4j.appender.console.layout}
log4j.appender.rolling.layout.dateFormat=${log4j.appender.console.layout.dateFormat}
log4j.appender.rolling.layout.contextPrinting=${log4j.appender.console.layout.contextPrinting}

#设置根Logger的输出log等级为All
#设置Log输出的几种输出源(appender):console, daily, rolling
log4j.rootLogger=ALL, daily

# 给“LoggerObjectPrio”这个类的Logger定义log输出等级为Error,
# 给“LoggerObjectPrio”这个类的Logger定义log输出源:daily, console
log4j.logger.LoggerObjectPrio=ERROR, rolling
#设置为false,表示“LoggerObjectPrio”这个类的logger不继承的rootLogger输出源(appender)
log4j.additivity.LoggerObjectPrio=false

在应用程序中使用宏定义日志器。logger是静态方法名称,可以自己命名。myLogerManage是自己日志器的名称,也可以自己命名。

LOG4QT_DECLARE_STATIC_LOGGER(logger, myLogerManage)

然后使用logger是静态方法写日志,logger()->info(“输出日志”)。单个日志这样简单使用就可以了。
通过源码跟踪可以发现,调用logger()静态方法会根据日志器名称myLogerManage去返回对应的日志器。
跟踪源码都此处,找到名字对应的日志器就返回了。
在这里插入图片描述

三、多进程输出多个日志文件

根据上文中的发现,只要创建多个日志器,并分别配置不同的路径下的DailyFileAppender即可达到目的。如创建两个

LOG4QT_DECLARE_STATIC_LOGGER(logger1, myLogerManage1)
LOG4QT_DECLARE_STATIC_LOGGER(logger2, myLogerManage2)

创建logger1和logger2的输出appender

//log_saving_dir_abs_path 是文件的目录完整路径
void SetupLog4QtByCodingWithLogSavingDirAbsPath(QString log_saving_dir_abs_path, Log4Qt::Logger* p)
{
    QString absPath = log_saving_dir_abs_path;
    if(!QDir::isAbsolutePath(absPath)) {
        absPath = QDir::cleanPath(qApp->applicationDirPath() + "/" + log_saving_dir_abs_path);
    }
    Q_ASSERT(QDir::isAbsolutePath(absPath));

    QDir().mkpath(absPath);
    if (!QDir().exists(absPath)) {
        qDebug("Failed to set log path which not exists: %s", qPrintable(absPath));
        return;
    }

    auto *layout = new Log4Qt::TTCCLayout();
    layout->setName(QStringLiteral("My Layout"));
    layout->setDateFormat("dd.MM.yyyy hh:mm:ss.zzz");
    layout->activateOptions();

    Log4Qt::ConsoleAppender *consoleAppender =
            new Log4Qt::ConsoleAppender(layout, Log4Qt::ConsoleAppender::STDOUT_TARGET);
    consoleAppender->setName(QStringLiteral("My console Appender"));
    consoleAppender->activateOptions();
    p->addAppender(consoleAppender);

    //Create a rolling file appender
    Log4Qt::RollingFileAppender *rollingFileAppender =
            new Log4Qt::RollingFileAppender(layout, absPath + "/basic.log", true);
    rollingFileAppender->setName(QStringLiteral("My rolling file appender"));
    rollingFileAppender->setMaximumFileSize(20 * 1024 * 1024);//default is 10 MB (10 * 1024 * 1024).
    rollingFileAppender->setThreshold(Log4Qt::Level::Value::INFO_INT);//sub-log-level
    rollingFileAppender->activateOptions();
    p->addAppender(rollingFileAppender);


    // Create a file appender
    Log4Qt::DailyFileAppender *dailyfileAppender =
            new Log4Qt::DailyFileAppender(layout, absPath + "/propertyconfigurator.log", "_yyyy_MM_dd",7);//true for append
    dailyfileAppender->setName(QStringLiteral("My dailyfile appender"));
    dailyfileAppender->activateOptions();
    p->addAppender(dailyfileAppender);
    
    p->setLevel(Log4Qt::Level::ALL_INT);
      
}

可以在main函数中调用创建路径及相应文件

//使用纯代码配置Log4Qt
    QString std_base_path =  QCoreApplication::applicationDirPath();
    QString my_log_path = std_base_path + "/logs1";
    SetupLog4QtByCodingWithLogSavingDirAbsPath(my_log_path,logger());

    QString my_log_path2 = std_base_path + "/logs2";
    SetupLog4QtByCodingWithLogSavingDirAbsPath(my_log_path2,logger2());

在main函数中调用SetupLog4QtByCodingWithLogSavingDirAbsPath之后,可以使用如下测试代码测试验证

logger1()->info("我是loger1");
logger2()->info("我是loger2");

测试结果截图
在这里插入图片描述
在这里插入图片描述

四、结语

如上所述,实现了在应用程序中将不同进程的日志输出到不同日志文件的需求。

五、拓展

如果要将捕捉的qt日志也输出不同文件中,得修改此处源码

void LogManager::qtMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message)
{
    Level level;
    switch (type)
    {
    case QtDebugMsg:
        level = Level::DEBUG_INT;
        break;
    case QtWarningMsg:
        level = Level::WARN_INT;
        break;
    case QtCriticalMsg:
        level = Level::ERROR_INT;
        break;
    case QtFatalMsg:
        level = Level::FATAL_INT;
        break;
    case QtInfoMsg:
        level = Level::INFO_INT;
        break;
    default:
        level = Level::TRACE_INT;
    }
    LoggingEvent loggingEvent = LoggingEvent(instance()->qtLogger(),
                                             level,
                                             message,
                                             MessageContext(context.file, context.line, context.function),
                                             QStringLiteral("Qt ") % context.category);

    instance()->qtLogger()->log(loggingEvent);


    // Qt fatal behaviour copied from global.cpp qt_message_output()
    // begin {

    if (isFatal(type))
        qt_message_fatal(type, context, message);

    // } end
}

做些特殊处理,把instance()->qtLogger()改为自己的日志器。

另外的发现

分别配置两个不同名称的配置文件log4qt.properties,然后使用如下代码配置一下,可能也能实现,仅是可能,没有再深入看了。

QString configFile = QCoreApplication::applicationDirPath() + QStringLiteral("/log4qt1.properties");
if (QFile::exists(configFile))
        Log4Qt::PropertyConfigurator::configureAndWatch(configFile);
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值