Golang 日志库

任何一个系统开发,都离不开完备的日志系统。go 日志不同其他语言,比如 java 由于 commons-logging 日志标准,和不同实现 如log4j,slf4j,logback,但都是统一调用标准接口;python 中标准logging 模块,功能强大,基本上满足各种需求。但是在golang 语言开发中,目前阅读了几个开源代码,都是自己实现了一套日志记录标准,并没有采用go 官方 log 模块。golang’s log 模块主要提供了3类接口。分别是 “Print、Panic、Fatal”,对每一类接口其提供了3中调用方式,分别是 “Xxxx 、 Xxxxln 、Xxxxf”,基本和fmt中的相关函数类似;但功能有限,很难比如按天,按照容量自动输出拆封生成新日志。如果自己开发一套日志,基本上要满足日志等级输出如DEBUG,INFO,WARN,ERROR/FATAL 、支持输出 console 或者滚动式文件、参数格式化输出、自定义格式化模板,当然如果支持更高级别如按照pakcage输出到不同文件,按照日志级别输出到不同地方那就更好了。

下面简要介绍7款golang日志库:

  • 标准库日志
  • 标准库的slog
  • Logrus
  • Zap
  • Zerolog
  • golang glog
  • seelog

1. 标准库日志

Go 的标准库包含一个名为 的基本日志记录包log。它提供了一种将消息记录到控制台的简单方法:

1
2
3
4
5
6
7
8
9
10
11

package main

import (
"log"
)

func main() {
log.Println("This is a log message")
}

但是,标准log包非常简单,可能不适合更复杂的日志记录要求,例如日志轮换、日志级别或日志格式。

2. 标准库的slog

最近,Go 标准库引入了一个名为 的新日志记录包slog,它将结构化日志记录引入标准库。结构化日志使用键值对,因此可以快速可靠地解析、过滤、搜索和分析它们。

该slog包提供了比 log 包更高级的日志记录功能,建议在生产环境中使用。

slog以下是如何使用该包登录 Go的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

package main

import (
"os"
"log/slog"
)

func main() {
textHandler := slog.NewTextHandler(os.Stdout)
logger := slog.New(textHandler)

logger.Info("Usage Statistics",
slog.Int("current-memory", 50),
slog.Int("min-memory", 20),
slog.Int("max-memory", 80),
slog.Int("cpu", 10),
slog.String("app-version", "v0.0.1-beta"),
)
}

要使用 Go 中的包记录到文件slog,您可以使用该slog.NewJSONHandler函数创建一个新的处理程序,以 JSON 格式将日志写入文件。这是一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

package main

import (
"os"
"log/slog"
)

func main() {
file, err := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
panic(err)
}
defer file.Close()

jsonHandler := slog.NewJSONHandler(file)
logger := slog.New(jsonHandler)

logger.Info("Application started",
slog.String("app-version", "v0.0.1-beta"),
)
}

3. Logrus

为了处理更高级的日志记录需求,许多开发人员转向第三方日志记录库。一种流行的选择是“logrus”,它提供了功能更丰富的日志记录体验。您可以使用以下方式安装它:

1
2
3

go get github.com/sirupsen/logrus

以下是如何使用 Logrus 库的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

package main

import (
"github.com/sirupsen/logrus"
)

func main() {
// Create a new logger instance
log := logrus.New()

// Set the log level (optional)
log.SetLevel(logrus.InfoLevel)

// Log messages
log.WithFields(logrus.Fields{
"animal": "walrus",
}).Info("A walrus appears")
}

Logrus 提供结构化日志记录、日志级别、自定义格式化程序等功能。

Logrus是一个高度可扩展的日志库,可以与各种监控工具集成。例如,OpenTelemetry Logrus是一个提供与 OpenTelemetry 集成的插件。

4. Zap

Go 生态系统中另一个流行的日志库是 Zap。它以其高性能和结构化日志记录功能而闻名。您可以使用以下方式安装它:

1
go get go.uber.org/zap

以下是如何使用 Zap 的基本示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

package main

import (
"go.uber.org/zap"
)

func main() {
// Create a logger
logger, _ := zap.NewProduction()

// Log messages
logger.Info("This is an info message", zap.String("key", "value"))
}

Zap 允许以最少的分配进行高效的日志记录,并具有丰富的功能。

您可以使用 OpenTelemetry Zap 将 Zap 与 OpenTelemetry集成插件

5. Zerolog

Zerolog 是一个快速且简单的结构化记录器。它专注于减少分配并为结构化日志记录提供干净的 API。它适合基本和高级日志记录需求。

1
2
3

go get github.com/rs/zerolog

以下是使用 Zerolog 记录消息的基本示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import (
"os"
"github.com/rs/zerolog"
)

func main() {
// Create a new logger instance
logger := zerolog.New(os.Stdout).With().Timestamp().Logger()

// Log messages
logger.Info().Str("key", "value").Msg("This is an info message")
logger.Error().Err(fmt.Errorf("An error occurred")).Msg("This is an error message")
}

6. golang glog

golang的glog是一个轻量级的日志库,它是著名的Google开源C++日志库glog的的Golang版本。glog具有上手简单、稳定高效的特点,但自定义控制的内容相对较少。

1
go get github.com/golang/glog

以下是使用 golang glog 记录消息的基本示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

// 导入所需的包
import (
"flag" // 导入flag包以解析命令行参数
"log" // 导入标准库中的log包(这里并未使用,仅作示例)
"os" // 导入os包(这里并未使用,仅作示例)

"github.com/golang/glog" // 导入glog包,用于记录日志
)

func main() {
// 初始化glog,必须先调用flag.Parse()解析命令行参数,glog依赖于命令行参数来设置日志级别等
flag.Parse()

// 设置glog的输出级别为INFO,这样INFO及以上级别的日志才会被输出
// V参数代表详细级别,通过命令行-v可以指定输出详细日志的级别
defer glog.SetV(2) // 使用defer确保在main函数结束前设置V级别

// 输出INFO级别的日志,当V级别设置为2或以上时,该消息会被记录
glog.Info("This is an info log message.")

// 输出WARNING级别的日志,这个级别的日志通常表示一些潜在的问题,但程序可以继续运行
glog.Warning("This is a warning log message.")

// 输出ERROR级别的日志,这通常表示程序遇到了错误,但不一定需要终止
glog.Error("This is an error log message.")

// 输出FATAL级别的日志,会导致程序立即终止,通常用于表示无法恢复的错误
glog.Fatal("This is a fatal log message.")

// 由于glog.Fatal会触发程序终止,因此这行代码不会执行
glog.Info("This message will not be printed because of the fatal above.")

// 通常不需要显式调用glog.Flush(),因为glog库会在程序终止时自动刷新缓冲区
// 如果需要确保日志被写入文件,可以在程序结束前显式调用glog.Flush()
}

glog库的详细日志级别是通过glog.SetV(level)来设置的,并且可以通过命令行参数-v来指定输出详细日志的级别。在上面的示例中,glog.SetV(2)表示当使用-v=2或更高值时,详细日志会被输出。而glog的的日志级别(INFO, WARNING, ERROR, FATAL)是固定的,不需要设置。

另外,在真实的应用场景中,glog库通常用于替代标准库的log包,用于更结构化、更灵活的日志记录。如果需要自定义日志格式或输出位置,可能需要结合glog库的其它功能或考虑使用其他日志库。

7. seelog

seelog 是一个 Go 语言(golang)的日志库,它提供了灵活且强大的日志记录功能。与标准的 log 库相比,seelog 提供了更多的定制性和更丰富的功能。

以下是一个简单的 seelog 使用示例:

首先,你需要安装 seelog:

1
2
3

go get github.com/cihub/seelog

然后,你可以通过 XML 配置文件来配置 seelog:

1
2
3
4
5
6
7
8
9
<seelog type="asynctimer" asyncinterval="500" minlevel="info">  
<outputs formatid="main">
<console />
<file path="logs/app.log" rollonfilesize="true" rollsize="10485760" />
</outputs>
<formats>
<format id="main" format="%Date %Time [%Level] %Msg%n"/>
</formats>
</seelog>

在 Go 代码中,你可以这样加载并使用配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main  

import (
"github.com/cihub/seelog"
)

func main() {
defer seelog.Flush()

// 加载配置文件
if err := seelog.LoadConfiguration("path/to/seelog.xml"); err != nil {
panic(err)
}

// 记录日志
seelog.Infof("This is an info message.")
seelog.Warnf("This is a warning message.")
seelog.Errorf("This is an error message.")
}

在上面的示例中,seelog 会根据配置文件将日志输出到控制台和文件。你可以根据实际需要调整配置文件的内容,以满足不同的日志记录需求。

总的来说,seelog 是一个功能丰富且灵活的日志库,它可以帮助你更好地管理和分析应用程序的日志。

8. 最佳实践

有效的日志记录是提供足够的信息来解决问题和避免信息过载之间的平衡。根据应用程序和组织的具体要求和限制调整您的日志记录实践。

结构化日志记录。采用结构化日志记录,它允许您将键值对或结构化数据附加到日志条目。这使得以结构化方式过滤和分析日志变得更加容易。

日志级别。利用日志级别(例如,INFO、DEBUG、WARN、ERROR)对日志消息进行分类。这使您可以控制日志的详细程度,并在调试或故障排除期间关注相关信息。

上下文信息。在日志消息中包含相关的上下文信息。例如,包括请求 ID、用户 ID 和时间戳。这有助于跨组件跟踪问题。

错误换行。记录错误时,使用错误包装来保留原始错误上下文。您可以使用“github.com/pkg/errors”之类的包或内置的“fmt.Errorf”来实现此目的。

监控和警报。为应用程序日志设置监控和警报。使用 Uptrace 或 Grafana 等工具创建仪表板并根据日志模式设置警报。

9. 总结

根据应用程序的要求和复杂性选择日志记录方法。大多数项目都建议使用 Logrus 和 Zap 等第三方库,因为它们提供了强大的功能并且社区维护得很好。

最近,Go 标准库引入了一个名为slog的新日志记录包,它将结构化日志记录引入标准库,并建议在生产环境中使用。

请记住,日志记录库的选择可能取决于项目的大小和复杂性。对于较小的项目,一个简单且易于使用的记录器可能就足够了,而较大且更复杂的项目可能会受益于功能更丰富、性能更佳的日志记录库。