若该文为原创文章,未经允许不得转载

各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究

​红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中..​​​​.(点击传送门)​

​​Qt开发专栏:三方库开发技术(点击传送门)​​


前话

       日志系统整理并模块化。


Log4Qt介绍

       Log4Qt是使用Trolltech Qt Framework的Apache Software Foundation Log4j包的C ++端口。它旨在供开源和商业Qt项目使用。


Qt4版本的log4qt

源码下载

当前最新版本为log4qt-0.3.zIP,这源码包最后修改日期为2009年。

       Sourceforge下载地址:​​https://sourceforge.net/projects/log4qt/​


模块化

源码加入日志模块:

       Qt三方库开发技术:log4Qt介绍、编译和使用_#include

       Qt三方库开发技术:log4Qt介绍、编译和使用_日志_02

       解压到当前文件夹:

       Qt三方库开发技术:log4Qt介绍、编译和使用_log4qt_03

将log4qt的源码包含到模块中:

        Qt三方库开发技术:log4Qt介绍、编译和使用_日志_04

     Qt三方库开发技术:log4Qt介绍、编译和使用_#define_05


封装日志类

       封装成独立的日志类,这样不论用什么日志系统只需要改变该类,代码其他模块无需改变,使用单例模式,因log4qt本身是线程安全的,所以不用考虑多线程,下面是封装的log4qt日志类。

Log.h

#ifndef LOG_H
#define LOG_H

#include <QObject>
#include <QMutex>
#include <QMutexLocker>
#include <QCoreApplication>

#include "log4qt/logger.h"
#include "log4qt/basicconfigurator.h"

/************************************************************\
* 类名:Log
* 描述:封装log4qt开源库类
* 注意:模块已带log4qt for qt4 和 qt5两个版本;
* 模块已带log4qt配置文件,分为4级别:DEBUG > INFO > WARN > ERROR
* 信号:
* 函数:
* instance() - 获取日志唯一实例
* 槽函数:
* slot_init() - 初始化加载配置文件
* slot_debug() - 调试级别日志
* slot_info() - 信息级别日志
* slot_warn() - 警告级别日志
* slot_error() - 错误级别日志
*
* 作者:红模仿
* 日期 版本号 描述
* 2019年04月09日 v1.0.0 基础日志模块
\************************************************************/


class Log : public QObject
{
Q_OBJECT
public:
explicit Log(QObject *parent = nullptr);

signals:

public slots:
static Log * instance();

public slots:
void init(QString configFilePath);

public slots:
void debug(QString msg);
void info(QString msg);
void warn(QString msg);
void error(QString msg);

private:
static Log *_pInstance;
static QMutex _mutex;
static Log4Qt::Logger * _pLoggerDebug;
static Log4Qt::Logger * _pLoggerInfo;
static Log4Qt::Logger * _pLoggerWarn;
static Log4Qt::Logger * _pLoggerError;
static QString _configFilePath;

};

Log.cpp

#include "Log.h"
#include "log4qt/log4qt.h"
#include "log4qt/propertyconfigurator.h"

Log * Log::_pInstance = 0;
QMutex Log::_mutex;
Log4Qt::Logger * Log::_pLoggerDebug = 0;
Log4Qt::Logger * Log::_pLoggerInfo = 0;
Log4Qt::Logger * Log::_pLoggerWarn = 0;
Log4Qt::Logger * Log::_pLoggerError = 0;
QString Log::_configFilePath;

Log::Log(QObject *parent) : QObject(parent)
{
// 一定要配置文件,不然运行起来会直接当掉
Log4Qt::BasicConfigurator::configure();
}

Log *Log::instance()
{
if(!_pInstance)
{
QMutexLocker mutexLocker(&_mutex);
if(!_pInstance)
{
Log *pInstance = new Log();
_pInstance = pInstance;
}
}
return _pInstance;
}

void Log::init(QString configFilePath)
{
_configFilePath = configFilePath;
Log4Qt::PropertyConfigurator::configure(_configFilePath);
_pLoggerDebug = Log4Qt::Logger::logger("debug");
_pLoggerInfo = Log4Qt::Logger::logger("info");
_pLoggerWarn = Log4Qt::Logger::logger("warn");
_pLoggerError = Log4Qt::Logger::logger("error");
}

void Log::debug(QString msg)
{
_pLoggerDebug->debug(msg);
}

void Log::info(QString msg)
{
_pLoggerInfo->info(msg);
}

void Log::warn(QString msg)
{
_pLoggerWarn->warn(msg);
}

void Log::error(QString msg)
{
_pLoggerError->error(msg);
}


测试代码

main.cpp

#include <QApplication>
#include <QTextCodec>
#include <QThread>
#include "Log.h"

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

QThread::currentThread()->setObjectName("主线程");

QTextCodec *codec = QTextCodec::codecForName("utf-8");
QTextCodec::setCodecForLocale(codec);

Log::instance()->init(QCoreApplication::applicationDirPath() + "/" +"etc/log.conf");
Log::instance()->debug("调试测试日志系统当中...");
Log::instance()->info("信息测试日志系统当中...");
Log::instance()->warn("警告测试日志系统当中...");
Log::instance()->error("错误测试日志系统当中...");

return a.exec();
}


配置文件

log.conf

log4j.logger.debug=CONSOLE,debug
log4j.appender.debug=org.apache.log4j.RollingFileAppender
log4j.appender.debug.Threshold=DEBUG
log4j.appender.debug.appendFile=true
log4j.appender.debug.Encoding=UTF-8
log4j.appender.debug.File=log/debug.txt
log4j.appender.debug.MaxFileSize=4096KB
log4j.appender.debug.MaxBackupIndex=7
log4j.appender.debug.layout=org.apache.log4j.PatternLayout
log4j.appender.debug.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.zzz}[%t][%p] %m%n

log4j.logger.info=CONSOLE,info,debug
log4j.appender.info=org.apache.log4j.RollingFileAppender
log4j.appender.info.Threshold=DEBUG
log4j.appender.info.appendFile=true
log4j.appender.info.Encoding=UTF-8
log4j.appender.info.File=log/info.txt
log4j.appender.info.MaxFileSize=4096KB
log4j.appender.info.MaxBackupIndex=7
log4j.appender.info.layout=org.apache.log4j.PatternLayout
log4j.appender.info.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.zzz}[%t][%p] %m%n

log4j.logger.warn=CONSOLE,info,debug,warn
log4j.appender.warn=org.apache.log4j.RollingFileAppender
log4j.appender.warn.Threshold=DEBUG
log4j.appender.warn.appendFile=true
log4j.appender.warn.Encoding=GBK
log4j.appender.warn.File=log/warn.txt
log4j.appender.warn.MaxFileSize=4096KB
log4j.appender.warn.MaxBackupIndex=2
log4j.appender.warn.layout=org.apache.log4j.PatternLayout
log4j.appender.warn.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.zzz}[%t][%p] %m%n


log4j.logger.error=CONSOLE,info,debug,warn,error
log4j.appender.error=org.apache.log4j.RollingFileAppender
log4j.appender.error.Threshold=DEBUG
log4j.appender.error.appendFile=true
log4j.appender.error.Encoding=UTF-8
log4j.appender.error.File=log/error.txt


协作开发

define.h

// 开发过程中暂时使用qDebug替代 1-使用debug打印输出  0-使用日志输出
#if 1

// 以文件行列记录信息,非以类名对象形式
#define LOG_DEBUG(msg) qDebug() << QString("[%1][%2][%3][%4]%5") \
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz")) \
.arg(QString("%1:%2:%3").arg(__FILE__).arg(__LINE__).arg(__FUNCTION__)) \
.arg(QThread::currentThread()->objectName()) \
.arg("DEBUG") \
.arg(msg);

#define LOG_INFO(msg) qDebug() << QString("[%1][%2][%3][%4]%5") \
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz")) \
.arg(QString("%1:%2:%3").arg(__FILE__).arg(__LINE__).arg(__FUNCTION__)) \
.arg(QThread::currentThread()->objectName()) \
.arg("INFO") \
.arg(msg);

#define LOG_WARN(msg) qDebug() << QString("[%1][%2][%3][%4]%5") \
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz")) \
.arg(QString("%1:%2:%3").arg(__FILE__).arg(__LINE__).arg(__FUNCTION__)) \
.arg(QThread::currentThread()->objectName()) \
.arg("WARN") \
.arg(msg);

#define LOG_ERROR(msg) qDebug() << QString("[%1][%2][%3][%4]%5") \
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz")) \
.arg(QString("%1:%2:%3").arg(__FILE__).arg(__LINE__).arg(__FUNCTION__)) \
.arg(QThread::currentThread()->objectName()) \
.arg("ERROR") \
.arg(msg);


// 以类名对象形式记录信息
#define LOG_OBJECT_DEBUG(msg) qDebug() << QString("[%1][%2][%3][%4]%5") \
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz")) \
.arg(QString("%1::%2:%3").arg(this->metaObject()->className()).arg(__FUNCTION__).arg(__LINE__)) \
.arg(QThread::currentThread()->objectName()) \
.arg("DEBUG") \
.arg(msg);

#define LOG_OBJECT_INFO(msg) qDebug() << QString("[%1][%2][%3][%4]%5") \
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz")) \
.arg(QString("%1::%2:%3").arg(this->metaObject()->className()).arg(__FUNCTION__).arg(__LINE__)) \
.arg(QThread::currentThread()->objectName()) \
.arg("INFO") \
.arg(msg);

#define LOG_OBJECT_WARN(msg) qDebug() << QString("[%1][%2][%3][%4]%5") \
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz")) \
.arg(QString("%1::%2:%3").arg(this->metaObject()->className()).arg(__FUNCTION__).arg(__LINE__)) \
.arg(QThread::currentThread()->objectName()) \
.arg("WARN") \
.arg(msg);

#define LOG_OBJECT_ERROR(msg) qDebug() << QString("[%1][%2][%3][%4]%5") \
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz")) \
.arg(QString("%1::%2:%3").arg(this->metaObject()->className()).arg(__FUNCTION__).arg(__LINE__)) \
.arg(QThread::currentThread()->objectName()) \
.arg("ERROR") \
.arg(msg);


// 写入日志系统
#else

// 以文件行列记录信息,非以类名对象形式
#define LOG_DEBUG(msg) Log::instance()->debug(QString("[%1]%2").arg(QString("%1:%2:%3").arg(__FILE__).arg(__LINE__).arg(__FUNCTION__)).arg(msg));

#define LOG_INFO(msg) Log::instance()->info(msg);

#define LOG_WARN(msg) Log::instance()->warn(msg);

#define LOG_ERROR(msg) Log::instance()->error(msg);


// 以类名对象形式记录信息
#define LOG_OBJECT_DEBUG(msg) Log::instance()->debug(QString("[%1]%2").arg(QString("%1::%2:%3").arg(this->metaObject()->className()).arg(__FUNCTION__).arg(__LINE__)).arg(msg));

#define LOG_OBJECT_INFO(msg) Log::instance()->info(msg);

#define LOG_OBJECT_WARN(msg) Log::instance()->warn(msg);

#define LOG_OBJECT_ERROR(msg) Log::instance()->error(msg);


#endif


Qt4版本日志移植到qt5编译过程出现错误

错误一:识别QtMsgHandler类

“error: 'QtMsgHandler' does not name a type”

Qt三方库开发技术:log4Qt介绍、编译和使用_#define_06

解决方法:QtMsgHandler替换为QtMessageHandler

Qt5做了一些更改:

Qt三方库开发技术:log4Qt介绍、编译和使用_apache_07

更改如下图:

Qt三方库开发技术:log4Qt介绍、编译和使用_#define_08

错误二:QObject类未声明

       点击跳转到错误文件,添加QObject

错误三:QTextCodec编码错误

       Qt三方库开发技术:log4Qt介绍、编译和使用_日志_09

       点击跳转到错误文件,修改log4qt源码:

        Qt三方库开发技术:log4Qt介绍、编译和使用_log4qt_10

错误四:操作符“<<”歧义

       Qt三方库开发技术:log4Qt介绍、编译和使用_#define_11

        直接修改吧,改变下存储的数据类型:

     Qt三方库开发技术:log4Qt介绍、编译和使用_apache_12

错误五:qInstallMsgHandle未声明

        Qt三方库开发技术:log4Qt介绍、编译和使用_log4qt_13

        宏修改如下:

         Qt三方库开发技术:log4Qt介绍、编译和使用_apache_14

       成功运行,如下图:

        Qt三方库开发技术:log4Qt介绍、编译和使用_#include_15


Qt5版本的Log4Qt

       下载后直接将qt4版本的pri文件换成qt5版本的,qt5版本的则没有以上的一些编译错误,替换模块,如下图:

        Qt三方库开发技术:log4Qt介绍、编译和使用_apache_16

源码下载