用于QT的一个简易日志功能模块封装。算不上强大和多高的性能,但是足够简单小巧。用于记录日志到文件够用了。单独的一个文件模块,使用时直接引入源码。想要其他功能,直接改
用于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中包含模块源码即可。
include(Logger/MessageLogger.pri)
MessageLogger.pri文件内容:
HEADERS += $$PWD/MessageLogger.h
SOURCES += $$PWD/MessageLogger.cpp
INCLUDEPATH += $$PWD
简易封装
#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
#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);
}
}
}
简单使用
#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,创建图片文件夹失败");
}
}
}