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.mainmain.main 那就是在退出之前做处理任何清理操作的正确位置。

# Error

也有很多人,在错误发生的地方要立马记录日志,尤其要使用 error 级别记录。

# 处理 error

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

# DEBUG

相信只有两件事你应该记录:

  • 开发人员在开发或调试软件时关心的事情。
  • 用户在使用软件时关心的事情。

显然,它们分别是调试和信息级别。
log.Info 只需将该行写入日志输出。不应该有关闭它的选项,因为用户只应该被告知对他们有用的事情。如果发生了一个无法处理的错误,它就会抛出到 main.mainmain.main 程序终止的地方。在最后的日志消息前面插入 fatal 前缀,或者直接写入 os.Stderr
log.Debug ,是完全不同的事情。它由开发人员或支持工程师控制。在开发过程中,调试语句应该是丰富的,而不必求助于 tracedebug2 (您知道自己是谁)级别。日志包应该支持细粒度控制,以启用或禁用调试,并且只在包或更精细的范围内启用或禁用调试语句。

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 ,并将队列中消息或数据间接传递给 LogstashLogstash 过滤、分析后将数据传递给 Elasticsearch 存储。最后由 Kibana 将日志和数据呈现给用户。因为引入了 Kafka ,所以即使远端 Logstash server 因故障停止运行,数据将会先被存储下来,从而避免数据丢失。
更进一步的: 将收集端 logstash 替换为 beats , 更灵活,消耗资源更少,扩展性更强。

# 日志系统的设计目标

  • 接入方式收敛;
  • 日志格式规范;
  • 日志解析对日志系统透明;
  • 系统高吞吐、低延迟;
  • 系统高可用、容量可扩展、高可运维性;

# 日志系统的格式规范

JSON 作为日志的输出格式:
time : 日志产生时间, ISO8601 格式;
level : 日志等级, ERRORWARNINFODEBUG
app_id : 应用 id ,用于标示日志来源;
instance_id : 实例 id ,用于区分同一应用不同实例,即 hostname

# 日志系统的设计与实现

日志从产生到可检索,经历几个阶段:

  • 生产 & 采集
  • 传输 & 切分
  • 存储 & 检索

# 采集

# logstash

监听 tcp/udp
适用于通过网络上报日志的方式

# filebeat

直接采集本地生成的日志文件
适用于日志无法定制化输出的应用

# logagent

物理机部署,监听 unixsocket
日志系统提供各种语言 SDK
直接读取本地日志文件

logagent的设计

# 传输

基于 flume + Kafka 统一传输平台
基于 LogID 做日志分流:

  • 一般级别
  • 低级别
  • 高级别( ERROR

现在替换为 Flink + Kafka 的实现方式。

# 切分

kafka 消费日志,解析日志,写入 elasticsearch
bili-index : 自研, golang 开发,逻辑简单,性能 高,可定制化方便。
・日志规范产生的日志 ( log agent 收集)
logstash : es 官方组件,基于 jruby 开发,功能强大, 资源消耗高,性能低。
・处理未按照日志规范产生的日志 ( filebeatlogstash 收集),需配置各种日志解析规则。

# 存储和检索

elasticsearch 多集群架构:
日志分级、高可用

单数据集群内:
master node + data node(hot/stale) + client node
每日固定时间进行热 -> 冷迁移
Index 提前一天创建,基于 template 进行 mapping 管理
检索基于 kibana

# 存储 - 文件

  • 使用自定义协议,对 SDK 质量、版本升级都有比较高的要求,因此我们长期会使用 “本地文件” 的方案实现:
  • 采集本地日志文件:位置不限,容器内 or 物理机
  • 配置自描述:不做中心化配置,配置由 app/paas 自身提供, agent 读取配置并生效
  • 日志不重不丢:多级队列,能够稳定地处理日志收集过程中各种异常
  • 可监控:实时监控运行状态
  • 完善的自我保护机制:限制自身对于宿主机资源的消耗,限制发送速度

# 最后

期望与你一起遇见更好的自己

期望与你一起遇见更好的自己

更新于 阅读次数

请我喝[咖啡]~( ̄▽ ̄)~*

方小白 微信支付

微信支付

方小白 支付宝

支付宝

方小白 numberpay

numberpay