首页 > 其他分享 >Golang日志新选择:slog

Golang日志新选择:slog

时间:2023-09-11 20:37:13浏览次数:42  
标签:09 greeting Golang slog 2023 msg 日志

go1.21中,slog这一被Go语言团队精心设计的结构化日志包正式落地,本文将带领读者上手slog,体会其与传统log的差异。

WHY

在日志处理上,我们从前使用的log包缺乏结构化的输出,导致信息呈现出来的样子并非最适合人类阅读,而slog是一种结构化的日志,它可以用键值对的形式将我们需要的信息呈现出来,使得处理与分析日志变得更为容易。

HOW

1. 快速入门

package main

import (
	"log/slog"
)

func main() {
	slog.Info("my first slog msg", "greeting", "hello, slog")
	slog.Error("my secod slog message", "greeting", "hello slog")
	slog.Warn("my third message", "greeting", "hello slog")
}

以上是三条最简单的slog语句,其结果是这样的:

2023/09/10 21:51:03 INFO my first slog msg greeting="hello, slog"
2023/09/10 21:51:03 ERROR my secod slog message greeting="hello slog"
2023/09/10 21:51:03 WARN my third message greeting="hello slog"

这三行代码中的第一个参数代表了log的message,我们可以看到,此时打印出来的日志信息是文本信息,那如何使得日志以非纯文本(比如json)展现呢?

2. TextHandler和JSONHandler

当我们想要日志以key-value格式呈现时,我们可以用下面这种方式:

h := slog.NewTextHandler(os.Stderr, nil)
	l := slog.New(h)
	l.Info("greeting", "name", "xxx")

最终结果:

time=2023-09-10T21:58:34.144+08:00 level=INFO msg=greeting name=xxx

当我们想要日志以json格式呈现时,我们可以使用下面这种方式:

h1 := slog.NewJSONHandler(os.Stderr, nil)
	l1 := slog.New(h1)
	l1.Info("greeting", "name", "xxx")

最终结果:

{"time":"2023-09-10T22:00:04.687003+08:00","level":"INFO","msg":"greeting","name":"xxx"}

slog.NewJSONHandler函数和slog.NewTextHandler函数都会返回一个JsonHandler结构体或是TextHandler的引用,这个结构体会被slog.new函数接受,该函数返回一个Logger结构体的引用,这个logger结构体包含Handler接口,拥有一系列日志相关函数,是我们最终打印日志的地方

func NewJSONHandler(w io.Writer, opts *HandlerOptions) *JSONHandler {}
func NewTextHandler(w io.Writer, opts *HandlerOptions) *TextHandler {}

func New(h Handler) *Logger {}

type Logger struct {
	handler Handler // for structured logging
}

type Handler interface {}

如此,我们实现了基本的日志结构化输出。

3.日志配置

我们通过对slog.HandlerOptions配置,可以实现例如 是否输出日志来源 等设置;

s := &slog.HandlerOptions{
		AddSource: true,
	}
	slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, s)))
	slog.Info("Test", "greeting", "hello, world")

此处笔者将该s设置为default情况,这样直接使用slog.info就可以用到之前的配置;

最终结果:

time=2023-09-10T22:11:04.432+08:00 level=INFO source="/Users/wurenyu/Library/Mobile Documents/com~apple~CloudDocs/Go_learn/basic/slog/t1.go:13" msg=Test greeting="hello, world"

可以看到,由于AddSource被设置为true,我们的输出日志中多了source这一信息;

又由于NewTextHandler,所以日志是以键值对的形式输出的。

再来看这一段代码:

opts := slog.HandlerOptions{
AddSource: true,
Level:     slog.LevelError,
}

slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stderr, &opts)))
slog.Info("open file for reading", "name", "foo.txt", "path", "/home/tonybai/demo/foo.txt")
slog.Error("open file error", "err", os.ErrNotExist, "status", 2)

在slog配置中将Level设置为了LevelError,如此,将只能使用slog.error这一级别;

最终输出结果:

{"time":"2023-09-10T22:13:44.493714+08:00","level":"ERROR","source":{"function":"main.main","file":"/Users/wurenyu/Library/Mobile Documents/com~apple~CloudDocs/Go_learn/basic/slog/t1.go","line":16},"msg":"open file error","err":"file does not exist","status":2}

3. Group形式输出日志

baseLogger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
	groupedLogger := baseLogger.WithGroup("TTT")

	// Log with the grouped logger
	groupedLogger.Info("This log entry includes module information.", "test1", "answer1")
	groupedLogger.Warn("This log entry also includes module information.", "test2", "answer2")

上述代码首先生成一个叫做baseLogger的logger,然后在这个logger上调用方法WithGroup,并传入参数“TTT”,后面两行分别输出info和warn级别的日志;

最终结果如下:

{"time":"2023-09-10T22:23:28.527786+08:00","level":"INFO","msg":"This log entry includes module information.","TTT":{"test1":"answer1"}}
{"time":"2023-09-10T22:23:28.528019+08:00","level":"WARN","msg":"This log entry also includes module information.","TTT":{"test2":"answer2"}}

可以看到,在groupLogger后面加上的键值对都被加在了TTT后面;

不过值得关注的是,slog是支持给logger自定义字段的,给一个logger加上一个属性之后,每次用这个logger输出日志,都会输出这个属性对应的键值对,而这个信息不会被包含在WithGroup函数传入的参数后面。

风格

个人认为一般不需要在msg中直接传入代码中的数据,msg中应该尽量直接使用constant常量,这样更可控。

WHAT

以下是slog大致的架构:

Untitled

全文终。

标签:09,greeting,Golang,slog,2023,msg,日志
From: https://www.cnblogs.com/wryyyyyyy/p/17694417.html

相关文章

  • fyne container.NewHSplit水平分割容器 Go golang
    环境:gofyne 要求:go项目中将窗口分成左右两个容器,实现窗口分割效果:实现代码:1packagemain23import(4"fyne.io/fyne/v2"5"fyne.io/fyne/v2/app"6"fyne.io/fyne/v2/container"7"fyne.io/fyne/v2/widget"8)91......
  • 日志是你的朋友:为什么每个开发者都应该写日志
    大家好,我是小米,一个热衷于技术分享的程序员。今天我想和大家聊一聊一个在编写代码时常常被忽视,却极为重要的话题——为什么要写有意义的日志。在日常的编程工作中,我们经常听到“日志”这个词,但是有些人可能并不理解为什么要在代码中写入日志,或者觉得这只是一种不必要的繁琐。但是,当......
  • Golang 日期处理丶函数执行耗时丶内置函数
    一.日期处理1functestDate(){2//获取当前时间3now:=time.Now()4fmt.Printf("当前时间:%v,时间的类型:%T\n",now,now)5fmt.Printf("当前时间的年=%v月=%v日=%v时=%v分=%v秒=%v\n",now.Year(),int(now.Month()),now.Day(),now.Hour(......
  • appium日志查看
    高级设置---》勾选Log--》然后重启  ......
  • SpringBoot + 自定义注解,实现用户操作日志(支持SpEL表达式)
    背景一个成熟的系统,都会针对一些关键的操作,去创建用户操作日志。比如:XX人创建了一条订单,订单号:XXXXXXXXX因为操作人或者订单号是动态的,所以有些开发人员,不知道获取,就将这种操作日志和业务代码融在一起。我们当然要杜绝这种现象,一定会有更好的解决方案。当前项目除了......
  • Golang(又称Go语言)是一种开源的静态强类型编程语
    Golang(又称Go语言)是一种开源的静态强类型编程语言,巧瞒七星解磐键由Google在2007年开始开发,并于2009年发布。它的设计目标是提供一种简洁、高效的语言,同时具备高并发、高性能的特性。Golang的语法风格简洁明了,易于上手,适用于各种规模的项目。下面将介绍Golang在实际应用中的具体案......
  • money详细日志分析--转
    一、Monkey日志详解Monkey日志由以下几部分组成:(1)测试命令信息:随机种子seed、运行次数、可运行应用列表、各事件百分比。​​​​​​​ (2)App切换和Activity跳转:可以看到切换到了哪个App,从哪个Activity跳转到了哪个Activity,如果发生了异常,就可以看出是在哪个A......
  • mybatisplus中按照条件查询的三种方式,常用的是lambda查询,当进行测试查询的时候,可以将
    2023-09-10目录结构 logback.xml<?xmlversion="1.0"encoding="UTF-8"?><configuration></configuration>application.ymlspring:datasource:driver-class-name:com.mysql.cj.jdbc.Driverurl:jdbc:mysql://loca......
  • Golang 初识: 函数调用与定义丶字符串处理丶Json的处理
    一.基本函数调用与定义1packagemain23import(4"encoding/json"5"errors"6"fmt"7"math/rand"8"mylib/pkg/student"9"mylib/pkg/utils"10"sort"11......
  • postgresql数据库安装日志解析插件wal2json
    postgresql数据库安装日志解析插件wal2json一、编译安装wal2json插件cdwal2jsonexportPATH=/data/home/fei.yang4/moudle/postgresql/bin:$PATHmakemakeinstall二、直接导入wal2json插件查看pg进程确定pgsql库和配置文件存放目录ps-ef|greppostgresqlubuntu24975248......