跳到主要内容
版本:2.7.x

基本介绍

监控指标的代码开发直接使用框架主库的 gmetric 组件即可,但由于 gmetric 组件实际上只是定义了监控指标的相关接口,并且默认提供的 NoopPerformer,默认监控指标特性是关闭的。因此需要引入具体的接口实现组件才能真正开启监控指标特性。框架社区提供了社区组件 github.com/gogf/gf/contrib/metric/otelmetric/v2,使用了 OpenTelemetry 实现框架的监控指标接口,引入该社区组件并且执行监控指标管理对象创建即可开启监控指标特性。 otelmetric 组件源码地址: https://github.com/gogf/gf/tree/master/contrib/metric/otelmetric

我们通过一个简单的监控指标实现示例来介绍一下监控指标组件的基本使用。

package main

import (
"go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/metric/metricdata"

"github.com/gogf/gf/contrib/metric/otelmetric/v2"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/gmetric"
)

var (
meter = gmetric.GetGlobalProvider().Meter(gmetric.MeterOption{
Instrument: "github.com/gogf/gf/example/metric/basic",
InstrumentVersion: "v1.0",
})
counter = meter.MustCounter(
"goframe.metric.demo.counter",
gmetric.MetricOption{
Help: "This is a simple demo for Counter usage",
Unit: "bytes",
},
)
)

func main() {
var (
ctx = gctx.New()
reader = metric.NewManualReader()
)

provider := otelmetric.MustProvider(otelmetric.WithReader(reader))
provider.SetAsGlobal()
defer provider.Shutdown(ctx)

counter.Inc(ctx)
counter.Add(ctx, 10)

var (
rm = metricdata.ResourceMetrics{}
err = reader.Collect(ctx, &rm)
)
if err != nil {
g.Log().Fatal(ctx, err)
}
g.DumpJson(rm)
}

指标管理组件的创建

通过 gmetric.GetGlobalProvider() 方法可以获取全局的监控 指标管理对象该对象是一个单例设计,全局只能有一个。并通过该对象的 Meter 方法可以创建/获取对应的 组件对象。组件对象用于管理该组件下所有的监控指标。在创建组件对象时通常需要定义组件( Instrument)的名称以及版本(虽然也可以为空,但为了方便后续维护建议都设置上)。

meter = gmetric.GetGlobalProvider().Meter(gmetric.MeterOption{
Instrument: "github.com/gogf/gf/example/metric/basic",
InstrumentVersion: "v1.0",
})

其中的 gmeter.MeterOption 数据结构如下:

// MeterOption holds the creation option for a Meter.
type MeterOption struct {
// Instrument is the instrumentation name to bind this Metric to a global MeterProvider.
// This is an optional configuration for a metric.
Instrument string

// InstrumentVersion is the instrumentation version to bind this Metric to a global MeterProvider.
// This is an optional configuration for a metric.
InstrumentVersion string

// Attributes holds the constant key-value pair description metadata for all metrics of Meter.
// This is an optional configuration for a meter.
Attributes Attributes
}

监控指标对象的创建

通过 Meter 接口对象,我们可以在该组件下创建对应的各种指标。指标有各种数据类型,因此 Meter 接口的定义如下:

// Meter hold the functions for kinds of Metric creating.
type Meter interface {
// Counter creates and returns a new Counter.
Counter(name string, option MetricOption) (Counter, error)

// UpDownCounter creates and returns a new UpDownCounter.
UpDownCounter(name string, option MetricOption) (UpDownCounter, error)

// Histogram creates and returns a new Histogram.
Histogram(name string, option MetricOption) (Histogram, error)

// ObservableCounter creates and returns a new ObservableCounter.
ObservableCounter(name string, option MetricOption) (ObservableCounter, error)

// ObservableUpDownCounter creates and returns a new ObservableUpDownCounter.
ObservableUpDownCounter(name string, option MetricOption) (ObservableUpDownCounter, error)

// ObservableGauge creates and returns a new ObservableGauge.
ObservableGauge(name string, option MetricOption) (ObservableGauge, error)

// MustCounter creates and returns a new Counter.
// It panics if any error occurs.
MustCounter(name string, option MetricOption) Counter

// MustUpDownCounter creates and returns a new UpDownCounter.
// It panics if any error occurs.
MustUpDownCounter(name string, option MetricOption) UpDownCounter

// MustHistogram creates and returns a new Histogram.
// It panics if any error occurs.
MustHistogram(name string, option MetricOption) Histogram

// MustObservableCounter creates and returns a new ObservableCounter.
// It panics if any error occurs.
MustObservableCounter(name string, option MetricOption) ObservableCounter

// MustObservableUpDownCounter creates and returns a new ObservableUpDownCounter.
// It panics if any error occurs.
MustObservableUpDownCounter(name string, option MetricOption) ObservableUpDownCounter

// MustObservableGauge creates and returns a new ObservableGauge.
// It panics if any error occurs.
MustObservableGauge(name string, option MetricOption) ObservableGauge

// RegisterCallback registers callback on certain metrics.
// A callback is bound to certain component and version, it is called when the associated metrics are read.
// Multiple callbacks on the same component and version will be called by their registered sequence.
RegisterCallback(callback Callback, canBeCallbackMetrics ...ObservableMetric) error

// MustRegisterCallback performs as RegisterCallback, but it panics if any error occurs.
MustRegisterCallback(callback Callback, canBeCallbackMetrics ...ObservableMetric)
}

以本示例代码中使用的 meter.MustCounter 方法来介绍,该方法是创建一个 Counter 同步指标,同时由于我们偷懒这个使用了 Must* 方法,也就是说如果创建指标失败,那么这个方法会 panic 报错。在创建指标对象时,指标名称 name 是必须参数,另外的 MetricOption 是可选项参数,用于进一步描述指标信息。 MetricOption 的数据结构定义如下:

// MetricOption holds the basic options for creating a metric.
type MetricOption struct {
// Help provides information about this Histogram.
// This is an optional configuration for a metric.
Help string

// Unit is the unit for metric value.
// This is an optional configuration for a metric.
Unit string

// Attributes holds the constant key-value pair description metadata for this metric.
// This is an optional configuration for a metric.
Attributes Attributes

// Buckets defines the buckets into which observations are counted.
// For Histogram metric only.
// A histogram metric uses default buckets if no explicit buckets configured.
Buckets []float64

// Callback function for metric, which is called when metric value changes.
// For observable metric only.
// If an observable metric has either Callback attribute nor global callback configured, it does nothing.
Callback MetricCallback
}

初始化监控指标实现

通过 otelmetric.MustProvider 创建方法即可创建并初始化监控指标管理对象。

provider := otelmetric.MustProvider(otelmetric.WithReader(reader))
provider.SetAsGlobal()
defer provider.Shutdown(ctx)

前面我们有介绍到, GlobalProvider 其实是一个单例的指标管理对象,因此这里通过 provider.SetAsGlobal 方法调用可以将该对象设置为全局的指标管理对象,便于后续的指标创建均基于该对象创建。

我们在 main 函数中通过 defer provider.ShutDown 方法调用便于在程序结束时优雅结束指标管理对象,例如对象中的指标缓存及时输出到目标端。

监控指标对象的使用

不同的指标对象有不同的操作方法用于实现指标数值的变化。以示例中的 Counter 指标类型为例,其接口定义如下:

// Counter is a Metric that represents a single numerical value that can ever
// goes up.
type Counter interface {
Metric
CounterPerformer
}

// CounterPerformer performs operations for Counter metric.
type CounterPerformer interface {
// Inc increments the counter by 1. Use Add to increment it by arbitrary
// non-negative values.
Inc(ctx context.Context, option ...Option)

// Add adds the given value to the counter. It panics if the value is < 0.
Add(ctx context.Context, increment float64, option ...Option)
}

可以看到, Counter 指标主要可以执行 IncAdd 两个操作方法。其中还有一个 Metric 的接口,所有的指标均实现了该接口用于获取当前指标的基础信息,其接口定义如下:

// Metric models a single sample value with its metadata being exported.
type Metric interface {
// Info returns the basic information of a Metric.
Info() MetricInfo
}

// MetricInfo exports information of the Metric.
type MetricInfo interface {
Key() string // Key returns the unique string key of the metric.
Name() string // Name returns the name of the metric.
Help() string // Help returns the help description of the metric.
Unit() string // Unit returns the unit name of the metric.
Type() MetricType // Type returns the type of the metric.
Attributes() Attributes // Attributes returns the constant attribute slice of the metric.
Instrument() InstrumentInfo // InstrumentInfo returns the instrument info of the metric.
}

// InstrumentInfo exports the instrument information of a metric.
type InstrumentInfo interface {
Name() string // Name returns the instrument name of the metric.
Version() string // Version returns the instrument version of the metric.
}

监控指标的数据读取

通过上一章节介绍的 OpenTelemetry 组件关系我们知道,如果想要使用指标必须要通过 MetricReader,因此在该示例代码中我们通过 OpenTelemetry 官方社区开源组件中最常用的 ManualReader 来简单实现指标数据读取, ManualReaderOpenTelemetry 官方社区提供的实现。

reader = metric.NewManualReader()

并通过 WithReader 方法配置到 Provider 中:

provider := otelmetric.MustProvider(otelmetric.WithReader(reader))

随后通过 Collect 方法可以获取当前所有的指标数据:

var (
rm = metricdata.ResourceMetrics{}
err = reader.Collect(ctx, &rm)
)
if err != nil {
g.Log().Fatal(ctx, err)
}
g.DumpJson(rm)

执行后,终端输出:

...
"ScopeMetrics": [
{
"Scope": {
"Name": "github.com/gogf/gf/example/metric/basic",
"Version": "v1.0",
"SchemaURL": ""
},
"Metrics": [
{
"Name": "goframe.metric.demo.counter",
"Description": "This is a simple demo for Counter usage",
"Unit": "bytes",
"Data": {
"DataPoints": [
{
"Attributes": [],
"StartTime": "2024-03-25T10:13:19.326977+08:00",
"Time": "2024-03-25T10:13:19.327144+08:00",
"Value": 11
}
],
"Temporality": "CumulativeTemporality",
"IsMonotonic": true
}
}
]
},
...

为了简化示例介绍,我们在这里省略了一些输出内容,更详细的指标及输出介绍请参考后续章节。