PowerModeler/source/logger.cpp

155 lines
4.6 KiB
C++

#include "logger.h"
#include "settings.h"
#include <QFileInfo>
#include <QDir>
#include <QTextStream>
Logger& Logger::instance()
{
//采用静态局部变量的方式,静态局部变量的初始化是在第一次访问时,以后的调用不会多次初始化,并且生命周期和程序一致
static Logger instance;
return instance;
}
Logger::Logger()
{
initialize();
}
Logger::~Logger()
{
shutdown();
}
void Logger::initialize()
{
//默认配置
m_logFilePath = "";
m_logLevel = INFO;
m_maxFileSize = 1024 *1024 * 10; //10MB
m_maxBackupFiles = 5;
m_outputToConsole = true;
m_outputOtFile = true;
//从配置文件中加载配置
loadConfig();
}
void Logger::loadConfig(/*const QString& configFilePath*/)
{
QString filePath = Settings::instance().value("Log", "logFile").toString();
setLogFile(filePath);
QString strLevel = Settings::instance().value("Log", "level").toString().toUpper();
if(strLevel == "DEBUG")
m_logLevel = DEBUG;
else if(strLevel == "INFO")
m_logLevel = INFO;
else if(strLevel == "WARNING")
m_logLevel = WARNING;
else if(strLevel == "ERROR")
m_logLevel = ERROR;
else if(strLevel == "FATAL")
m_logLevel = FATAL;
m_maxFileSize = Settings::instance().value("Log", "maxSize").toLongLong();
m_maxBackupFiles = Settings::instance().value("Log", "backups").toInt();
QString strOutputToConsole = Settings::instance().value("Log", "consoleOutput").toString();
if(strOutputToConsole == "true")
m_outputToConsole = true;
else
m_outputToConsole = false;
QString strOutputToFile = Settings::instance().value("Log", "fileOutput").toString();
if(strOutputToFile == "true")
m_outputOtFile = true;
else
m_outputOtFile = false;
}
void Logger::setLogFile(const QString& filePath)
{
//检查目录文件所在目录,如果不存在则创建目录
QFileInfo fileInfo(filePath);
QDir logDir = fileInfo.dir();
if(!logDir.exists())
logDir.mkpath(".");
//更新log文件前要先关闭当前已打开的文件
if(m_logFile.isOpen())
m_logFile.close();
m_logFilePath = filePath;
m_logFile.setFileName(filePath);
}
void Logger::shutdown()
{
if(m_logFile.isOpen())
m_logFile.close();
}
void Logger::writeToFile(const QString& message)
{
if(m_logFilePath.isEmpty())
return;
if(!m_logFile.isOpen())
{
if (!m_logFile.open(QIODevice::Append | QIODevice::Text))
{
qWarning() << "Failed to open log file:" << m_logFile.errorString();
return;
}
//打开文件时先键入一个换行符
QTextStream stream(&m_logFile);
stream << Qt::endl;
stream.flush(); //刷新输出缓冲区,确保数据立即写入文件
}
QTextStream stream(&m_logFile);
stream << message << Qt::endl;
stream.flush(); //刷新输出缓冲区,确保数据立即写入文件
if(m_logFile.size() > m_maxFileSize)
rollLogFiles();
}
void Logger::rollLogFiles()
{
if(m_logFile.isOpen())
m_logFile.close();
//删除最旧的备份文件(备份文件以‘日志文件.数字’的格式命名,数字越大表示文件越旧)
QFile::remove(QString("%1.%2").arg(m_logFilePath).arg(m_maxBackupFiles));
//剩余文件依次更改名称
for(int i = m_maxBackupFiles - 1; i > 0; i--)
QFile::rename(QString("%1.%2").arg(m_logFilePath).arg(i), QString("%1.%2").arg(m_logFilePath).arg(i + 1));
//将当前日志文件更改为'最新'的备份文件(编号为1)
QFile::rename(m_logFilePath, QString("%1.1").arg(m_logFilePath));
//更新当前配置文件(重新打开)
m_logFile.setFileName(m_logFilePath);
if (!m_logFile.open(QIODevice::Append | QIODevice::Text))
qWarning() << "Failed to open new log file after rolling:" << m_logFile.errorString();
}
QString Logger::formatLogMessage(LogLevel level, const QString& context, const QString& message)
{
static const char* levelStrings[] = {"FATAL", "ERROR", "WARNING", "INFO", "DEBUG"};
return QString("[%1] [%2] [%3] %4")
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"))
.arg(levelStrings[level])
.arg(context)
.arg(message);
}
void Logger::log(LogLevel level, const QString& context, const QString& message)
{
if(level > m_logLevel)
return;
QString formatMessage = formatLogMessage(level, context, message);
if(m_outputToConsole)
QTextStream(stderr) << formatMessage << Qt::endl;
if(m_outputOtFile)
writeToFile(formatMessage);
}