2026/11/2 10:42:31

C++多平台日志库,支持wasm

C++多平台日志库,支持wasm #include memory#include string#include unordered_setLog.h:class Log{public:using SP std::shared_ptrLog;enum class Level {eInfo,eWarning,eError,};struct Message {Level m_level; // 日志级别const char *m_module; // 所属模块std::string_view m_tag; // 自定义打印标签const char *m_file; // 文件std::size_t m_lineNumber; // 行编号const char *m_func; // 函数std::size_t m_verboseLevel; // 详细级别std::string_view m_message; // 消息内容};Log();static Log *instance();static void release();public:void log(const Message str) const;bool connectToWebSocket(const std::string url);void closeWebSocket();void setUserIdentity(const std::string userIdentity);private:std::string getCurrentTime(bool bLocal, bool bIncludeMs) const;const char *getLevelStr(Level level) const;std::string formatLine(const Message message) const;void outputJsonValue(std::string line, const std::string key, const std::string_view value) const;private:std::string m_userIdentity;};#if _MSC_VER // Visual C # define MY_FUNC __FUNCSIG__#elif __GUNC__ // GCC# define MY_FUNC __PRETTY_FUNCTION__#elif __INTEL_COMPILER // Intel C# define MY_FUNC __PRETTY_FUNCTION__#elif (defined(__clang__) (__clang__ 1)) // Clang# define MY_FUNC __PRETTY_FUNCTION__#else# if defined(__func__)# define MY_FUNC __func__# else# define MY_FUNC # endif#endif#define MESSAGE_DEFAULT(level, msg) \{ \level, MODULE_NAME_DEF, , __FILE__, __LINE__, MY_FUNC, 0, msg \}#define MESSAGE_TAG_DEFAULT(level, tag, msg) \{ \level, MODULE_NAME_DEF, tag, __FILE__, __LINE__, MY_FUNC, 0, msg \}#define MESSAGE_DEFAULT_VERBOSE(level, msg, verbose) \{ \level, MODULE_NAME_DEF, , __FILE__, __LINE__, MY_FUNC, verbose, msg \}#define LOG_INFO(message) Log::instance()-log(MESSAGE_DEFAULT(Log::Level::eInfo, message));#define LOG_WARN(message) Log::instance()-log(MESSAGE_DEFAULT(Log::Level::eWarning, message));#define LOG_ERROR(message) Log::instance()-log(MESSAGE_DEFAULT(Log::Level::eError, message));#define LOG_INFO_TAG(tag, message) \Log::instance()-log(MESSAGE_TAG_DEFAULT(Log::Level::eInfo, tag, message));#define LOG_WARN_TAG(tag, message) \Log::instance()-log(MESSAGE_TAG_DEFAULT(Log::Level::eWarning, tag, message));#define LOG_ERROR_TAG(tag, message) \Log::instance()-log(MESSAGE_TAG_DEFAULT(Log::Level::eError, tag, message));#endifLog.cpp:#include Log.h#include algorithm#include chrono#include iomanip#include iostream#include sstream#ifdef __EMSCRIPTEN__# include emscripten/emscripten.h# include emscripten/html5.h# include emscripten/websocket.h# include stdio.h# include stdlib.hEMSCRIPTEN_WEBSOCKET_T gWebSocket -1;EM_BOOL WebSocketOpen(int eventType, const EmscriptenWebSocketOpenEvent *e, void *userData){printf(open(eventType%d, userData%ld)\n, eventType, (long)userData);emscripten_websocket_send_utf8_text(e-socket, hello on the other side);char data[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};emscripten_websocket_send_binary(e-socket, data, sizeof(data));// emscripten_websocket_close(e-socket, 0, 0);return 0;}EM_BOOL WebSocketClose(int eventType, const EmscriptenWebSocketCloseEvent *e, void *userData){printf(close(eventType%d, wasClean%d, code%d, reason%s, userData%ld)\n,eventType,e-wasClean,e-code,e-reason,(long)userData);return 0;}EM_BOOL WebSocketError(int eventType, const EmscriptenWebSocketErrorEvent *e, void *userData){printf(error(eventType%d, userData%ld)\n, eventType, (long)userData);return 0;}EM_BOOL WebSocketMessage(int eventType, const EmscriptenWebSocketMessageEvent *e, void *userData){printf(message(eventType%d, userData%ld, data%p, numBytes%d, isText%d)\n,eventType,(long)userData,e-data,e-numBytes,e-isText);if (e-isText)printf(text data: \%s\\n, e-data);else {printf(binary data:);for (int i 0; i e-numBytes; i)printf( %02X, e-data[i]);printf(\n);// emscripten_websocket_delete(e-socket);// exit(0);}return 0;}#endifstatic Log* m_instance nullptr;Log* Log::instance(){if(!m_instance)m_instance new Log();return m_instance;}void Log::release(){if(m_instance)delete m_instance;m_instance nullptr;}Log::Log() {}/** 用户具体信息*/void Log::setUserIdentity(const std::string userIdentity){m_userIdentity userIdentity;}std::string Log::getCurrentTime(bool bLocal, bool bIncludeMs) const{std::stringstream ss;auto timePoint std::chrono::system_clock::now();auto tSeconds std::chrono::duration_caststd::chrono::seconds(timePoint.time_since_epoch());#if (defined __EMSCRIPTEN__)// 用WebAssembly得方式打印时间std::time_t tt std::chrono::system_clock::to_time_t(timePoint);std::tm *ptm std::localtime(tt);ss std::put_time(ptm, %Y-%m-%d %H:%M:%S);#elif defined(WINDOWS_DEV_MODE) || defined(QT_PLATFORM)auto secNow tSeconds.count();tm tmNow;if(bLocal)localtime_s(tmNow, secNow);elsegmtime_s(tmNow, secNow);ss std::put_time(tmNow, %Y-%m-%d %H:%M:%S);#else// 用WebAssembly得方式打印时间std::time_t tt std::chrono::system_clock::to_time_t(timePoint);std::tm *ptm std::localtime(tt);ss std::put_time(ptm, %Y-%m-%d %H:%M:%S);#endifif(bIncludeMs) {auto tMilli std::chrono::duration_caststd::chrono::milliseconds(timePoint.time_since_epoch());auto ms tMilli - tSeconds;ss . std::setfill(0) std::setw(3) ms.count();}// ss std::put_time(std::localtime(timeT), %X,);return ss.str();}const char *Log::getLevelStr(Level level) const{switch (level) {case Log::Level::eError:return ERROR;case Log::Level::eWarning:return WARNING;case Log::Level::eInfo:return INFO;default:return UNKNOWN;}}bool Log::connectToWebSocket(const std::string url){#if (defined __EMSCRIPTEN__)if (!emscripten_websocket_is_supported()) {printf(WebSockets are not supported, cannot continue!\n);return false;}closeWebSocket();EmscriptenWebSocketCreateAttributes attr;emscripten_websocket_init_create_attributes(attr);attr.url url.c_str();gWebSocket emscripten_websocket_new(attr);if (gWebSocket 0) {printf(WebSocket creation failed, error code %d!\n, (EMSCRIPTEN_RESULT)gWebSocket);return false;}emscripten_websocket_set_onopen_callback(gWebSocket, (void *)42, WebSocketOpen);emscripten_websocket_set_onclose_callback(gWebSocket, (void *)43, WebSocketClose);emscripten_websocket_set_onerror_callback(gWebSocket, (void *)44, WebSocketError);emscripten_websocket_set_onmessage_callback(gWebSocket, (void *)45, WebSocketMessage);#endifreturn true;}void Log::closeWebSocket(){#if (defined __EMSCRIPTEN__)if (gWebSocket 0) {emscripten_websocket_close(gWebSocket, 0, 0); // 关闭旧的连接// emscripten_websocket_delete(0);}gWebSocket -1;#endif}void Log::log(const Message str) const{auto logLine formatLine(str);#if (defined __EMSCRIPTEN__)// 0 (CONNECTING): The connection is still being established.// 1 (OPEN): The connection is open and ready to send/receive data.// 2 (CLOSING): The connection is in the process of closing.// 3 (CLOSED): The connection has been closed or could not be opened.unsigned short readyState 0;if (gWebSocket 0)emscripten_websocket_get_ready_state(gWebSocket, readyState);if (1 ! readyState || gWebSocket 0) {if (Level::eError str.m_level)emscripten_console_error(logLine.c_str());else if (Level::eWarning str.m_level)emscripten_console_warn(logLine.c_str());elseemscripten_console_log(logLine.c_str());} else {emscripten_websocket_send_utf8_text(gWebSocket, logLine.c_str());}#elseif (Level::eError str.m_level)std::cerr logLine std::endl;elsestd::cout logLine std::endl;#endif}void Log::outputJsonValue(std::string line, const std::string key, const std::string_view value) const{if (line.empty())line.append({);elseline.append(, );line.append(\);line.append(key);line.append(\);line.append(:);line.append(\);line.append(value);line.append(\);}/*** 日志行输出* param message* return*/std::string Log::formatLine(const Message message) const{std::string line;#if (defined __EMSCRIPTEN__)std::string now getCurrentTime(true, true);outputJsonValue(line, TIME, now);#endifif (!message.m_tag.empty())outputJsonValue(line, Tag, message.m_tag);if (!m_userIdentity.empty())outputJsonValue(line, user, m_userIdentity);outputJsonValue(line, MODULE, message.m_module);#if (defined __EMSCRIPTEN__)std::string newFileNamePath message.m_file;std::replace(newFileNamePath.begin(), newFileNamePath.end(), \\, /); // windows下符号替换outputJsonValue(line, FILE, newFileNamePath);outputJsonValue(line, FUNC, message.m_func);outputJsonValue(line, LINE, std::to_string(message.m_lineNumber));outputJsonValue(line, LEVEL, getLevelStr(message.m_level));// outputJsonValue(line, VERBOSE, std::to_string(message.m_verboseLevel));#endifoutputJsonValue(line, MSG, message.m_message);line.append(});#if (defined __EMSCRIPTEN__)if (Level::eError message.m_level) {char buffer[2048];auto len emscripten_get_callstack(EM_LOG_JS_STACK | EM_LOG_C_STACK, buffer, 2048);std::string_view stringView(buffer, len);outputJsonValue(line, callstack, std::string{stringView});line.append(, \callstack\:\n);}#endifreturn line;}使用示例#include Log.hvoid main() {LOG_INFO(setHotZoneMode invalid mode);}GitHub - ArthurSonzogni/quill: Asynchronous Low Latency Logging Library创作不易小小的支持一下吧