cpp
#ifndef LOGGER_H
#define LOGGER_H
#include <QObject>
#include <QFile>
#include <QTextStream>
#include <QMutex>
#include <QQueue>
#include <QThread >
class Logger : public QObject {
Q_OBJECT
public:
static Logger* getInstance();
void startLogging();
void log(const QString& message, const QString& val, const char* file, int line);
private:
explicit Logger(QObject *parent = nullptr);
QFile logFile;
QTextStream logStream;
QMutex mutex;
QQueue<QString> logQueue;
bool logging;
void processLogQueue();
static Logger* instance;
};
class LoggerThread : public QThread {
public:
void run() override {
Logger::getInstance()->startLogging();
}
};
#define LOG(message, val) Logger::getInstance()->log(message, val, __FILE__, __LINE__)
#endif // LOGGER_H
cpp
#include "logger.h"
#include <QFileInfo>
Logger* Logger::instance = nullptr;
Logger::Logger(QObject *parent) : QObject(parent), logging(false) {
logFile.setFileName("out.log");
}
Logger* Logger::getInstance() {
if (instance == nullptr) {
instance = new Logger();
}
return instance;
}
void Logger::startLogging() {
if (logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {
logStream.setDevice(&logFile);
logging = true;
processLogQueue();
} else {
qCritical() << "Error opening log file.";
}
}
void Logger::log(const QString& message, const QString& val, const char* file, int line) {
QFileInfo fileInfo(file);
QString msg = QString("[%1] [%2:%3] %4 %5")
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss.zzz"))
.arg(fileInfo.fileName())
.arg(QString::number(line))
.arg(message)
.arg(val);
{
QMutexLocker locker(&mutex);
logQueue.enqueue(msg);
}
if (logging) {
processLogQueue();
}
}
void Logger::processLogQueue() {
while (!logQueue.isEmpty()) {
logStream << logQueue.dequeue() << endl;
}
}
cpp
#include <QCoreApplication>
#include <QDebug>
#include "logger.h"
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv);
LoggerThread loggerThread;
loggerThread.start();
loggerThread.wait(); // 等待线程完成
QString strVal = "test";
LOG("This is a log message.", strVal );
LOG("Another log message.", strVal );
return app.exec();
}
进一步拓展,可以随机输入不确定的参数:
cpp
#define LOG(...) Logger::getInstance()->log(__VA_ARGS__, __FILE__, __LINE__)
void Logger::log(const char* file, int line, const QString& message) {
QFileInfo fileInfo(file);
QString msg = QString("[%1] [%2:%3] [Thread ID: %4] %5")
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss.zzz"))
.arg(fileInfo.fileName())
.arg(line)
.arg(QThread::currentThreadId())
.arg(message);
{
QMutexLocker locker(&mutex);
logQueue.enqueue(msg);
}
if (logging) {
processLogQueue();
}
}
template<typename T, typename... Args>
void Logger::log(const char* file, int line, const QString& message, T&& value, Args&&... args) {
QString newValue = QString::fromUtf8(QByteArray::number(value));
log(file, line, message + " " + newValue, std::forward<Args>(args)...);
}
下一步还可以输入不同类型来确定打印,可以使用模板函数来处理等等;