liuxiaolong
2022-06-28 37714b1093c04061e636e5b1d27179652e671c0a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package metrics
 
import (
    "os"
    "sync"
    "sync/atomic"
    "time"
 
    "github.com/hashicorp/go-immutable-radix"
)
 
// Config is used to configure metrics settings
type Config struct {
    ServiceName          string        // Prefixed with keys to separate services
    HostName             string        // Hostname to use. If not provided and EnableHostname, it will be os.Hostname
    EnableHostname       bool          // Enable prefixing gauge values with hostname
    EnableHostnameLabel  bool          // Enable adding hostname to labels
    EnableServiceLabel   bool          // Enable adding service to labels
    EnableRuntimeMetrics bool          // Enables profiling of runtime metrics (GC, Goroutines, Memory)
    EnableTypePrefix     bool          // Prefixes key with a type ("counter", "gauge", "timer")
    TimerGranularity     time.Duration // Granularity of timers.
    ProfileInterval      time.Duration // Interval to profile runtime metrics
 
    AllowedPrefixes []string // A list of metric prefixes to allow, with '.' as the separator
    BlockedPrefixes []string // A list of metric prefixes to block, with '.' as the separator
    AllowedLabels   []string // A list of metric labels to allow, with '.' as the separator
    BlockedLabels   []string // A list of metric labels to block, with '.' as the separator
    FilterDefault   bool     // Whether to allow metrics by default
}
 
// Metrics represents an instance of a metrics sink that can
// be used to emit
type Metrics struct {
    Config
    lastNumGC     uint32
    sink          MetricSink
    filter        *iradix.Tree
    allowedLabels map[string]bool
    blockedLabels map[string]bool
    filterLock    sync.RWMutex // Lock filters and allowedLabels/blockedLabels access
}
 
// Shared global metrics instance
var globalMetrics atomic.Value // *Metrics
 
func init() {
    // Initialize to a blackhole sink to avoid errors
    globalMetrics.Store(&Metrics{sink: &BlackholeSink{}})
}
 
// DefaultConfig provides a sane default configuration
func DefaultConfig(serviceName string) *Config {
    c := &Config{
        ServiceName:          serviceName, // Use client provided service
        HostName:             "",
        EnableHostname:       true,             // Enable hostname prefix
        EnableRuntimeMetrics: true,             // Enable runtime profiling
        EnableTypePrefix:     false,            // Disable type prefix
        TimerGranularity:     time.Millisecond, // Timers are in milliseconds
        ProfileInterval:      time.Second,      // Poll runtime every second
        FilterDefault:        true,             // Don't filter metrics by default
    }
 
    // Try to get the hostname
    name, _ := os.Hostname()
    c.HostName = name
    return c
}
 
// New is used to create a new instance of Metrics
func New(conf *Config, sink MetricSink) (*Metrics, error) {
    met := &Metrics{}
    met.Config = *conf
    met.sink = sink
    met.UpdateFilterAndLabels(conf.AllowedPrefixes, conf.BlockedPrefixes, conf.AllowedLabels, conf.BlockedLabels)
 
    // Start the runtime collector
    if conf.EnableRuntimeMetrics {
        go met.collectStats()
    }
    return met, nil
}
 
// NewGlobal is the same as New, but it assigns the metrics object to be
// used globally as well as returning it.
func NewGlobal(conf *Config, sink MetricSink) (*Metrics, error) {
    metrics, err := New(conf, sink)
    if err == nil {
        globalMetrics.Store(metrics)
    }
    return metrics, err
}
 
// Proxy all the methods to the globalMetrics instance
func SetGauge(key []string, val float32) {
    globalMetrics.Load().(*Metrics).SetGauge(key, val)
}
 
func SetGaugeWithLabels(key []string, val float32, labels []Label) {
    globalMetrics.Load().(*Metrics).SetGaugeWithLabels(key, val, labels)
}
 
func EmitKey(key []string, val float32) {
    globalMetrics.Load().(*Metrics).EmitKey(key, val)
}
 
func IncrCounter(key []string, val float32) {
    globalMetrics.Load().(*Metrics).IncrCounter(key, val)
}
 
func IncrCounterWithLabels(key []string, val float32, labels []Label) {
    globalMetrics.Load().(*Metrics).IncrCounterWithLabels(key, val, labels)
}
 
func AddSample(key []string, val float32) {
    globalMetrics.Load().(*Metrics).AddSample(key, val)
}
 
func AddSampleWithLabels(key []string, val float32, labels []Label) {
    globalMetrics.Load().(*Metrics).AddSampleWithLabels(key, val, labels)
}
 
func MeasureSince(key []string, start time.Time) {
    globalMetrics.Load().(*Metrics).MeasureSince(key, start)
}
 
func MeasureSinceWithLabels(key []string, start time.Time, labels []Label) {
    globalMetrics.Load().(*Metrics).MeasureSinceWithLabels(key, start, labels)
}
 
func UpdateFilter(allow, block []string) {
    globalMetrics.Load().(*Metrics).UpdateFilter(allow, block)
}
 
// UpdateFilterAndLabels set allow/block prefixes of metrics while allowedLabels
// and blockedLabels - when not nil - allow filtering of labels in order to
// block/allow globally labels (especially useful when having large number of
// values for a given label). See README.md for more information about usage.
func UpdateFilterAndLabels(allow, block, allowedLabels, blockedLabels []string) {
    globalMetrics.Load().(*Metrics).UpdateFilterAndLabels(allow, block, allowedLabels, blockedLabels)
}