2.27日分享介绍
1.Go 日志基础
2.Go 日志统一格式
JSON 格式的结构优势
- 标准化 Golang 日志
3.Go 日志上下文
4.Go 日志对性能的影响
不要在 Goroutine 中使用日志
使用异步库
使用严重等级管理日志
5.集中化 Go 日志
6.享受 Go 日志之旅
直播时间:2.27日21:00-22:00
文末添加小助手获取直播链接
你是如何使用 Golang 日志监控你的应用程序的呢?Golang 没有异常,只有错误。因此你的第一印象可能就是开发 Golang 日志策略并不是一件简单的事情。不支持异常事实上并不是什么问题,异常在很多编程语言中已经失去了其异常性:它们过于被滥用以至于它们的作用都被忽视了。
在进一步深入之前,我们首先会介绍 Golang 日志的基础,并讨论 Golang 日志标准、元数据意义、以及最小化 Golang 日志对性能的影响。通过日志,你可以追踪用户在你应用中的活动,快速识别你项目中失效的组件,并监控总体性能以及用户体验。
一Go 日志基础

使用 Golang “log” 库
Golang 给你提供了一个称为 “log” 的原生日志库。它的日志器完美适用于追踪简单的活动,例如通过使用可用的选项在错误信息之前添加一个时间戳。
下面是一个 Golang 中如何记录错误日志的简单例子:
package main "errors" "log"if b == return return10 if err != 如果你尝试除以0,你就会得到类似下面的结果:
2020/02/24 16:13:30 division by zero为了快速测试一个 Golang 函数,你可以使用 go playground。为了确保日志总是能轻易访问,可以把 log 写在一个文件:
package main import (可以找到 Golang 日志的完整指南,以及“log”库内可用函数的完整列表。现在你就可以记录它们的错误以及根本原因啦。另外,日志也可以帮你将活动流拼接在一起,查找需要修复的错误上下文,或者调查在你的系统中单个 请求如何影响其它应用层和 API。为了获得更好的日志效果,你首先需要在你的项目中使用尽可能多的上下文丰富你的 Golang 日志,并标准化你使用的格式。这就是 Golang 原生库能达到的极限。使用最广泛的库是 glog 和 logrus。必须承认还有很多好的库可以使用。如果你已经在使用支持 JSON 格式的库,你就不需要再换其它库了,后面我们会解释。
二 Go 日志统一格式

JSON 格式的结构优势 在一个项目或者多个微服务中结构化你的 Golang 日志可能是最困难的事情,但一旦完成就很轻松了。结构化你的日志能使机器可读。灵活性和层级是JSON 格式的核心,因此信息能够轻易被人类和机器解析以及处理。 下面是一个使用 Logrus/Logmatic.io 如何用 JSON 格式记录日志的例子:
package main import ( "/logmatic/logmatic-go" log.SetFormatter(&logmatic.JSONFormatter{}) 会输出结果:
{
"date":"2016-05-09T10:56:00+02:00",
"float":1.1,
"int":1, "level":"info",
"message":"My first ssl event from golang", "String":"foo"
} 标准化 Golang 日志 同一个错误出现在你代码的不同部分,却以不同形式被记录下来是一件可耻的事情。下面是一个由于一 个变量错误导致无法确定 web 页面加载状态的例子。一个开发者日志格式是:
'unknown error: cannot determine loading status from unknown error: missing or invalid arg value client' 另一个人的格式却是:
unknown error: cannot determine loading status - invalid client 强制日志标准化的一个好的解决办法是在你的代码和日志库之间创建一个接口。这个标准化接口会包括 所有你想添加到你日志中的可能行为的预定义日志消息。这么做可以防止出现不符合你想要的标准格式 的自定义日志信息。这么做也便于日志调查。 由于日志格式都被统一处理,使它们保持更新也变得更加简单。如果出现了一种新的错误类型,它只需要被添加到一个接口,这样每个组员都会使用完全相同的信息。
最常使用的简单例子就是在Golang 日志信息前面添加日志器名称和id。你的代码然后就会发送“事件”
到你的标准化接口,它会继续讲它们转化为Golang 日志消息。
// 主要部分,我们会在这里定义所有消息。
}"arg." + name,
}因此如果我们使用前面例子中无效的参数值,我们就会得到相似的日志信息:
time="2017-02-24T23:12:31+01:00" level=error msg="LoadPageLogger00003 - Missing
arg: client - cannot determine loading status" arg.client=
=LoadPageLoggerJSON 格式如下:
{"arg.client":null,"level":"error","":"LoadPageLogger","msg":"LoadPag
eLogger00003 - Missing arg: client - cannot determine loading status",
"time":"2017-02-24T23:14:28+01:00"}三Go日志上下文
现在 Golang 日志已经按照特定结构和标准格式记录,时间会决定需要添加哪些上下文以及相关信息。为了能从你的日志中抽取信息,例如追踪一个用户活动或者工作流,上下文和元数据的顺序非常重要。
例如在 logrus 库中可以按照下面这样使用 JSON 格式添加 hostname、appname 和 session 参数:
// 对于元数据,通常做法是通过复用来重用日志语句中的字段。
contextualizedLog :=
log.WithFields(log.Fields{ "hostname":
"staging-1",
"appname": "foo-app",
"session": "1ce3f6v"
}) 元数据可以视为 javascript 片段。 为了更好地说明它们有多么重要,让我们看看几个 Golang 微服务中元数据的使用。
你会清楚地看到是怎么在你的应用程序中跟踪用户的。
这是因为你不仅需要知道一个错 误发生了,还要知道是哪个实例以及什么模式导致了错误。
假设我们有两个按顺序调用的微服务。
上下 文信息保存在头部(header)中传输:
func helloMicroService1(w http.ResponseWriter, r *http.Request)
if
"x-session", session)"x-track", track)
….
......
















