这是本节的多页打印视图。 点击此处打印.

返回本页常规视图.

Metrics的源码学习

Dapr Metrics的源码学习

1 - exporter.go的源码学习

Exporter 是用于 metrics 导出器的接口,当前只支持 Prometheus

Dapr metrics package中的 exporter.go文件的源码分析,包括结构体定义、方法实现。当前只支持 Prometheus。

Exporter定义和实现

Exporter 接口定义

Exporter 接口定义:

// Exporter is the interface for metrics exporters
type Exporter interface {
	// Init initializes metrics exporter
	Init() error
	// Options returns Exporter options
	Options() *Options
}

exporter 结构体定义

exporter 结构体定义:

// exporter is the base struct
type exporter struct {
	namespace string
	options   *Options
	logger    logger.Logger
}

构建 exporter

// NewExporter creates new MetricsExporter instance
func NewExporter(namespace string) Exporter {
	// TODO: support multiple exporters
	return &promMetricsExporter{
		&exporter{
			namespace: namespace,
			options:   defaultMetricOptions(),
			logger:    logger.NewLogger("dapr.metrics"),
		},
		nil,
	}
}

当前只支持 promMetrics 的 Exporter。

接口方法Options()的实现

Options() 方法简单返回 m.options:

// Options returns current metric exporter options
func (m *exporter) Options() *Options {
	return m.options
}

具体的赋值在 defaultMetricOptions().

Prometheus Exporter的实现

promMetricsExporter 结构体定义

// promMetricsExporter is prometheus metric exporter
type promMetricsExporter struct {
	*exporter
	ocExporter *ocprom.Exporter
}

内嵌 exporter (相当于继承),还有一个 ocprom.Exporter 字段。

接口方法 Init() 的实现

初始化 opencensus 的 exporter:


// Init initializes opencensus exporter
func (m *promMetricsExporter) Init() error {
	if !m.exporter.Options().MetricsEnabled {
		return nil
	}

	// Add default health metrics for process
	
	// 添加默认的 health metrics: 进程信息,和 go 信息
	registry := prom.NewRegistry()
	registry.MustRegister(prom.NewProcessCollector(prom.ProcessCollectorOpts{}))
	registry.MustRegister(prom.NewGoCollector())

	var err error
	m.ocExporter, err = ocprom.NewExporter(ocprom.Options{
		Namespace: m.namespace,
		Registry:  registry,
	})

	if err != nil {
		return errors.Errorf("failed to create Prometheus exporter: %v", err)
	}

	// register exporter to view
	view.RegisterExporter(m.ocExporter)

	// start metrics server
	return m.startMetricServer()
}

startMetricServer() 方法的实现

启动 MetricServer, 监听端口来自 options 的 MetricsPort,监听路径为 defaultMetricsPath:


const (
	defaultMetricsPath     = "/"
)

// startMetricServer starts metrics server
func (m *promMetricsExporter) startMetricServer() error {
	if !m.exporter.Options().MetricsEnabled {
		// skip if metrics is not enabled
		return nil
	}

	addr := fmt.Sprintf(":%d", m.options.MetricsPort())

	if m.ocExporter == nil {
		return errors.New("exporter was not initialized")
	}

	m.exporter.logger.Infof("metrics server started on %s%s", addr, defaultMetricsPath)
	go func() {
		mux := http.NewServeMux()
		mux.Handle(defaultMetricsPath, m.ocExporter)

		if err := http.ListenAndServe(addr, mux); err != nil {
			m.exporter.logger.Fatalf("failed to start metrics server: %v", err)
		}
	}()

	return nil
}

2 - options.go的源码学习

metrics 相关的配置选项

Dapr metrics package中的 options.go文件的源码学习

代码实现

Options 结构体定义

// Options defines the sets of options for Dapr logging
type Options struct {
	// OutputLevel is the level of logging
	MetricsEnabled bool

	metricsPort string
}

默认值

metrics 默认端口 9090, 默认启用 metrics:

const (
	defaultMetricsPort    = "9090"
	defaultMetricsEnabled = true
)

func defaultMetricOptions() *Options {
	return &Options{
		metricsPort:    defaultMetricsPort,
		MetricsEnabled: defaultMetricsEnabled,
	}
}

MetricsPort() 方法实现

MetricsPort() 方法用于获取 metrics 端口,如果配置错误,则使用默认端口 9090:

// MetricsPort gets metrics port.
func (o *Options) MetricsPort() uint64 {
	port, err := strconv.ParseUint(o.metricsPort, 10, 64)
	if err != nil {
		// Use default metrics port as a fallback
		port, _ = strconv.ParseUint(defaultMetricsPort, 10, 64)
	}

	return port
}

解析命令行标记的方法

AttachCmdFlags() 方法

AttachCmdFlags() 方法解析 metrics-port 和 enable-metrics 两个命令行标记:

// AttachCmdFlags attaches metrics options to command flags
func (o *Options) AttachCmdFlags(
	stringVar func(p *string, name string, value string, usage string),
	boolVar func(p *bool, name string, value bool, usage string)) {
	stringVar(
		&o.metricsPort,
		"metrics-port",
		defaultMetricsPort,
		"The port for the metrics server")
	boolVar(
		&o.MetricsEnabled,
		"enable-metrics",
		defaultMetricsEnabled,
		"Enable prometheus metric")
}

AttachCmdFlag() 方法

AttachCmdFlag() 方法只解析 metrics-port 命令行标记(不解析 enable-metrics ) :

// AttachCmdFlag attaches single metrics option to command flags
func (o *Options) AttachCmdFlag(
	stringVar func(p *string, name string, value string, usage string)) {
	stringVar(
		&o.metricsPort,
		"metrics-port",
		defaultMetricsPort,
		"The port for the metrics server")
}

使用场景

只解析 metrics-port 命令行标记 的 AttachCmdFlag() 方法在 dapr runtime 启动时被调用(也只被这一个地方调用):

metricsExporter := metrics.NewExporter(metrics.DefaultMetricNamespace)

// attaching only metrics-port option
metricsExporter.Options().AttachCmdFlag(flag.StringVar)

而解析 metrics-port 和 enable-metrics 两个命令行标记的 AttachCmdFlags() 方法被 injector / operator / placement / sentry 调用:

func init() {
	metricsExporter := metrics.NewExporter(metrics.DefaultMetricNamespace)
	metricsExporter.Options().AttachCmdFlags(flag.StringVar, flag.BoolVar)
}