https://github.com/golang/glog
,是 google
提供的一个不维护的日志库, glog
有其他语言的一些版本,对我当时使用 log
库有很大的影响。它包含如下日志级别:Info
, Warning
, Error
, Fatal
(会中断程序执行)
还有类似 log4go
, loggo
,zap
等其他第三方日志库,他们还提供了设置日志级别的可见行,一般提供日志级别:Trace
, Debug
, Info
, Warning
, Error
, Critical
.
日志级别
Warning
没人看警告,因为从定义上讲,没有什么出错。也许将来会出问题,但这听起来像是别人的问题。我们尽可能的消除警告级别,它要么是一条信息性消息,要么是一个错误。我们参考 Go
语言设计哲学,所有警告都是错误,其他语言的 warning
都可以忽略,除非 IDE
或者在 CICD
流程中强制他们为 error
,然后逼着程序员们尽可能去消除。同样的,如果想要最终消除 warning
可以记录为 error
,让代码作者重视起来。
Fatal
记录消息后,直接调用 os.Exit(1)
,这意味着:在其他 goroutine
defer
语句不会被执行;各种 buffers
不会被 flush
,包括日志的;临时文件或者目录不会被移除;不要使用 fatal
记录日志,而是向调用者返回错误。如果错误一直持续到 main.main
。main.main
那就是在退出之前做处理任何清理操作的正确位置。
Error
也有很多人,在错误发生的地方要立马记录日志,尤其要使用 error
级别记录。

处理 error
把 error
抛给调用者,在顶部打印日志;如果您选择通过日志记录来处理错误,那么根据定义,它不再是一个错误 — 您已经处理了它。记录错误的行为会处理错误,因此不再适合将其记录为错误。

DEBUG
相信只有两件事你应该记录:
开发人员在开发或调试软件时关心的事情。 用户在使用软件时关心的事情。
显然,它们分别是调试和信息级别。log.Info
只需将该行写入日志输出。不应该有关闭它的选项,因为用户只应该被告知对他们有用的事情。如果发生了一个无法处理的错误,它就会抛出到 main.main
。main.main
程序终止的地方。在最后的日志消息前面插入 fatal
前缀,或者直接写入 os.Stderr
。log.Debug
,是完全不同的事情。它由开发人员或支持工程师控制。在开发过程中,调试语句应该是丰富的,而不必求助于 trace
或 debug2
(您知道自己是谁)级别。日志包应该支持细粒度控制,以启用或禁用调试,并且只在包或更精细的范围内启用或禁用调试语句。
B站的go框架是如何设计和思考的:https://github.com/go-kratos/kratos/tree/v2.0.x/log
日志选型
一个完整的集中式日志系统,需要包含以下几个主要特点:
收集-能够采集多种来源的日志数据; 传输-能够稳定的把日志数据传输到中央系统; 存储-如何存储日志数据; 分析-可以支持 UI
分析;警告-能够提供错误报告,监控机制;
开源界鼎鼎大名 ELK stack
,分别表示:Elasticsearch
, Logstash
, Kibana
, 它们都是开源软件。新增了一个 FileBeat
,它是一个轻量级的日志收集处理工具(Agent
),Filebeat
占用资源少,适合于在各个服务器上搜集日志后传输给 Logstash
,官方也推荐此工具。
ELK
此架构由 Logstash
分布于各个节点上搜集相关日志、数据,并经过分析、过滤后发送给远端服务器上的 Elasticsearch
进行存储。Elasticsearch
将数据以分片的形式压缩存储并提供多种 API
供用户查询,操作。用户亦可以更直观的通过配置 Kibana Web
方便的对日志查询,并根据数据生成报表。因为 logstash
属于 server
角色,必然出现流量集中式的热点问题,因此我们不建议使用这种部署方式,同时因为 还需要做大量 match
操作(格式化日志),消耗的 CPU
也很多,不利于 scale out
。


此种架构引入了消息队列机制,位于各个节点上的 Logstash Agent
先将数据/日志传递给 Kafka
,并将队列中消息或数据间接传递给 Logstash
,Logstash
过滤、分析后将数据传递给Elasticsearch
存储。最后由 Kibana
将日志和数据呈现给用户。因为引入了 Kafka
,所以即使远端 Logstash server
因故障停止运行,数据将会先被存储下来,从而避免数据丢失。更进一步的: 将收集端 logstash
替换为 beats
, 更灵活,消耗资源更少,扩展性更强。

日志系统的设计目标
接入方式收敛; 日志格式规范; 日志解析对日志系统透明; 系统高吞吐、低延迟; 系统高可用、容量可扩展、高可运维性;
日志系统的格式规范
JSON
作为日志的输出格式:time
: 日志产生时间,ISO8601
格式;level
: 日志等级,ERROR
、WARN
、INFO
、DEBUG
;app_id
: 应用id
,用于标示日志来源;instance_id
: 实例 id
,用于区分同一应用不同实例,即 hostname
;

日志系统的设计与实现
日志从产生到可检索,经历几个阶段:
生产 & 采集 传输 & 切分 存储 & 检索
采集

logstash
:
监听 tcp/udp
适用于通过网络上报日志的方式
filebeat
:
直接采集本地生成的日志文件 适用于日志无法定制化输出的应用
logagent
:
物理机部署,监听 unixsocket
日志系统提供各种语言 SDK
直接读取本地日志文件

传输
基于 flume + Kafka
统一传输平台
基于 LogID
做日志分流:
一般级别 低级别 高级别( ERROR
)
现在替换为 Flink + Kafka
的实现方式。

切分
从kafka
消费日志,解析日志,写入elasticsearchbili-index
: 自研,golang
开发,逻辑简单,性能 高, 可定制化方便。• 日志规范产生的日志(log agent
收集)logstash
: es
官方组件,基于 jruby
开发,功能强大, 资源消耗高,性能低。• 处理未按照日志规范产生的日志(filebeat
、logstash
收集),需配置各种日志解析规则。
存储和检索
elasticsearch
多集群架构:日志分级、高可用
单数据集群内:master node + data node(hot/stale) + client node
每日固定时间进行热->冷迁移Index
提前一天创建,基于 template
进行mapping
管理
检索基于 kibana
存储-文件
使用自定义协议,对 SDK
质量、版本升级都有比较高的要求,因此我们长期会使用“本地文件”的方案实现:采集本地日志文件:位置不限,容器内 or
物理机配置自描述:不做中心化配置,配置由 app/paas
自身提供,agent
读取配置并生效日志不重不丢:多级队列,能够稳定地处理日志收集过程中各种异常 可监控:实时监控运行状态 完善的自我保护机制:限制自身对于宿主机资源的消耗,限制发送速度
最后
期望与你一起遇见更好的自己





