基本介绍
监控指标的代码开发直接使用框架主库的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
指标主要可以执行Inc
及Add
两个操作方法。其中还有一个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
来简单实现指标数据读取,ManualReader
是OpenTelemetry
官方社区提供的实现。
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
}
}
]
},
...
为了简化示例介绍,我们在这里省略了一些输出内容,更详细的指标及输出介绍请参考后续章节。