Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add metrics base api interface #2350

Merged
merged 2 commits into from
Jul 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions common/host_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
)

import (
"github.com/dubbogo/gost/log/logger"
gxnet "github.com/dubbogo/gost/net"
)

Expand All @@ -31,6 +32,7 @@ import (
)

var localIp string
var localHostname string

func GetLocalIp() string {
if len(localIp) != 0 {
Expand All @@ -40,6 +42,18 @@ func GetLocalIp() string {
return localIp
}

func GetLocalHostName() string {
if len(localHostname) != 0 {
return localHostname
}
hostname, err := os.Hostname()
if err != nil {
logger.Errorf("can not get local hostname")
}
localHostname = hostname
return localHostname
}

func HandleRegisterIPAndPort(url *URL) {
// if developer define registry port and ip, use it first.
if ipToRegistry := os.Getenv(constant.DubboIpToRegistryKey); len(ipToRegistry) > 0 {
Expand Down
12 changes: 9 additions & 3 deletions config/metric_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@ import (

"github.com/dubbogo/gost/log/logger"

"github.com/pkg/errors"
)

import (
"dubbo.apache.org/dubbo-go/v3/common/extension"
"dubbo.apache.org/dubbo-go/v3/metrics"
"github.com/pkg/errors"
)

// MetricConfig This is the config struct for all metrics implementation
Expand All @@ -36,6 +39,7 @@ type MetricConfig struct {
Path string `default:"/metrics" yaml:"path" json:"path,omitempty" property:"path"`
PushGatewayAddress string `default:"" yaml:"push-gateway-address" json:"push-gateway-address,omitempty" property:"push-gateway-address"`
SummaryMaxAge int64 `default:"600000000000" yaml:"summary-max-age" json:"summary-max-age,omitempty" property:"summary-max-age"`
Protocol string `default:"prometheus" yaml:"protocol" json:"protocol,omitempty" property:"protocol"`
}

func (mc *MetricConfig) ToReporterConfig() *metrics.ReporterConfig {
Expand Down Expand Up @@ -65,7 +69,9 @@ func (mc *MetricConfig) Init() error {
if err := verify(mc); err != nil {
return err
}
extension.GetMetricReporter("prometheus", mc.ToReporterConfig())
config := mc.ToReporterConfig()
extension.GetMetricReporter(mc.Protocol, config)
metrics.Init(config)
return nil
}

Expand All @@ -88,7 +94,7 @@ func (mc *MetricConfig) DynamicUpdateProperties(newMetricConfig *MetricConfig) {
mc.Enable = newMetricConfig.Enable
logger.Infof("MetricConfig's Enable was dynamically updated, new value:%v", mc.Enable)

extension.GetMetricReporter("prometheus", mc.ToReporterConfig())
extension.GetMetricReporter(mc.Protocol, mc.ToReporterConfig())
}
}
}
1 change: 1 addition & 0 deletions imports/imports.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ import (
_ "dubbo.apache.org/dubbo-go/v3/metadata/service/exporter/configurable"
_ "dubbo.apache.org/dubbo-go/v3/metadata/service/local"
_ "dubbo.apache.org/dubbo-go/v3/metadata/service/remote"
_ "dubbo.apache.org/dubbo-go/v3/metrics/app_info"
_ "dubbo.apache.org/dubbo-go/v3/metrics/prometheus"
_ "dubbo.apache.org/dubbo-go/v3/protocol/dubbo"
_ "dubbo.apache.org/dubbo-go/v3/protocol/dubbo3"
Expand Down
161 changes: 161 additions & 0 deletions metrics/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
package metrics

var registries = make(map[string]func(*ReporterConfig) MetricRegistry)
var collectors = make([]CollectorFunc, 0)
var registry MetricRegistry

// CollectorFunc 各个指标处理模块扩展
type CollectorFunc func(MetricRegistry, *ReporterConfig)

// Init 整个 Metrics 模块初始化入口
func Init(config *ReporterConfig) {
// config.extention = prometheus
regFunc, ok := registries[config.Protocol]
if !ok {
regFunc = registries["prometheus"] // default
}
registry = regFunc(config)
for _, co := range collectors {
co(registry, config)
}
registry.Export()
}

// SetRegistry 扩展其他数据容器,暴露方式,内置 Prometheus 实现
func SetRegistry(name string, v func(*ReporterConfig) MetricRegistry) {
registries[name] = v
}

// AddCollector 扩展指标收集器,例如 metadata、耗时、配置中心等
func AddCollector(name string, fun func(MetricRegistry, *ReporterConfig)) {
collectors = append(collectors, fun)
}

// MetricRegistry 数据指标容器,指标计算、指标暴露、聚合
type MetricRegistry interface {
Counter(*MetricId) CounterMetric // add or update a counter
Gauge(*MetricId) GaugeMetric // add or update a gauge
Histogram(*MetricId) HistogramMetric // add a metric num to a histogram
Summary(*MetricId) SummaryMetric // add a metric num to a summary
Export() // 数据暴露, 如 Prometheus 是 http 暴露
// GetMetrics() []*MetricSample // 获取所有指标数据
// GetMetricsString() (string, error) // 如需复用端口则加一下这个接口
}

// 组合暴露方式,参考 micrometer CompositeMeterRegistry
//type CompositeRegistry struct {
// rs []MetricRegistry
//}

// Type 指标类型,暂定和 micrometer 一致
type Type uint8

const (
Counter Type = iota
Gauge
LongTaskTimer
Timer
DistributionSummary
Other
)

// MetricId
// # HELP dubbo_metadata_store_provider_succeed_total Succeed Store Provider Metadata
// # TYPE dubbo_metadata_store_provider_succeed_total gauge
// dubbo_metadata_store_provider_succeed_total{application_name="provider",hostname="localhost",interface="org.example.DemoService",ip="10.252.156.213",} 1.0
// 除值以外的其他属性
type MetricId struct {
Name string
Desc string
Tags map[string]string
Type Type
}

func (m *MetricId) TagKeys() []string {
keys := make([]string, 0, len(m.Tags))
for k := range m.Tags {
keys = append(keys, k)
}
return keys
}

// MetricSample 一个指标的完整定义,包含值,这是指标的最终呈现,不是中间值(如 summary,histogram 他们统计完后会导出为一组 MetricSample)
type MetricSample struct {
*MetricId
value float64
}

// CounterMetric 指标抽象接口
type CounterMetric interface {
Inc()
Add(float64)
}

// GaugeMetric 指标抽象接口
type GaugeMetric interface {
Set(float64)
// Inc()
// Dec()
// Add(float64)
// Sub(float64)
}

// HistogramMetric 指标抽象接口
type HistogramMetric interface {
Record(float64)
}

// SummaryMetric 指标抽象接口
type SummaryMetric interface {
Record(float64)
}

// StatesMetrics 综合指标,包括总数、成功数,失败数,调用 MetricsRegistry 实现最终暴露
type StatesMetrics interface {
Success()
AddSuccess(float64)
Fail()
AddFailed(float64)
}

func NewStatesMetrics(total *MetricId, succ *MetricId, fail *MetricId) StatesMetrics {
return &DefaultStatesMetric{total: total, succ: succ, fail: fail, r: registry}
}

// TimeMetrics 综合指标, 包括 min(Gauge)、max(Gauge)、avg(Gauge)、sum(Gauge)、last(Gauge),调用 MetricRegistry 实现最终暴露
// 参见 dubbo-java org.apache.dubbo.metrics.aggregate.TimeWindowAggregator 类实现
type TimeMetrics interface {
Record(float64)
}

// NewTimeMetrics init and write all data to registry
func NewTimeMetrics(min *MetricId, avg *MetricId, max *MetricId, last *MetricId, sum *MetricId) {

}

type DefaultStatesMetric struct {
r MetricRegistry
total *MetricId
succ *MetricId
fail *MetricId
}

func (c DefaultStatesMetric) Success() {
c.r.Counter(c.total).Inc()
c.r.Counter(c.succ).Inc()
}

func (c DefaultStatesMetric) AddSuccess(v float64) {
c.r.Counter(c.total).Add(v)
c.r.Counter(c.succ).Add(v)
}

func (c DefaultStatesMetric) Fail() {
c.r.Counter(c.total).Inc()
c.r.Counter(c.fail).Inc()
}

func (c DefaultStatesMetric) AddFailed(v float64) {
c.r.Counter(c.total).Add(v)
c.r.Counter(c.fail).Add(v)
}
36 changes: 36 additions & 0 deletions metrics/app_info/application_info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package app_info

import (
"dubbo.apache.org/dubbo-go/v3/metrics"
"dubbo.apache.org/dubbo-go/v3/metrics/common"
)

/*
* # HELP dubbo_application_info_total Total Application Info
* # TYPE dubbo_application_info_total counter
* dubbo_application_info_total{application_name="metrics-provider",application_version="3.2.1",git_commit_id="20de8b22ffb2a23531f6d9494a4963fcabd52561",hostname="localhost",ip="127.0.0.1",} 1.0
*/
var info = common.NewMetricKey("dubbo_application_info_total", "Total Application Info") // Total Application Info include application name、version etc

func init() {
metrics.AddCollector("application_info", func(mr metrics.MetricRegistry, config *metrics.ReporterConfig) {
mr.Counter(&metrics.MetricId{Name: info.Name, Desc: info.Desc, Tags: common.NewApplicationLevel().Tags()}).Inc()
})
}
101 changes: 101 additions & 0 deletions metrics/common/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package common

import (
"dubbo.apache.org/dubbo-go/v3/common"
"dubbo.apache.org/dubbo-go/v3/config"
)

const (
TagIp = "ip"
TagPid = "pid"
TagHostname = "hostname"
TagApplicationName = "application_name"
TagApplicationModule = "application_module_id"
TagInterfaceKey = "interface"
TagMethodKey = "method"
TagGroupKey = "group"
TagVersionKey = "version"
TagApplicationVersionKey = "application_version"
TagKeyKey = "key"
TagConfigCenter = "config_center"
TagChangeType = "change_type"
TagThreadName = "thread_pool_name"
TagGitCommitId = "git_commit_id"
)

type MetricKey struct {
Name string
Desc string
}

func NewMetricKey(name string, desc string) *MetricKey {
return &MetricKey{Name: name, Desc: desc}
}

type MetricLevel interface {
Tags() map[string]string
}

type ApplicationMetricLevel struct {
ApplicationName string
Version string
GitCommitId string
Ip string
HostName string
}

var appLevel *ApplicationMetricLevel

func NewApplicationLevel() *ApplicationMetricLevel {
if appLevel == nil {
var rootConfig = config.GetRootConfig()
appLevel = &ApplicationMetricLevel{
ApplicationName: rootConfig.Application.Name,
Version: rootConfig.Application.Version,
Ip: common.GetLocalIp(),
HostName: common.GetLocalHostName(),
GitCommitId: "",
}
}
return appLevel
}

func (m *ApplicationMetricLevel) Tags() map[string]string {
tags := make(map[string]string)
tags[TagIp] = m.Ip
tags[TagHostname] = m.HostName
tags[TagApplicationName] = m.ApplicationName
tags[TagApplicationVersionKey] = m.Version
tags[TagGitCommitId] = m.GitCommitId
return tags
}

type ServiceMetricLevel struct {
*ApplicationMetricLevel
Interface string
}

func NewServiceMetric(interfaceName string) *ServiceMetricLevel {
return &ServiceMetricLevel{ApplicationMetricLevel: NewApplicationLevel(), Interface: interfaceName}
}

func (m ServiceMetricLevel) Tags() map[string]string {
tags := m.ApplicationMetricLevel.Tags()
tags[TagInterfaceKey] = m.Interface
return tags
}

type MethodMetricLevel struct {
*ServiceMetricLevel
Method string
Group string
Version string
}

func (m MethodMetricLevel) Tags() map[string]string {
tags := m.ServiceMetricLevel.Tags()
tags[TagMethodKey] = m.Method
tags[TagGroupKey] = m.Group
tags[TagVersionKey] = m.Version
return tags
}
Loading