1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
|
#### 简介
MESA_handle_logger_new是基于开源C++日志库[easylogging++](https://github.com/muflihun/easyloggingpp)封装的新的日志库。具有以下特性:
* 线程安全
* 强大的配置功能
* 保留旧接口不变,完全兼容旧程序
#### 安装方法
```bash
git clone https://git.mesalab.cn/leo/MESA_handle_logger_new
cd MESA_handle_logger_new
make && make install #install到lib/下
export LD_LIBRARY_PATH="xxxx" #指定运行时链接的日志库为新的.so的目录
```
#### 对外接口
* 获取日志句柄
* 为了兼容旧程序,我们保留了旧的接口,同时提供了一个新的方法用来获取句柄
* MESA_create_runtime_log_handle( )和MESA_create_runtime_log_handle_new( )中会使用一份默认的日志配置。具体内容见src/MESA_handle_logger.c中的set_default_conf( )函数
```c++
/* functionality: 旧接口,用来获取日志句柄
params:
file_path: 日志文件保存路径, 长度不能超过256
level: 日志文件级别,>=该级别的日志才会输出,level = {RLOG_LV_DEBUG, RLOG_LV_INFO, RLOG_LV_FATAL }
returns:
void*: 返回一个日志句柄
*/
void *MESA_create_runtime_log_handle(const char *file_path, int level);
/* functionality: 新接口,用来获取日志句柄
desc: 新接口不用显示指定日志文件路径和日志级别,可以在配置文件配置或者通过MESA_set_runtime_log_handle_opt指定
对于新程序,我们推荐使用这种方法
params:
logger_id: 一个logger_id唯一标识一个日志句柄
returns:
void*: 返回一个日志句柄
*/
void* MESA_create_runtime_log_handle_new(const char* logger_id);
```
* 配置日志属性
* 我们提供了两种方法用来配置日志属性
* 读取配置文件
* 在代码中显式配置某个属性
```c++
/* functionality: 读取日志配置文件,我们推荐使用这种方法
params:
handle: 日志句柄
conf_file_path: 配置文件路径
returns:
0: 成功
-1: 失败
*/
int MESA_read_runtime_log_handle_conf(void* handle, const char* conf_file_path);
/* functionality: 设置某个日志属性
desc: 可配置的属性值见"可配置日志属性"
params:
handle: 日志句柄
level: 设置的日志级别,level = {RLOG_LV_DEBUG, RLOG_LV_INFO, RLOG_LV_FATAL }
key: 配置的属性
value: 配置的属性值
returns:
0: 成功
-1: 失败
*/
int MESA_set_runtime_log_handle_opt(void* handle, int level, const char* key, const char* value);
```
* 写日志
* 写日志接口保持和原来一致
```c++
/* functionality: 写日志
params:
handle: 日志句柄
level: 设置的日志级别,level = {RLOG_LV_DEBUG, RLOG_LV_INFO, RLOG_LV_FATAL }
module: 日志所属模块
fmt: 格式化字符串,单条日志长度不能超过4096
returns: none
*/
void MESA_handle_runtime_log(void *handle, int level, const char *module, const char *fmt, ...);
```
* 释放句柄
* 释放句柄保持和原来一致
```c++
/* functionality: 释放日志句柄
params:
handle: 日志句柄
returns: none
*/
void MESA_destroy_runtime_log_handle(void *handle);
```
#### 可配置日志属性
| Configuration Name | Description | Value |
| --- | --- | --- |
| `enabled` | Determines whether or not corresponding level for logger is enabled | {“true”, “false”} |
| `to_file` | Whether or not to write corresponding log to log file | {“true”, “false”} |
| `to_standard_output` | Whether or not to write logs to standard output e.g, terminal or command prompt | {“true”, “false”} |
| `format` | Determines format/pattern of logging for corresponding level and logger. | 如: ”[%level%datetime{%Y-%M-%d %H:%m:%s}]: %msg“ |
| `file_name` | Determines log file (full path) to write logs to for corresponding level and logger | 如: “./log2/debug_log_%datetime{%Y-%M-%d}“ |
| `max_log_file_size` | If log file size of corresponding level is >= specified size, log file will be truncated. | 如: “2097152” |
| `sub_second_precision` | Specifies subsecond precision (previously called 'milliseconds width')|{“1”, “2”, “3”, “4”, “5”, “6”,}|
|`performance_tracking` |determines whether or not performance tracking is enabled|{“true”, “false”}|
| `log_flush_threshold` | Specifies number of log entries to hold until we flush pending log data|如: “100” |
#### 日志格式说明符
| Specifier | Replaced By |
|-----------------|---------------------------------------------------------------------------------------------|
| `%logger` | Logger ID |
| `%thread` | Thread ID - Uses std::thread if available, otherwise GetCurrentThreadId() on windows |
| `%level` | Severity level (Info, Debug, Error, Warning, Fatal, Verbose, Trace) |
| `%levshort` | Severity level (Short version i.e, I for Info and respectively D, E, W, F, V, T) |
| `%vlevel` | Verbosity level (Applicable to verbose logging) |
| `%datetime` | Date and/or time - Pattern is customizable - see Date/Time Format Specifiers below |
| `%user` | User currently running application |
| `%host` | Computer name application is running on |
| `%file` | File name of source file (Full path) - This feature is subject to availability of `__FILE__` macro of compiler |
| `%fbase` | File name of source file (Only base name) | | `%line` | Source line number - This feature is subject to availability of `__LINE__` macro of compile |
| `%func` | Logging function |
| `%loc` | Source filename and line number of logging (separated by colon) |
| `%msg` | Actual log message | | `%` | Escape character (e.g, %%level will write %level) |
#### 日志配置文件格式
* 这里仅仅以FATAL级别的配置为例,完整配置参考sample/new/sample.conf
* %level, %datetime是日志格式说明符, 参考“日志格式说明符”
* GLOBAL是全局配置,作用于所有Level。其相当于一个开关。
* 若GLOBAL中配置了属性A:
* Level(DEBUG,INFO,FATAL)中配置了属性A:Level使用自己配置的属性A
* Level(DEBUG,INFO,FATAL)中没有配置属性A:Level使用GLOBAL中配置的属性A
* 若GLOBAL中没有配置属性A:
* 无论Level(DEBUG,INFO,FATAL)中是否配置属性A,属性A均不生效
```c++
* GLOBAL:
FORMAT = "[%level|%datetime{%Y-%M-%d %H:%M:%s}]: %msg"
FILENAME = "myeasylog.log"
ENABLED = true
TO_FILE = true
TO_STANDARD_OUTPUT = true
## SUBSECOND_PRECISION = 6
## PERFORMANCE_TRACKING = true
## MAX_LOG_FILE_SIZE = 2097152
## LOG_FLUSH_THRESHOLD = 100
* FATAL:
FORMAT = "[%level|%datetime{%Y-%M-%d %H:%m:%s}]: %msg" ##日志内容格式
FILENAME = "./log1/fatal_log_%datetime{%Y-%M-%d}" ##日志保存路径
ENABLED = true
TO_FILE = true
TO_STANDARD_OUTPUT = true
##SUBSECOND_PRECISION = 6 ## 暂时用不到
##PERFORMANCE_TRACKING = true ## 暂时用不到
##MAX_LOG_FILE_SIZE = 2097152 ## 文件最大值,超过该值后日志文件会truncated,这里是2MB
##LOG_FLUSH_THRESHOLD = 100 ## Flush after every 100 logs, 暂时用不到
```
#### 示例程序
* 旧程序
```c++
void* handle = MESA_create_runtime_log_handle("./log/sample_log", RLOG_LV_DEBUG);
MESA_handle_runtime_log(handle, RLOG_LV_DEBUG, "module", "test debug log:%s", "xxxxx");
MESA_destroy_runtime_log_handle(handle);
```
* 新程序
```c++
##通过读取配置文件设置日志属性
void* handle1 = MESA_create_runtime_log_handle_new("logger_id1");
int rtn = MESA_read_runtime_log_handle_conf(handle, "./sample.conf");
MESA_handle_runtime_log(handle, RLOG_LV_DEBUG, "module_test_read_conf", "test debug log:%s", "xxxxx");
MESA_destroy_runtime_log_handle(handle1);
##通过代码中显式设置某个日志属性
void* handle2 = MESA_create_runtime_log_handle("logger_id2");
MESA_set_runtime_log_handle_opt(handle, RLOG_LV_DEBUG, "enabled", "true");
MESA_set_runtime_log_handle_opt(handle, RLOG_LV_DEBUG, "to_file", "true");
MESA_set_runtime_log_handle_opt(handle, RLOG_LV_DEBUG, "to_standard_output", "true");
MESA_set_runtime_log_handle_opt(handle, RLOG_LV_DEBUG, "format", "[%level|%datetime{%Y-%M-%d %H:%m:%s}]: %msg");
MESA_set_runtime_log_handle_opt(handle, RLOG_LV_DEBUG, "file_name", "./log2/debug_log_%datetime{%Y-%M-%d}");
MESA_set_runtime_log_handle_opt(handle, RLOG_LV_DEBUG, "sub_second_precision", "6");
MESA_set_runtime_log_handle_opt(handle, RLOG_LV_DEBUG, "performance_tracking", "true");
MESA_set_runtime_log_handle_opt(handle, RLOG_LV_DEBUG, "max_log_file_size", "2097152");
MESA_set_runtime_log_handle_opt(handle, RLOG_LV_DEBUG, "log_flush_threshold", "100");
```
#### F.A.Q
* 对于旧的程序,如果想在不修改代码的情况下也想使用配置文件进行日志配置,可不可以呢?
* 可以,在旧接口MESA_create_runtime_log_handle( )中,我们会读取 **MESA_HANDLE_LOGGER_CONF_PATH**这个环境变量。然后根据环境变量中的路径读取配置文件进行配置。
* 所以你只需要编写配置文件,然后export MESA_HANDLE_LOGGER_CONF_PATH="xxxxx"就可以使用配置文件进行配置了。
* 其中xxxx为你的配置文件所在的路径
|