參考 Unity Debug.Log 和 Qt qDebug() 風格,實現一個易用、高效的 C++ 日誌系統,滿足:
operator<< 鏈式調用)// 日誌上下文:文件、函數、行號
class MessageLogContext {
public:
const char* file;
const char* function;
int line;
MessageLogContext(const char* f, const char* fn, int l)
: file(f), function(fn), line(l) {}
};
// 前端介面:通過宏自動捕獲上下文
class MessageLogger {
MessageLogContext ctx;
public:
MessageLogger(const char* f, const char* fn, int l) : ctx(f, fn, l) {}
Debug debug() const; // 返回 Debug 對象,析構時自動輸出
Debug info() const;
Debug warning() const;
Debug error() const;
Debug fatal() const;
};
// 宏定義:使用時自動展開為 MessageLogger(__FILE__, __FUNCTION__, __LINE__).debug()
#define LOG_DEBUG MessageLogger(__FILE__, __FUNCTION__, __LINE__).debug()
#define LOG_INFO MessageLogger(__FILE__, __FUNCTION__, __LINE__).info()
#define LOG_WARN MessageLogger(__FILE__, __FUNCTION__, __LINE__).warning()
#define LOG_ERROR MessageLogger(__FILE__, __FUNCTION__, __LINE__).error()
class Debug {
struct Stream {
ostringstream ss;
MessageLogContext ctx;
LogType type;
Stream() : type(LogType::Default) {}
Stream(const MessageLogContext& c) : ctx(c), type(LogType::Default) {}
};
unique_ptr stream;
public:
Debug() : stream(make_unique()) {}
Debug(const MessageLogContext& ctx, LogType t)
: stream(make_unique(ctx)) { stream->type = t; }
~Debug() { flush(); } // 析構時自動輸出
// 通用流式輸出
template
Debug& operator<<(const T& val) {
stream->ss << val;
return *this;
}
// 支援 STL 容器
template
Debug& operator<<(const vector& vec) {
stream->ss << '[';
for (size_t i = 0; i < vec.size(); ++i) {
stream->ss << vec[i];
if (i + 1 < vec.size()) stream->ss << ", ";
}
stream->ss << ']';
return *this;
}
void flush() {
// 格式化輸出:[LEVEL] message (file:function:line)
string prefix;
switch(stream->type) {
case LogType::Error: prefix = "[ERROR] "; break;
case LogType::Warning: prefix = "[WARN] "; break;
default: break;
}
cout << prefix << stream->ss.str()
<< " (" << stream->ctx.file << ":" << stream->ctx.function
<< ":" << stream->ctx.line << ")" << endl;
}
};
Debug MessageLogger::debug() const {
return Debug(ctx, LogType::Debug);
}
Debug MessageLogger::info() const {
return Debug(ctx, LogType::Info);
}
Debug MessageLogger::warning() const {
return Debug(ctx, LogType::Warning);
}
Debug MessageLogger::error() const {
return Debug(ctx, LogType::Error);
}
Debug MessageLogger::fatal() const {
return Debug(ctx, LogType::Fatal);
}
struct Vec3 { float x, y, z; };
ostream& operator<<(ostream& os, const Vec3& v) {
return os << "(" << v.x << ", " << v.y << ", " << v.z << ")";
}
void test() {
vector vecs = {{1,2,3}, {4,5,6}};
LOG_DEBUG << "Hello Debug";
LOG_INFO << "Vector: " << Vec3{1,2,3};
LOG_WARN << "Container: " << vecs;
LOG_ERROR << "Error code: " << 404;
}
Hello Debug (main.cpp:test:10) [INFO] Vector: (1, 2, 3) (main.cpp:test:11) [WARN] Container: [(1, 2, 3), (4, 5, 6)] (main.cpp:test:12) [ERROR] Error code: 404 (main.cpp:test:13)
Debug 臨時對象析構時自動輸出,無需手動調用 flush()__FILE__, __FUNCTION__, __LINE__ 自動傳遞operator<< 即可無縫接入vector, map 等