# 日志模块配置
## 日志模块简介
长安链采用Go语言开发,使用Go语言领域最流行的zap包作为日志记录的实现。按长安链整体软件架构设计,日志模块被定义为通用日志记录器放到common包中,长安链日志接口放到protocol包中,以及长安链日志实现模块放在logger包中。而在各个业务模块中记录日志时,只需要使用protocol.Logger接口即可,从而解耦了各个模块对日志包的依赖,便于各个模块的单元测试和模块级测试。下面分别对各个日志包进行介绍:
### common/log
在chainmaker.org/chainmaker/common/log包中,对zap进行了封装,增强了日志文件滚动输出和配置简化。如果是common包或者其他基础软件包有记录日志的需求,可以直接使用该log包的LoggerInterface。
### protocol.Logger
在长安链整体架构中,将日志的功能定义为如下接口:protocol.Logger
```go
type Logger interface {
Debug(args ...interface{})
Debugf(format string, args ...interface{})
Debugw(msg string, keysAndValues ...interface{})
Error(args ...interface{})
Errorf(format string, args ...interface{})
Errorw(msg string, keysAndValues ...interface{})
Fatal(args ...interface{})
Fatalf(format string, args ...interface{})
Fatalw(msg string, keysAndValues ...interface{})
Info(args ...interface{})
Infof(format string, args ...interface{})
Infow(msg string, keysAndValues ...interface{})
Panic(args ...interface{})
Panicf(format string, args ...interface{})
Panicw(msg string, keysAndValues ...interface{})
Warn(args ...interface{})
Warnf(format string, args ...interface{})
Warnw(msg string, keysAndValues ...interface{})
DebugDynamic(getStr func() string)
InfoDynamic(getStr func() string)
}
```
各个长安链业务模块在代码中需要记录日志时,都引用这个日志接口即可,而不用关心日志记录的实现。
### logger的实现
在chainmaker.org/chainmaker/logger项目中基于common/log(zap的封装)提供了protocol.Logger的实例化实现,这也是在实际长安链使用时的实现。另外为了单元测试的方便,系统还提供了:
* protocol.test.GoLogger 通过系统的log打印日志
* protocol.test.HoleLogger 不打印日志
* protocol.test.TestLogger 通过testing对象打印日志
* protocol.mock.MockLogger 基于gomock的日志接口实现
## 日志配置
在实际长安链的使用中,一般通过独立的log.yml配置文件来配置长安链节点的日志行为。系统启动时通过读取chainmaker.yml中的log/config_file配置获得log.yml的路径,并读取该日志配置内容。
### 基本配置
```yml
log:
system:
log_level_default: INFO # 默认日志级别,可配:DEBUG,INFO,WARN,ERROR
file_path: ./log/system.log # 日志文件路径
max_age: 365 # 日志最长保存时间,单位:天
rotation_time: 1 # 日志滚动时间,单位:小时
rotation_size: 100 # 日志滚动大小,单位:MB
log_in_console: true # 是否展示日志到终端,仅限于调试使用
show_color: true # 是否打印颜色日志
stack_trace_level: ERROR # 设置 stack trace 日志级别,当日志信息大于等于此级别时将会输出 stack trace, 置空或无效级别将不会打开 stack trace
is_compress: false #是否启用日志压缩;启用后历史文件会被压缩
no_compress_count: 3 #不压缩的文件数量(需要>=1)
hmac_key: password #日志完整性;设置后,每行日志生成 hmac,历史日志文件最后追加 hmac
archive_path: ./log/archive #日志归档路径
sensitive_data_filtering: false #是否启用敏感数据过滤
sensitive_data_encryption_key: password #敏感数据加密密钥
multiple_log_files: false #是否启用多日志文件;启用后不同级别的日志保存到不同文件夹中
```
最简单的情况下,log.yml中只需要配置log/system即可,其中允许的配置属性和说明如下:
| 配置项 | 默认值 | 说明 |
|:------------------------------|:--------------|:-------------------------------|
| log_level_default | DEBUG | 日志记录级别,大于等于这个级别则记录日志 |
| log_levels | 空 | 指定模块的日志级别 |
| file_path | ./default.log | 日志记录的文件名 |
| max_age | 365 | 日志最长保存时间,单位:天 |
| rotation_time | 6 | 日志滚动间隔,单位:小时 |
| rotation_size | 100 | 默认的日志滚动大小,单位:MB |
| log_in_console | true | 是否向控制台输出日志 |
| log_by_chain | false | [根据链ID分文件夹记录日志](#log_by_chain) |
| json_format | false | 以JSON格式输出日志 |
| show_color | true | 控制台打印彩色日志 |
| stack_trace_level | ERROR | 哪种日志级别时打印调用堆栈 |
| kafka | 空 | [向Kafka输出日志](#kafka) |
| is_compress | false | 是否启用日志压缩 |
| no_compress_count | 1 | 不压缩的文件数量(需要 >=1) |
| hmac_key | 空 | 日志完整性;设置后,每行日志生成 hmac |
| archive_path | 空 | 日志归档路径 |
| sensitive_data_filtering | false | 是否启用敏感数据过滤 |
| sensitive_data_encryption_key | 空 | 敏感数据加密密钥 |
| multiple_log_files | false | 是否启用多日志文件 |
### 按模块配置日志
#### 模块列表
| 日志中的打印的模块名 | 配置的模块名 | 说明 |
|:-------------|:-----------|:-------|
| [Access] | access | 访问控制 |
| [Blockchain] | blockchain | 主模块 |
| [ChainConf] | chainconf | 链配置 |
| [Cli] | cli | 命令行 |
| [Consensus] | consensus | 共识 |
| [Core] | core | 核心 |
| [DPoS] | dpos | DPos共识 |
| [Ledger] | ledger | 账本 |
| [Monitor] | monitor | 监控 |
| [Net] | net | 网络 |
| [Rpc] | rpc | RPC服务 |
| [Snapshot] | snapshot | 快照 |
| [Storage] | storage | 存储 |
| [Sync] | sync | 同步 |
| [TxFilter] | txfilter | 交易过滤 |
| [TxPool] | txpool | 交易池 |
| [Vm] | vm | 虚拟机 |
#### 按模块配置不同日志级别
如果日志级别设置为INFO,而特别关注某几个模块的日志,想针对某几个模块的日志记录为DEBUG,则日志配置如下所示:
```yml
log:
system:
log_level_default: INFO
log_levels:
core: DEBUG
vm: DEBUG
file_path: ./log/system.log
……
```
#### 按模块配置不同路径、级别等
除system配置外,长安链还支持针对不同的模块进行完全不同的日志配置,包括日志输出路径、日志级别、日志滚动等等,将[日志配置](#log_config)的各项配置到log/module/模块名/模块日志配置下。
比如系统默认是INFO级别,而指定交易池的日志配置为DEBUG级别,单独记录在./log/txpool.log文件中,则日志配置如下:
```yml
log:
system:
log_level_default: DEBUG
file_path: ./log/system.log
module:
txpool:
log_level_default: INFO
file_path: ./log/txpool.log
max_age: 365 # 日志最长保存时间,单位:天
rotation_time: 1 # 日志滚动间隔,单位:小时
rotation_size: 100 # 日志滚动大小,单位:MB
log_in_console: false # 是否展示日志到终端,仅限于调试使用
show_color: false # 是否打印颜色日志
```
### 多链模式下按ChainId输出
在多子链模式下,默认所有子链的日志都记录到同一个日志文件中,如果希望对不同的子链分别记录到不同的文件夹,则需要开启log_by_chain配置。开启该配置后,系统会根据配置的日志路径,在日志文件夹中根据子链ChainId创建同名的文件夹,然后将对应子链的日志文件记录到文件夹下。比如当前节点有chain1和chain2两个子链,并而日志配置如下:
```yml
log:
system:
log_level_default: INFO
file_path: ./log/system.log
log_by_chain: true
```
那么系统将会把日志记录到:
* ./log/chain1/system.log
* ./log/chain2/system.log
### 日志向Kafka输出
在一些以云原生为基础的场景下,可能希望将日志输出到第三方云服务(比如腾讯云日志服务CLS)或者是Kafka中,为此日志模块提供了作为Kafka生产者,将记录日志文件的同时将日志输出到Kafka的能力。
#### Kafka日志配置
Kafka子项的配置如下:
```yml
log:
system:
log_level_default: INFO
file_path: ./log/org1/system.log
kafka: # Kafka配置子项
servers:
- "kafkaserver:9096" # Kafka服务器IP端口,可以是多个
compression: 1 # 是否压缩:0不压缩,1 Gzip,2 snappy,3 LZ4,4 ZSTD
topic: "" # 默认Kafka主题
topic_mapping: # 指定不同的子链对应不同的主题
"chain1":"topic1" # 子链ChainId对应的Kafka主题
"chain2":"topic2"
kafka_version: "" # 指定Kafka版本,空表示不指定版本
sasl: # Kafka安全设置
enable: true # 是否启用安全验证
username: "user1" # 用户名
password: "1" # 密码
mechanism: PLAIN # 模式:OAUTHBEARER或者PLAIN
version: 1 # SASL协议版本
```
## 日志查看
### VM日志查看
此处介绍在智能合约中使用长安链提供的log接口的日志查看方式。
使用 `wasmer`、`gasm`、`wxvm`引擎日志所在位置为:log/system.log。模块为[vm]
使用`dockergo`引擎日志所在位置为:
- log/orgid/go/go.log(默认)
- log/orgid/docker-go/docker-go.log(旧版)
日志格式为:
```
`date` [`logLevel`] [Contract `chainId`#o#`contractName`#`version`#0#99] `log`
```
示例如下:
```
2022-11-22 18:15:19.816 [INFO] [Contract chainmaker_testnet_chain#o#test_leader5#1.0#0#99] save key=1669112119
```