Skip to content

SOUI 日志系统使用指南

Warning

The current page still doesn't have a translation for this language.

You can read it through google translate.

SOUI 框架提供了一套完整的日志系统,用于帮助开发者调试和监控应用程序运行状态。新版本的日志系统借鉴了 webrtc 的流式输出日志方法,使日志输出格式更加简洁易用。

日志系统架构

SOUI 的日志系统由两个核心部分组成:

  1. 日志输出宏:提供便捷的日志记录接口
  2. 日志打印模块:负责将日志输出到文件或调试窗口

日志打印模块基于 log4z 代码进行修改,以适配 SOUI 的接口需求。

日志输出方式

SOUI 支持两种日志输出方式:

  1. 文件输出:配置日志打印模块后,日志可直接输出到 log 文件
  2. 调试窗口输出:不配置打印模块时,默认使用 OutputDebugString 输出到调试窗口

日志打印模块配置

要在 SOUI 中使用日志打印模块,需要进行如下配置:

if (pComMgr->CreateLog4z((IObjRef**)&pLogMgr) && pLogMgr)
{
    // 取消注释下一行可禁用日志管理器输出调试字符串
    // pLogMgr->setLoggerDisplay(LOG4Z_MAIN_LOGGER_ID, false);

    // 取消注释下一行可记录信息级别日志
    // pLogMgr->setLoggerLevel(LOG4Z_MAIN_LOGGER_ID, LOG_LEVEL_INFO);
    pLogMgr->start();
}

// 定义一个唯一的 SApplication 对象,SApplication 管理整个应用程序的资源
SApplication* theApp = new SApplication2(pRenderFactory, hInstance);

// 将日志模块交给 SApp 管理
theApp->SetLogManager(pLogMgr);

日志输出宏详解

SOUI 提供了丰富的日志输出宏,满足不同场景的使用需求:

流式输出宏

基于 kLogTag 的流式输出

// 流式输出日志,当 kLogTag 有效时使用,否则编译失败
// kLogTag 可以是当前定义的宏,也可以是当前对象的成员变量
#define SLOGD() SLOG(kLogTag,SOUI::Log::LOG_DEBUG,0)
#define SLOGI() SLOG(kLogTag,SOUI::Log::LOG_INFO,0)
#define SLOGW() SLOG(kLogTag,SOUI::Log::LOG_WARN,0)
#define SLOGE() SLOG(kLogTag,SOUI::Log::LOG_ERROR,0)
#define SLOGF() SLOG(kLogTag,SOUI::Log::LOG_FATAL,0)

手动指定 Tag 的流式输出

// 流式输出日志,每条日志手动指定 tag
#define SLOGD2(tag) SLOG(tag,SOUI::Log::LOG_DEBUG,0)
#define SLOGI2(tag) SLOG(tag,SOUI::Log::LOG_INFO,0)
#define SLOGW2(tag) SLOG(tag,SOUI::Log::LOG_WARN,0)
#define SLOGE2(tag) SLOG(tag,SOUI::Log::LOG_ERROR,0)
#define SLOGF2(tag) SLOG(tag,SOUI::Log::LOG_FATAL,0)

格式化输出宏

基于 kLogTag 的格式化输出

// 格式化输出日志,当 kLogTag 有效时使用
#define SLOGFMTD(logformat, ...) SLOG_FMT(kLogTag,SOUI::Log::LOG_DEBUG,0,logformat,##__VA_ARGS__)
#define SLOGFMTI(logformat, ...) SLOG_FMT(kLogTag,SOUI::Log::LOG_INFO,0,logformat,##__VA_ARGS__)
#define SLOGFMTW(logformat, ...) SLOG_FMT(kLogTag,SOUI::Log::LOG_WARN,0,logformat,##__VA_ARGS__)
#define SLOGFMTE(logformat, ...) SLOG_FMT(kLogTag,SOUI::Log::LOG_ERROR,0,logformat,##__VA_ARGS__)
#define SLOGFMTF(logformat, ...) SLOG_FMT(kLogTag,SOUI::Log::LOG_FATAL,0,logformat,##__VA_ARGS__)

手动指定 Tag 的格式化输出

// 格式化输出日志,每条日志手动指定 tag
#define SLOGFMTD2(tag,logformat, ...) SLOG_FMT(tag,SOUI::Log::LOG_DEBUG,0,logformat,##__VA_ARGS__)
#define SLOGFMTI2(tag,logformat, ...) SLOG_FMT(tag,SOUI::Log::LOG_INFO,0,logformat,##__VA_ARGS__)
#define SLOGFMTW2(tag,logformat, ...) SLOG_FMT(tag,SOUI::Log::LOG_WARN,0,logformat,##__VA_ARGS__)
#define SLOGFMTE2(tag,logformat, ...) SLOG_FMT(tag,SOUI::Log::LOG_ERROR,0,logformat,##__VA_ARGS__)
#define SLOGFMTF2(tag,logformat, ...) SLOG_FMT(tag,SOUI::Log::LOG_FATAL,0,logformat,##__VA_ARGS__)

SOUI 内部使用宏

// SOUI4 内部使用的日志输出,自动将 TAG 定义为 soui4
#define kSoui4Tag "soui4"
#define SSLOGD() SLOG(kSoui4Tag,SOUI::Log::LOG_DEBUG,0)
#define SSLOGI() SLOG(kSoui4Tag,SOUI::Log::LOG_INFO,0)
#define SSLOGW() SLOG(kSoui4Tag,SOUI::Log::LOG_WARN,0)
#define SSLOGE() SLOG(kSoui4Tag,SOUI::Log::LOG_ERROR,0)
#define SSLOGF() SLOG(kSoui4Tag,SOUI::Log::LOG_FATAL,0)

#define SSLOGFMTD(logformat, ...) SLOG_FMT(kSoui4Tag,SOUI::Log::LOG_DEBUG,0,logformat,##__VA_ARGS__)
#define SSLOGFMTI(logformat, ...) SLOG_FMT(kSoui4Tag,SOUI::Log::LOG_INFO,0,logformat,##__VA_ARGS__)
#define SSLOGFMTW(logformat, ...) SLOG_FMT(kSoui4Tag,SOUI::Log::LOG_WARN,0,logformat,##__VA_ARGS__)
#define SSLOGFMTE(logformat, ...) SLOG_FMT(kSoui4Tag,SOUI::Log::LOG_ERROR,0,logformat,##__VA_ARGS__)
#define SSLOGFMTF(logformat, ...) SLOG_FMT(kSoui4Tag,SOUI::Log::LOG_FATAL,0,logformat,##__VA_ARGS__)

使用示例

流式日志输出

使用 SLOGx 系列宏需要在当前代码中定义 kLogTag 宏或可访问变量:

#define kLogTag "demo"

// 使用流式输出
SLOGI() << "test=" << 200;
SLOGW() << "warning message: " << "something went wrong";
SLOGE() << "error occurred: " << GetLastError();

如果希望使用不同的 tag,可以使用 SLOGx2 系列宏:

SLOGI2("tag1") << "test=" << 200;
SLOGI2("tag2") << "another test=" << 300;
SLOGW2("network") << "connection timeout";

格式化日志输出

SOUI 还提供了格式化输出宏,使用方式类似于 printf:

#define kLogTag "demo"

// 格式化输出(基于 kLogTag)
SLOGFMTE(L"log output using unicode format,str=%s, tick=%u", L"中文", GetTickCount());
SLOGFMTI("log output using ansi format,str=%s, tick=%u", "test", GetTickCount());

// 格式化输出(手动指定 tag)
SLOGFMTE2("newtag", L"log output using unicode format,str=%s, tick=%u", L"中文", GetTickCount());

注意:在格式化输出宏中,会根据 format 参数自动选择以宽字符还是 Ansi 字符串来格式化输出。如果 format 是宽字符,则后续的 %s 对应的字符串也必须是宽字符串。

SOUI 内部日志

SSLOGx 系列宏是 SOUI 内部使用的宏,与前面几组宏的唯一区别在于自动将 tag 固定为 "soui4":

SSLOGI() << "internal SOUI message";
SSLOGFMTE("error in SOUI module: %s", "module failed to initialize");

最佳实践

  1. 合理使用日志级别
  2. DEBUG:调试信息,用于开发阶段
  3. INFO:一般信息,用于记录程序运行状态
  4. WARN:警告信息,程序可以继续运行
  5. ERROR:错误信息,功能受到影响
  6. FATAL:致命错误,程序无法继续运行

  7. 统一 Tag 命名

  8. 在每个模块的开始定义 kLogTag
  9. 使用有意义的 tag 名称,便于日志分类和过滤

  10. 性能考虑

  11. 避免在高频调用的代码中输出 DEBUG 级别日志
  12. 生产环境中可适当调整日志级别

  13. 字符编码注意

  14. 宽字符和 Ansi 字符串要匹配使用
  15. 在格式化输出中特别注意字符串类型一致性

通过合理使用 SOUI 的日志系统,可以大大提高应用程序的可调试性和可维护性。