秋来冬风的博客

metrics包如何记录非默认行为发生次数

目录

go1.21前瞻

metrics包如何记录非默认行为发生次数

go1.21正在开发中,发行说明草案 提到预计2023年8月发布。

在go1.21的开发分支中,metrics 包中,新增了一系列格式如同 /godebug/non-default-behavior/(godebug-name):events的指标,(godebug-name)是GODEBUG环境变量的一系列键值对,某些键的名称,比如go1.19引入的execerrdot(以下简称godebug指标)。通过这些新增的指标,可以获取因为设置了这些环境变量导致非默认行为发生次数的数量,本文通过研究源代码来分析这是如何实现的。

首先,本文使用的是go标准库源代码(通过gotip安装),具体版本号(go version devel go1.21-8d68b388d4 Wed Apr 5 21:45:24 2023 +0000 windows/amd64)。


在go标准库的internal/godebug包有如下API:

type Setting struct
    func New(name string) *Setting
    func (s *Setting) IncNonDefault()
    func (s *Setting) Name() string
    func (s *Setting) String() string
    func (s *Setting) Value() string

在Setting结构体中,有一个非默认行为计数器,类型是atomic.Uint64,这是一个在go1.19引入的原子类型,API如下

type Uint64 struct
    func (x *Uint64) Add(delta uint64) (new uint64)
    func (x *Uint64) CompareAndSwap(old, new uint64) (swapped bool)
    func (x *Uint64) Load() uint64
    func (x *Uint64) Store(val uint64)
    func (x *Uint64) Swap(new uint64) (old uint64)

这个结构体的IncNonDefault方法每次调用时非默认行为计数器都会原子加1,在第一次调用时还会将非默认行为计数器的Load方法通过runtime包的godebug_registerMetric函数设置为获取godebug指标对应的值的函数。

这样通过每次非默认行为发生时都调用IncNonDefault方法,就可以在Setting结构体中记录非默认行为发生次数。

godebug_registerMetric函数签名如下:

func godebug_registerMetric(name string, read func() uint64)

这个函数将name参数的值表示的指标,获取指标对应的值的函数设置为read参数传递的参数。

metrics包获取godebug指标对应的值的能力来源于runtime包。


这样,非默认行为发生次数被记录和获取的顺序是:

  • go标准库的每个godebug选项都通过internal/godebug包的New()函数创建,返回值包含非默认行为计数器。
  • 每次非默认行为发生时都会调用Setting结构体的IncNonDefault方法。
  • IncNonDefault方法将获取godebug指标对应的值的函数设置为非默认行为计数器的Load方法。
  • IncNonDefault方法将非默认行为计数器原子加1。
  • 每次godebug指标对应的值被获取,都会调用非默认行为计数器的Load方法,这样就实现了metrics包有记录非默认行为发生次数的现象(实际记录在Setting结构体,只是metrics包通过runtime包,runtime包通过调用Setting结构体的非默认行为计数器的Load方法展现出了这种现象)。
Tags: