Skip to content

Latest commit

 

History

History
137 lines (93 loc) · 4.84 KB

readme.md

File metadata and controls

137 lines (93 loc) · 4.84 KB

日志优化

新版日志是以原来的 spdlog-1.6.1 为基础修改而来, 主要变动有:

  1. 新增审计日志级别 rtt.LogLevel.Audit
  2. 新增关闭日志级别 rtt.LogTrace.Off
  3. 新增日志输出格式 set_backend_logpattern
  4. 修改 set_backend_logfile 函数, 支持通过 task_id 映射日志句柄
  5. 优化流式打印
  6. 新增fmt打印

1 日志级别

日志级别共有七类

[07-19 18:36:56 leaker@ubuntu ~/Desktop/tmp/Rosetta0712]$ more cc/python_export/_rosetta.cc
py::enum_<LogLevel>(m, "LogLevel")
.value("Trace", LogLevel::Trace)
.value("Debug", LogLevel::Debug)
.value("Audit", LogLevel::Audit)
.value("Info",  LogLevel::Info)
.value("Warn",  LogLevel::Warn)
.value("Error", LogLevel::Error)
.value("Fatal", LogLevel::Fatal)
.value("Off", LogLevel::Off)

其中, LogLevel::Audit 为新增日志级别. 当日志级别设为 LogLevel::Off 时, 则关闭所有日志(包括控制台日志). 调用格式为:

#!/usr/bin/env python3

import latticex.rosetta as rtt
import tensorflow as tf

...

rtt.set_backend_loglevel(rtt.LogLevel.Info) # info level

2 日志输出样式

日志输出样式由 set_backend_logpattern (python调用层)和 set_pattern (日志底层)函数控制. 其格式定义为: SPDLOG_ROSETTA_LOGGER_PATTERN . 需要主要的是, Release 版本和 Debug 版本的缺省输出样式有所不同:

  1. Debug: %Y-%m-%d %H:%M:%S.%e|%^%l%$|%s:%#|%!|%v
  2. Release: %Y-%m-%d %H:%M:%S.%e|%^%l%$|%v

即Debug版本的日志会带有 file:line ( %s:%# ) 和函数名 ( %! )

3 日志文件

日志文件名设置函数为: set_backend_logfile (python调用层)和 set_filename (日志底层)函数控制. 相对旧版, 新版新增了一个参数 task_id. 用于查找日志文件句柄.

函数定义为:

void Logger::set_filename(const std::string& filename, const std::string& task_id="");

函数实现逻辑为:

  1. 查找日志文件 filename 是否存在, 存在则函数返回. 反之, 转下一步
  2. 判断 task_id 是否为空字符串. 如果非空, 则创建一个异步非阻塞的常规日志文件( auto logger = spdlog::create_async_nb<spdlog::sinks::basic_file_sink_mt>(task_id.c_str(), filename.c_str()) ), 并把 filenametask_id 做关联后, 成功返回. 反之, 转下一步.
  3. 判断缺省的日志句柄 SPDLOG_ROSETTA_LOGGER_NAME 是否已经存在。如果存在, 则创建一个异步非阻塞的常规日志文件, 然后把文件名作为日志文件的句柄. 反之, 转下一步.
  4. 创建一个异步非阻塞的常规日志文件, 然后把缺省的日志文件句柄和该日志文件做关联

4 流式日志

流式日志是通过宏 SPDLOG_LOGGER_STREAM 实现:

#define SPDLOG_LOGGER_STREAM(log, lvl)    LogStream(log, lvl, spdlog::source_loc{__FILE__, __LINE__, __FUNCTION__}) == LogLine()

其底层实现为 LogLine 类. 主要是把以前旧版的 继承std::ostringstream 更改为 组合 . 具体实现为:

class LogLine 
{
public:
LogLine() {
}

template<typename T> LogLine& operator<<(const T& t) { 
ss_ << t; 

return *this; 
}

std::string str() const { 
return ss_.str(); 
}

private:
std::ostringstream ss_;
};

5 fmt日志

fmt日志是通过宏 SPDLOG_LOGGER_CALL_FUNCTION 实现:

#define SPDLOG_LOGGER_CALL_FUNCTION(logger, level, ...) (logger)->log(spdlog::source_loc{__FILE__, __LINE__, __FUNCTION__}, level, ##__VA_ARGS__)

每种日志级别的宏定义(以AUDIT为例):

#define TAUDIT_(task_id, ...) \
   do {\
   if (Logger::Get().get_log_to_stdout()) { \
   SPDLOG_LOGGER_CALL_FUNCTION(spdlog::default_logger(), spdlog::level::audit, ##__VA_ARGS__); \
   } \
   std::shared_ptr<spdlog::logger> logger = Logger::Get().get_logger(task_id); \
   if (logger != nullptr && logger != spdlog::default_logger())  {\
   SPDLOG_LOGGER_CALL_FUNCTION(Logger::Get().get_logger(task_id), spdlog::level::audit, ##__VA_ARGS__); \
   } \
   } while(0)

#define AUDIT(...) TAUDIT_(context_->TASK_ID, ##__VA_ARGS__)

6 注意事项

  1. 流式日志( log_/tlog_ 系列)不支持std::endl强刷, 因为日志带有换行功能
  2. 如果有隐式的 TASK_ID , 请使用 log_ 系列, 不要使用 tlog_ 系列(其实, 绝大部分日志打印都是使用 log_ 系列, 除非是单模板函数没有 TASK_ID 的日志打印的话, 才需要使用 tlog_ 系列)
  3. 基于点 2 , 流式日志请直接使用 log_ 系列. 因为如果是错误使用, 编译会直接报错
  4. 如果是 Debug 模式的日志输出, 请不要再次使用 __FUNCTION__ , __func__, __PRETTY_FUNCTION__, __LINE__, __FILENAME__ 等和宏定义, 因为Debug模式下, 日志已经带了文件名:行号和函数名的相关信息