cpp
#ifndef LOGGER_H
#define LOGGER_H
#include <QObject>
#include <QFile>
#include <QMutex>
#include <QDateTime>
#include <QBasicTimer>
#include <atomic>
#include <memory>
enum class LogLevel {
Message,
Warning,
Error
};
class Logger : public QObject
{
Q_OBJECT
public:
static Logger* instance();
bool initialize(const QString& filePath);
void log(LogLevel level, const QString& message);
void message(const QString& message);
void warning(const QString& message);
void error(const QString& message);
private:
explicit Logger(QObject* parent = nullptr);
~Logger();
Logger(const Logger&) = delete;
Logger& operator=(const Logger&) = delete;
void writeToFile(const QByteArray& data);
void timerEvent(QTimerEvent* event) override;
QFile logFile;
QMutex fileMutex;
std::atomic<bool> isInitialized{ false };
QBasicTimer flushTimer;
static std::atomic<Logger*> m_instance;
static QMutex m_instanceMutex;
};
#define LOG_MESSAGE(msg) Logger::instance()->message(msg)
#define LOG_WARNING(msg) Logger::instance()->warning(msg)
#define LOG_ERROR(msg) Logger::instance()->error(msg)
#endif // LOGGER_H
cpp
#include "logger.h"
#include <QThread>
#include <QCoreApplication>
#include <QDir>
#include <QFileInfo>
#include <QDebug>
#include <cstring>
std::atomic<Logger*> Logger::m_instance = nullptr;
QMutex Logger::m_instanceMutex;
Logger::Logger(QObject* parent) : QObject(parent)
{
if (QCoreApplication::instance()) {
connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit,
this, [this] {
QMutexLocker locker(&fileMutex);
if (logFile.isOpen()) logFile.flush();
});
}
}
Logger::~Logger()
{
QMutexLocker locker(&fileMutex);
if (logFile.isOpen()) {
logFile.flush();
logFile.close();
}
}
Logger* Logger::instance()
{
auto* instance = m_instance.load(std::memory_order_acquire);
if (!instance) {
QMutexLocker locker(&m_instanceMutex);
instance = m_instance.load(std::memory_order_relaxed);
if (!instance) {
// 确保在主线程创建
if (QThread::currentThread() != QCoreApplication::instance()->thread()) {
qFatal("Logger instance must be created in main thread");
}
instance = new Logger();
m_instance.store(instance, std::memory_order_release);
}
}
return instance;
}
bool Logger::initialize(const QString& filePath)
{
if (isInitialized.load(std::memory_order_acquire))
return true;
QMutexLocker locker(&fileMutex);
QFileInfo fileInfo(filePath);
QDir logDir = fileInfo.absoluteDir();
if (!logDir.exists() && !logDir.mkpath(".")) {
qDebug() << "Failed to create log directory:" << logDir.path();
return false;
}
logFile.setFileName(filePath);
if (!logFile.open(QIODevice::Append | QIODevice::Text)) {
qDebug() << "Failed to open log file:" << filePath;
return false;
}
const auto header = QByteArrayLiteral("========================================\n")
+ "Log started at: "
+ QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss").toUtf8()
+ "\n========================================\n\n";
logFile.write(header);
logFile.flush();
isInitialized.store(true, std::memory_order_release);
return true;
}
void Logger::log(LogLevel level, const QString& message)
{
if (!isInitialized.load(std::memory_order_acquire)) {
qDebug() << "Logger not initialized, message dropped:" << message;
return;
}
const QByteArray timeStamp = QDateTime::currentDateTime()
.toString("yyyy-MM-dd HH:mm:ss.zzz").toUtf8();
const QByteArray msgUtf8 = message.toUtf8();
static const char* const levelStrings[] = { "MESSAGE", "WARNING", "ERROR" };
static_assert(sizeof(levelStrings) / sizeof(levelStrings[0]) ==
static_cast<int>(LogLevel::Error) + 1,
"LogLevel count mismatch");
const char* levelStr = levelStrings[static_cast<int>(level)];
// 精确预分配缓冲区
int totalSize = 1; // '['
totalSize += timeStamp.size();
totalSize += 3; // "] ["
totalSize += std::strlen(levelStr);
totalSize += 2; // "] "
totalSize += msgUtf8.size();
totalSize += 1; // '\n'
QByteArray logEntry;
logEntry.reserve(totalSize);
// 高效构建日志条目
logEntry.append('[')
.append(timeStamp)
.append("] [")
.append(levelStr)
.append("] ")
.append(msgUtf8)
.append('\n');
writeToFile(logEntry);
}
void Logger::writeToFile(const QByteArray& data)
{
QMutexLocker locker(&fileMutex);
logFile.write(data);
// 使用单次触发定时器
if (!flushTimer.isActive()) {
flushTimer.start(20, this);
}
}
void Logger::timerEvent(QTimerEvent* event)
{
if (event->timerId() == flushTimer.timerId()) {
QMutexLocker locker(&fileMutex);
logFile.flush();
flushTimer.stop();
}
}
void Logger::message(const QString& message) { log(LogLevel::Message, message); }
void Logger::warning(const QString& message) { log(LogLevel::Warning, message); }
void Logger::error(const QString& message) { log(LogLevel::Error, message); }
main.cpp引用头文件并初始化
cpp
// 初始化(主线程)
Logger::instance()->initialize("app.log");
// 记录日志(任意线程)
LOG_MESSAGE("User logged in"); // 宏展开为:
// Logger::instance()->message("User logged in");
LOG_ERROR("Database connection failed");