通过一个完整的例子,在gogf/gf框架内合理管理日志。
使用场景有哪些?
日志自动滚动 拆分成多个日志文件 日志格式修改等待
我们将使用rk-boot来启动gogf/gf框架的微服务。
完整教程请访问以下地址:
- https://rkdocs.netlify.app/cn
简要概念去 github.com/rookie-ninja/rk-boot/gf
Rk boot 使用以下两个库来管理日志。
-
zap管理日志实例
-
伐木工人管理日志滚动
rk boot 定义了两种日志类型,后面会详细介绍。这里有一个简单的介绍。
-
ZapLogger:标准日志,用于记录Error、Info等。
-
事件记录器:JSON或Console格式,用于记录事件,例如RPC请求。
在本例中,我们将尝试更改 zap 日志的路径和格式。
1.创建启动 yaml
---
zapLogger:
- 名称:zap-log # 必需
扎普:
encoding: json # 可选,选项:console, json
outputPaths: ["logs/zap.log"] # 可选
女朋友:
- 名称:迎宾员
端口:8080
启用:真
2.创建主程序
将日志写入 zap 日志实例。
// 版权所有 (c) 2021 菜鸟忍者
//
// 此源代码的使用由 Apache 风格管理
// 可以在 LICENSE 文件中找到的许可证。
包主
进口(
“上下文”
“github.com/rookie-ninja/rk-boot”
_“github.com/rookie-ninja/rk-boot/gf”
)
功能主() {
// 创建一个新的启动实例。
引导 :u003d rkboot.NewBoot()
// 引导
boot.Bootstrap(context.Background())
// 写 zap 日志
boot.GetZapLoggerEntry("zap-log").GetLogger().Info("这是zap-log")
// 等待关机信号
boot.WaitForShutdownSig(context.Background())
}
3.确认
文件夹结构
├── boot.yaml
├── go.mod
├── go.sum
├── 原木
│ └── zap.log
└── main.go
日志输出
配置EventLogger{"level":"INFO","ts":"2021-10-21T02:10:09.279+0800","msg":"这是 zap-log"}
在上面的示例中,我们配置了 zap 日志。这一次,我们修改了EventLogger。
1.创建启动 yaml
---
事件记录器:
- 名称:事件日志 # 必需
encoding: json # 可选,选项:console, json
outputPaths: ["logs/event.log"] # 可选
女朋友:
- 名称:迎宾员
端口:8080
启用:真
2.创建主程序
将日志写入事件日志实例。
包主
进口(
“上下文”
“github.com/rookie-ninja/rk-boot”
“github.com/rookie-ninja/rk-entry/entry”
)
功能主() {
// 创建一个新的启动实例。
引导 :u003d rkboot.NewBoot()
// 引导
boot.Bootstrap(context.Background())
// 写事件日志
helper :u003d boot.GetEventLoggerEntry("事件日志").GetEventHelper()
事件 :u003d helper.Start("demo-event")
event.AddPair("key", "value")
helper.Finish(事件)
// 等待关机信号
boot.WaitForShutdownSig(context.Background())
}
3.开始主线
$ 去运行 main.go
4.确认
文件夹结构
├── boot.yaml
├── go.mod
├── go.sum
├── 原木
│ └── event.log
└── main.go
日志内容
概念{"endTime": "2022-01-18T22:18:44.926+0800", "startTime": "2022-01-18T22:18:44.926+0800", "elapsedNano": 746, "timezone": "CST ", "ids": {"eventId":"2aaea6f5-c7ac-4245-ac50-857726f3ede4"}, "app": {"appName":"rk","appVersion":"","entryName":"" ,"entryType":""}, "env": {"arch":"amd64","az":"*","domain":"*","hostname":"lark.local", "localIP":"10.8.0.2","os":"darwin","realm":"*","region":"*"}, "payloads": {}, "error": {} , "counters": {}, "pairs": {"key":"value"}, "timing": {}, "remoteAddr": "localhost", "operation": "demo-event", "eventStatus" : "结束", "resCode": "OK"}
在上面的例子中,我们尝试了 ZapLogger 和 EventLogger。接下来看看rk boot是如何实现和使用的。
框架zvz100016 ZapLoggerEnta
ZapLoggerEntry 是对 zap 实例的封装。
// ZapLoggerEntry 包含以下字段。
// 1: EntryName:条目的名称。
// 2:EntryType:入口类型,ZapLoggerEntryType。
// 3:EntryDescription:ZapLoggerEntry 的描述。
// 4: Logger: zap.Logger,一开始就被初始化了。
// 5: LoggerConfig: zap.Logger 配置,一开始就初始化了,初始化后就无法访问了..
// 6: LumberjackConfig: lumberjack.Logger,一开始就被初始化了。
类型 ZapLoggerEntry 结构 {
条目名称字符串 `yaml:"entryName" json:"entryName"`
EntryType 字符串 `yaml:"entryType" json:"entryType"`
EntryDescription 字符串 `yaml:"entryDescription" json:"entryDescription"`
记录器 *zap.Logger `yaml:"-" json:"-"`
LoggerConfig *zap.Config `yaml:"zapConfig" json:"zapConfig"`
LumberjackConfig *lumberjack.Logger `yaml:"lumberjackConfig" json:"lumberjackConfig"`
}
如何开机在yaml中配置ZapLoggerEntry?
zapLoggerEntry 完全兼容和lumberjack的 YAML 结构。
用户可以根据需要配置多个ZapLogger实例,通过名称访问。
完整配置:
---
zapLogger:
- 名称:zap-logger # 必需
描述:“条目描述”# 可选
扎普:
level: info # 可选,默认:info,选项:[debug, DEBUG, info, INFO, warn, WARN, dpanic, DPANIC, panic, PANIC, fatal, FATAL]
development: true # 可选,默认:true
disableCaller: false # 可选,默认:false
disableStacktrace: true # 可选,默认:true
sampling: # 可选,默认:空地图
初始:0
此后:0
编码:console # 可选,默认:“console”,选项:[console, json]
编码器配置:
messageKey: "msg" # 可选,默认:"msg"
levelKey: "level" # 可选,默认:"level"
timeKey: "ts" # 可选,默认:"ts"
nameKey: "logger" # 可选,默认:"logger"
callerKey: "caller" # 可选,默认:"caller"
functionKey: "" # 可选,默认:""
stacktraceKey: "stacktrace" # 可选,默认:"stacktrace"
lineEnding: "\n" # 可选,默认:"\n"
levelEncoder: "capitalColor" # 可选,默认:"capitalColor",选项:[capital, capitalColor, color, lowercase]
timeEncoder: "iso8601" # 可选,默认:"iso8601",选项:[rfc3339nano, RFC3339Nano, rfc3339, RFC3339, iso8601, ISO8601, millis, nanos]
durationEncoder: "string" # 可选,默认:"string",选项:[string, nanos, ms]
callerEncoder: "" # 可选,默认:""
nameEncoder: "" # 可选,默认:""
consoleSeparator: "" # 可选,默认:""
outputPaths: [ "stdout" ] # 可选,默认:["stdout"],如果指定stdout会被替换
errorOutputPaths: [ "stderr" ] # 可选,默认:["stderr"],如果指定,stderr 将被替换
initialFields: # 可选,默认:空地图
关键:“价值”
伐木工人:# 可选
filename: "rkapp-event.log" # 可选,默认:如果为空,则在 os.TempDir() 中使用 <processname>-lumberjack.log。
maxsize: 1024 # 可选,默认值:1024 (MB)
maxage: 7 # 可选,默认:7(天)
maxbackups: 3 # 可选,默认值:3(天)
localtime: true # 可选,默认:true
compress: true # 可选,默认:true
如何在代码中获取ZapLogger?
通过名称访问。
引导 :u003d rkboot.NewBoot()
// 访问入口
boot.GetZapLoggerEntry("zap-logger")
// 访问 zap 记录器
boot.GetZapLoggerEntry("zap-logger").GetLogger()
// 访问 zap 记录器配置
boot.GetZapLoggerEntry("zap-logger").GetLoggerConfig()
// 访问伐木工人配置
EventLoggerEntryboot.GetZapLoggerEntry("zap-logger").GetLumberjackConfig()
rk boot 将每个 RPC 请求视为一个 Event,并使用rk-queryEvent type in 进行日志记录。
// EventLoggerEntry 包含以下字段。
// 1: EntryName:条目的名称。
// 2:EntryType:条目类型,EventLoggerEntryType。
// 3:EntryDescription:EventLoggerEntry的描述。
// 4: EventFactory: rkquery.EventFactory 一开始就被初始化了。
// 5: EventHelper: rkquery.EventHelper 一开始就被初始化了。
// 6:LoggerConfig:zap.Config,一开始就初始化了,初始化后无法访问。
// 7: LumberjackConfig: lumberjack.Logger,一开始就被初始化了。
类型 EventLoggerEntry 结构 {
条目名称字符串 `yaml:"entryName" json:"entryName"`
EntryType 字符串 `yaml:"entryType" json:"entryType"`
EntryDescription 字符串 `yaml:"entryDescription" json:"entryDescription"`
事件工厂*rkquery.EventFactory `yaml:"-" json:"-"`
事件助手 *rkquery.EventHelper `yaml:"-" json:"-"`
LoggerConfig *zap.Config `yaml:"zapConfig" json:"zapConfig"`
LumberjackConfig *lumberjack.Logger `yaml:"lumberjackConfig" json:"lumberjackConfig"`
}
事件记录器字段
我们可以看到 EventLogger 打印的日志包含字段。让我们介绍一下这些领域。
场地
细节
时间结束
时间结束
开始时间
开始时间
经过纳米
事件时间开销(纳秒)
时区
时区
身份证
包含 eventId、requestId 和 traceId。如果启动了原来的数据拦截器,或者 event 就像两颗豌豆一样,用户调用了 SetRequest(),就会使用新的 RequestId,eventId 和 requestId 完全一样。如果调用链拦截器启动,traceId会被记录。
应用程序
包含appName,appVersion,entryName,entryType。
环境
包括arch、AZ、DOMAIN、hostname、localip、OS、REALM、REGION REALM、REGION、AZ、DOMAIN字段。这些字段来自系统环境变量(real、REGION、AZ、DOMAIN)。 “*”表示环境变量为空。
有效载荷
包含 RPC 相关信息。
错误
包含错误。
计数器
通过事件 Setcounter()。
对
通过事件 Addpair()。
定时
通过事件 Starttimer() 和事件 Endtimer()。
远程地址
RPC 远程地址。
手术
RPC 名称。
资源代码
RPC 返回码。
事件状态
已结束或进行中
例子
------------------------------------------------ ----------------------
结束时间u003d2021-11-27T02:30:27.670807+08:00
开始时间u003d2021-11-27T02:30:27.670745+08:00
经过纳米u003d62536
时区u003dCST
idsu003d{"eventId":"4bd9e16b-2b29-4773-8908-66c860bf6754"}
appu003d{"appName":"gf-demo","appVersion":"master-f948c90","entryName":"greeter","entryType":"GfEntry"}
envu003d{"arch":"amd64","az":"*","domain":"*","hostname":"lark.local","localIP":"10.8.0.6", "os":"darwin","realm":"*","region":"*"}
payloadsu003d{"apiMethod":"GET","apiPath":"/rk/v1/healthy","apiProtocol":"HTTP/1.1","apiQuery":"","userAgent":"curl/7.64 .1"}
错误u003d{}
计数器u003d{}
对u003d{}
时间u003d{}
remoteAddru003dlocalhost:61726
操作u003d/rk/v1/healthy
resCodeu003d200
事件状态u003d结束
EOE
如何开机在yaml中配置EventLoggerEntry?
EventLoggerEntry 会将应用程序名称注入到事件中。启动器将从 go 从 mod 文件中提取应用程序名称开始。如果没有 go Mod 文件,则启动器将使用默认名称。
用户可以根据需要配置多个EventLogger实例,通过名称访问。
完整配置:
---
事件记录器:
- 名称:事件记录器 # 必需
描述:“这是描述”# 可选
encoding: console # 可选,默认:console,options:console and json
outputPaths: ["stdout"] # 可选
伐木工人:# 可选
filename: "rkapp-event.log" # 可选,默认:如果为空,则在 os.TempDir() 中使用 <processname>-lumberjack.log。
maxsize: 1024 # 可选,默认值:1024 (MB)
maxage: 7 # 可选,默认:7(天)
maxbackups: 3 # 可选,默认值:3(天)
localtime: true # 可选,默认:true
compress: true # 可选,默认:true
如何获取代码中的EventLogger?
通过名称访问。
引导 :u003d rkboot.NewBoot()
// 访问入口
boot.GetEventLoggerEntry("事件记录器")
// 访问事件工厂
boot.GetEventLoggerEntry("事件记录器").GetEventFactory()
// 访问事件助手
boot.GetEventLoggerEntry("事件记录器").GetEventHelper()
// 访问伐木工人配置
boot.GetEventLoggerEntry("事件记录器").GetLumberjackConfig()
如何使用Event?
Event 是一个包含多个方法的接口。请参考:事件
常用方法:
引导 :u003d rkboot.NewBoot()
// 获取 EventHelper 创建 Event 实例
helper :u003d boot.GetEventLoggerEntry("事件日志").GetEventHelper()
// 开始和结束事件
事件 :u003d helper.Start("demo-event")
helper.Finish(事件)
// 添加K/V
event.AddPair("key", "value")
// 开始和结束计时器
event.StartTimer("我的计时器")
event.EndTimer("我的计时器")
// 设置计数器
event.SetCounter("我的计数器", 1)