日志记录
本节将介绍如何在 Go-Sail 中进行日志记录。
简介
日志记录几乎是每个系统都会执行的任务。原因很简单:日志可以帮助你追踪事件,从而便于定位和排查问题。
为了帮助你更好地洞察应用内部的运行状况,Go-Sail 提供了强大的日志服务,支持将日志信息记录到文件或通过导出器(exporter)输出。
配置
Go-Sail 的日志组件基于 uber/zap 日志库,并在服务启动时自动激活。你可以通过配置来指定其行为。
// 代码见原文,省略...
上面高亮的示例代码配置了 warn 级别,日志输出到当前目录下名为 running.log 的文件,并限制单个文件最大 100MB。Go-Sail 的日志组件支持日志轮转,无需担心日志文件体积过大或过多导致磁盘被填满。MaxBackups 表示最多保留 10 个最近的日志文件,且滚动的旧日志将被压缩,以进一步节省空间。
日志等级
日志等级决定哪些级别的日志会被记录,这一筛选是在配置阶段完成的,与具体调用什么日志方法无关。日志级别从低到高分为:
- debug
- info
- warn
- error
调用时可根据紧急和重要性优先选择。例如,普通信息可用 Info() 方法输出,当配置等级高于 info 时,代码里的此类日志不会被写入日志文件,从而实现全局管控。
import (
"github.com/keepchen/go-sail/v3/sail"
)
func main() {
sail.GetLogger().Info("记录一些日志...")
}
当设置的日志等级高于 info 时,以上代码的日志不会被写入文件,通过此机制实现统一的日志输出策略。
控制台输出(ConsoleOutput)
默认情况下,日志只输出到文件。但有时你可能希望开发调试时同时在终端看到日志,这时候只需要在配置中加上 ConsoleOutput 配置即可:
// 代码见原文,省略...
多模块(Modules)
模块配置的作用是将不同来源的日志分类记录到不同文件里,便于管理。比如可以将定时任务的日志单独写入名为 schedule 的文件。由于定时任务定期执行,日志重要但不多,分离日志便于后续查看。
在配置中声明需要的模块即可,使用时再调用对应模块:
// 代码见原文,省略...
如果你调用了一个没有配置的模块,日志会默认写到默认日志文件。
例如下面两行日志,都会被记录到同一个地方:
sail.GetLogger().Info("...")
sail.GetLogger("no-existent-module").Info("...")
日志导出器(Exporter)
通常情况下,Go-Sail 日志会输出到本地文件。这在开发环境并无问题,但在复杂的服务器或微服务环境下,本地存储不可靠且不可持久,日志通常需要转发到中央日志服务或 ELK 等日志中心。这时就可以使用日志导出器。
Go-Sail 的日志导出器会将日志同步到消息队列类中间件,后续由其它消费者消费和处理。目前支持以下中间件:
- Redis(单机)
- Redis(集群)
- Nats
- Kafka
注意,为保证数据不丢失,Redis 的导出器不是采用发布-订阅,而是用 List 结构执行 RPush,消费端应使用 LPop 获取。
声明日志导出器时,相关中间件如 Redis、NATS、Kafka 的连接信息需要分别单独配置。
这种设计是有意为之,为了核心服务的稳定性,初版就将日志导出配置与核心服务配置分离。若你没此类需求,也可以把两部分配置写成一样即可。
分布式链路追踪
用法
在 Web 应用程序中,记录和追踪整条链路(请求-处理-响应)很常见。
我们可能希望追踪关键事务或错误日志的全流程,便于排查与优化。这时就可用上分布式链路追踪。Go-Sail 启动时会自动启用链路追踪,你可以在路由处理函数中自由调用。
// 代码见原文,省略...
组件透传
要启用链路日志,推荐从上下文中获取日志组件进行输出,也可以将日志组件往下层函数传递实现更统一的日志记录。
// 代码见原文,省略...
微服务间链路追踪
在微服务环境下,多服务之间相互发起请求很常见。要想串联整个请求链路,需要传递请求唯一标识。如果你所有服务都用 Go-Sail,实现会自动处理。
以 Http 请求为例,只需在请求头加上 requestId 或 X-Request-Id 字段,值从当前请求上下文读取即可。
示例:
// 代码见原文,省略...
目前 Go-Sail 只自动处理 HTTP 请求,如果你的服务使用其它协议(如 gRPC),需要自行集成,但原理一致。