Skip to content

Commit e30ca64

Browse files
authored
Introduce compat package to ease migration from the old armon/go-metrice module name to the current hashicorp/go-metrics name (#169)
* Introduce `compat` package to ease migration from the old armon/go-metrics module name to the current hashicorp/go-metrics name * Update README.md to include backwards compatibility info * Fix typos
1 parent c5fef7b commit e30ca64

File tree

11 files changed

+426
-3
lines changed

11 files changed

+426
-3
lines changed

README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,46 @@ By default, both `Config.AllowedLabels` and `Config.BlockedLabels` are nil, mean
4141
no tags are filtered at all, but it allows a user to globally block some tags with high
4242
cardinality at the application level.
4343

44+
Backwards Compatibility
45+
-----------------------
46+
v0.5.0 of the library renamed the Go module from `github.com/armon/go-metrics` to `github.com/hashicorp/go-metrics`.
47+
While this did not introduce any breaking changes to the API, the change did subtly break backwards compatibility.
48+
49+
In essence, Go treats a renamed module as entirely distinct and will happily compile both modules into the same binary.
50+
Due to most uses of the go-metrics library involving emitting metrics via the global metrics handler, having two global
51+
metrics handlers could cause a subset of metrics to be effectively lost. As an example, if your application configures
52+
go-metrics exporting via the `armon` namespace, then any metrics sent to go-metrics via the `hashicorp` namespaced module
53+
will never get exported.
54+
55+
Eventually all usage of `armon/go-metrics` should be replaced with usage of `hashicorp/go-metrics`. However, a single
56+
point-in-time coordinated update across all libraries that an application may depend on isn't always feasible. To facilitate migrations,
57+
a `github.com/hashicorp/go-metrics/compat` package has been introduced. This package and sub-packages are API compatible with
58+
`armon/go-metrics`. Libraries should be updated to use this package for emitting metrics via the global handlers. Internally,
59+
the package will route metrics to either `armon/go-metrics` or `hashicorp/go-metrics`. This is achieved at a global level
60+
within an application via the use of Go build tags.
61+
62+
**Build Tags**
63+
* `armonmetrics` - Using this tag will cause metrics to be routed to `armon/go-metrics`
64+
* `hashicorpmetrics` - Using this tag will cause all metrics to be routed to `hashicorp/go-metrics`
65+
66+
If no build tag is specified, the default behavior is to use `armon/go-metrics`. The overall migration path would be as follows:
67+
68+
1. Upgrade libraries using `armon/go-metrics` to consume `hashicorp/go-metrics/compat` instead.
69+
2. Update library dependencies of applications that use `armon/go-metrics`.
70+
* This doesn't need to be one big atomic update but can be slower due to the default behavior remaining unaltered.
71+
* At this point all metrics will still be emitted to `armon/go-metrics`
72+
3. Update the application to use `hashicorp/go-metrics`
73+
* Replace all application imports of `github.com/armon/go-metrics` with `github.com/hashicorp/go-metrics`
74+
* Libraries are unaltered at this stage.
75+
* Instrument your build system to build with the `hashicorpmetrics` tag.
76+
77+
Your migration is effectively finished and your application is now exclusively using `hashicorp/go-metrics`. A future release of the library
78+
will change the default behavior to use `hashicorp/go-metrics` instead of `armon/go-metrics`. At that point in time, any application that
79+
needs more time before performing the migration must instrument their build system to include the `armonmetrics` tag. A subsequent release
80+
after that will eventually remove the compatibility layer all together. The rough timeline for this will be mid-2025 for changing the default
81+
behavior and then the end of 2025 for removal of the compatibility layer.
82+
83+
4484
Examples
4585
--------
4686

compat/armon.go

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
//go:build armonmetrics || ignore || !hashicorpmetrics
2+
// +build armonmetrics ignore !hashicorpmetrics
3+
4+
package metrics
5+
6+
import (
7+
"io"
8+
"net/url"
9+
"syscall"
10+
"time"
11+
12+
"github.com/armon/go-metrics"
13+
)
14+
15+
const (
16+
// DefaultSignal is used with DefaultInmemSignal
17+
DefaultSignal = metrics.DefaultSignal
18+
)
19+
20+
func AddSample(key []string, val float32) {
21+
metrics.AddSample(key, val)
22+
}
23+
func AddSampleWithLabels(key []string, val float32, labels []Label) {
24+
metrics.AddSampleWithLabels(key, val, labels)
25+
}
26+
func EmitKey(key []string, val float32) {
27+
metrics.EmitKey(key, val)
28+
}
29+
func IncrCounter(key []string, val float32) {
30+
metrics.IncrCounter(key, val)
31+
}
32+
func IncrCounterWithLabels(key []string, val float32, labels []Label) {
33+
metrics.IncrCounterWithLabels(key, val, labels)
34+
}
35+
func MeasureSince(key []string, start time.Time) {
36+
metrics.MeasureSince(key, start)
37+
}
38+
func MeasureSinceWithLabels(key []string, start time.Time, labels []Label) {
39+
metrics.MeasureSinceWithLabels(key, start, labels)
40+
}
41+
func SetGauge(key []string, val float32) {
42+
metrics.SetGauge(key, val)
43+
}
44+
func SetGaugeWithLabels(key []string, val float32, labels []Label) {
45+
metrics.SetGaugeWithLabels(key, val, labels)
46+
}
47+
func Shutdown() {
48+
metrics.Shutdown()
49+
}
50+
func UpdateFilter(allow, block []string) {
51+
metrics.UpdateFilter(allow, block)
52+
}
53+
func UpdateFilterAndLabels(allow, block, allowedLabels, blockedLabels []string) {
54+
metrics.UpdateFilterAndLabels(allow, block, allowedLabels, blockedLabels)
55+
}
56+
57+
type AggregateSample = metrics.AggregateSample
58+
type BlackholeSink = metrics.BlackholeSink
59+
type Config = metrics.Config
60+
type Encoder = metrics.Encoder
61+
type FanoutSink = metrics.FanoutSink
62+
type GaugeValue = metrics.GaugeValue
63+
type InmemSignal = metrics.InmemSignal
64+
type InmemSink = metrics.InmemSink
65+
type IntervalMetrics = metrics.IntervalMetrics
66+
type Label = metrics.Label
67+
type MetricSink = metrics.MetricSink
68+
type Metrics = metrics.Metrics
69+
type MetricsSummary = metrics.MetricsSummary
70+
type PointValue = metrics.PointValue
71+
type SampledValue = metrics.SampledValue
72+
type ShutdownSink = metrics.ShutdownSink
73+
type StatsdSink = metrics.StatsdSink
74+
type StatsiteSink = metrics.StatsiteSink
75+
76+
func DefaultConfig(serviceName string) *Config {
77+
return metrics.DefaultConfig(serviceName)
78+
}
79+
80+
func DefaultInmemSignal(inmem *InmemSink) *InmemSignal {
81+
return metrics.DefaultInmemSignal(inmem)
82+
}
83+
func NewInmemSignal(inmem *InmemSink, sig syscall.Signal, w io.Writer) *InmemSignal {
84+
return metrics.NewInmemSignal(inmem, sig, w)
85+
}
86+
87+
func NewInmemSink(interval, retain time.Duration) *InmemSink {
88+
return metrics.NewInmemSink(interval, retain)
89+
}
90+
91+
func NewIntervalMetrics(intv time.Time) *IntervalMetrics {
92+
return metrics.NewIntervalMetrics(intv)
93+
}
94+
95+
func NewInmemSinkFromURL(u *url.URL) (MetricSink, error) {
96+
return metrics.NewInmemSinkFromURL(u)
97+
}
98+
99+
func NewMetricSinkFromURL(urlStr string) (MetricSink, error) {
100+
return metrics.NewMetricSinkFromURL(urlStr)
101+
}
102+
103+
func NewStatsdSinkFromURL(u *url.URL) (MetricSink, error) {
104+
return metrics.NewStatsdSinkFromURL(u)
105+
}
106+
107+
func NewStatsiteSinkFromURL(u *url.URL) (MetricSink, error) {
108+
return metrics.NewStatsiteSinkFromURL(u)
109+
}
110+
111+
func Default() *Metrics {
112+
return metrics.Default()
113+
}
114+
115+
func New(conf *Config, sink MetricSink) (*Metrics, error) {
116+
return metrics.New(conf, sink)
117+
}
118+
119+
func NewGlobal(conf *Config, sink MetricSink) (*Metrics, error) {
120+
return metrics.NewGlobal(conf, sink)
121+
}
122+
123+
func NewStatsdSink(addr string) (*StatsdSink, error) {
124+
return metrics.NewStatsdSink(addr)
125+
}
126+
127+
func NewStatsiteSink(addr string) (*StatsiteSink, error) {
128+
return metrics.NewStatsiteSink(addr)
129+
}

compat/circonus/armon.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//go:build armonmetrics || ignore || !hashicorpmetrics
2+
// +build armonmetrics ignore !hashicorpmetrics
3+
4+
package circonus
5+
6+
import (
7+
"github.com/armon/go-metrics/circonus"
8+
)
9+
10+
type CirconusSink = circonus.CirconusSink
11+
type Config = circonus.Config
12+
13+
func NewCirconusSink(cc *Config) (*CirconusSink, error) {
14+
return circonus.NewCirconusSink(cc)
15+
}

compat/circonus/hashicorp.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//go:build hashicorpmetrics
2+
// +build hashicorpmetrics
3+
4+
package circonus
5+
6+
import (
7+
"github.com/hashicorp/go-metrics/circonus"
8+
)
9+
10+
type CirconusSink = circonus.CirconusSink
11+
type Config = circonus.Config
12+
13+
func NewCirconusSink(cc *Config) (*CirconusSink, error) {
14+
return circonus.NewCirconusSink(cc)
15+
}

compat/datadog/armon.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//go:build armonmetrics || ignore || !hashicorpmetrics
2+
// +build armonmetrics ignore !hashicorpmetrics
3+
4+
package datadog
5+
6+
import (
7+
"github.com/armon/go-metrics/datadog"
8+
)
9+
10+
type DogStatsdSink = datadog.DogStatsdSink
11+
12+
func NewDogStatsdSink(addr string, hostName string) (*DogStatsdSink, error) {
13+
return datadog.NewDogStatsdSink(addr, hostName)
14+
}

compat/datadog/hashicorp.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//go:build hashicorpmetrics
2+
// +build hashicorpmetrics
3+
4+
package datadog
5+
6+
import (
7+
"github.com/hashicorp/go-metrics/datadog"
8+
)
9+
10+
type DogStatsdSink = datadog.DogStatsdSink
11+
12+
func NewDogStatsdSink(addr string, hostName string) (*DogStatsdSink, error) {
13+
return datadog.NewDogStatsdSink(addr, hostName)
14+
}

compat/hashicorp.go

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
//go:build hashicorpmetrics
2+
// +build hashicorpmetrics
3+
4+
package metrics
5+
6+
import (
7+
"io"
8+
"net/url"
9+
"syscall"
10+
"time"
11+
12+
"github.com/hashicorp/go-metrics"
13+
)
14+
15+
const (
16+
// DefaultSignal is used with DefaultInmemSignal
17+
DefaultSignal = metrics.DefaultSignal
18+
)
19+
20+
func AddSample(key []string, val float32) {
21+
metrics.AddSample(key, val)
22+
}
23+
func AddSampleWithLabels(key []string, val float32, labels []Label) {
24+
metrics.AddSampleWithLabels(key, val, labels)
25+
}
26+
func EmitKey(key []string, val float32) {
27+
metrics.EmitKey(key, val)
28+
}
29+
func IncrCounter(key []string, val float32) {
30+
metrics.IncrCounter(key, val)
31+
}
32+
func IncrCounterWithLabels(key []string, val float32, labels []Label) {
33+
metrics.IncrCounterWithLabels(key, val, labels)
34+
}
35+
func MeasureSince(key []string, start time.Time) {
36+
metrics.MeasureSince(key, start)
37+
}
38+
func MeasureSinceWithLabels(key []string, start time.Time, labels []Label) {
39+
metrics.MeasureSinceWithLabels(key, start, labels)
40+
}
41+
func SetGauge(key []string, val float32) {
42+
metrics.SetGauge(key, val)
43+
}
44+
func SetGaugeWithLabels(key []string, val float32, labels []Label) {
45+
metrics.SetGaugeWithLabels(key, val, labels)
46+
}
47+
func Shutdown() {
48+
metrics.Shutdown()
49+
}
50+
func UpdateFilter(allow, block []string) {
51+
metrics.UpdateFilter(allow, block)
52+
}
53+
func UpdateFilterAndLabels(allow, block, allowedLabels, blockedLabels []string) {
54+
metrics.UpdateFilterAndLabels(allow, block, allowedLabels, blockedLabels)
55+
}
56+
57+
type AggregateSample = metrics.AggregateSample
58+
type BlackholeSink = metrics.BlackholeSink
59+
type Config = metrics.Config
60+
type Encoder = metrics.Encoder
61+
type FanoutSink = metrics.FanoutSink
62+
type GaugeValue = metrics.GaugeValue
63+
type InmemSignal = metrics.InmemSignal
64+
type InmemSink = metrics.InmemSink
65+
type IntervalMetrics = metrics.IntervalMetrics
66+
type Label = metrics.Label
67+
type MetricSink = metrics.MetricSink
68+
type Metrics = metrics.Metrics
69+
type MetricsSummary = metrics.MetricsSummary
70+
type PointValue = metrics.PointValue
71+
type SampledValue = metrics.SampledValue
72+
type ShutdownSink = metrics.ShutdownSink
73+
type StatsdSink = metrics.StatsdSink
74+
type StatsiteSink = metrics.StatsiteSink
75+
76+
func DefaultConfig(serviceName string) *Config {
77+
return metrics.DefaultConfig(serviceName)
78+
}
79+
80+
func DefaultInmemSignal(inmem *InmemSink) *InmemSignal {
81+
return metrics.DefaultInmemSignal(inmem)
82+
}
83+
func NewInmemSignal(inmem *InmemSink, sig syscall.Signal, w io.Writer) *InmemSignal {
84+
return metrics.NewInmemSignal(inmem, sig, w)
85+
}
86+
87+
func NewInmemSink(interval, retain time.Duration) *InmemSink {
88+
return metrics.NewInmemSink(interval, retain)
89+
}
90+
91+
func NewIntervalMetrics(intv time.Time) *IntervalMetrics {
92+
return metrics.NewIntervalMetrics(intv)
93+
}
94+
95+
func NewInmemSinkFromURL(u *url.URL) (MetricSink, error) {
96+
return metrics.NewInmemSinkFromURL(u)
97+
}
98+
99+
func NewMetricSinkFromURL(urlStr string) (MetricSink, error) {
100+
return metrics.NewMetricSinkFromURL(urlStr)
101+
}
102+
103+
func NewStatsdSinkFromURL(u *url.URL) (MetricSink, error) {
104+
return metrics.NewStatsdSinkFromURL(u)
105+
}
106+
107+
func NewStatsiteSinkFromURL(u *url.URL) (MetricSink, error) {
108+
return metrics.NewStatsiteSinkFromURL(u)
109+
}
110+
111+
func Default() *Metrics {
112+
return metrics.Default()
113+
}
114+
115+
func New(conf *Config, sink MetricSink) (*Metrics, error) {
116+
return metrics.New(conf, sink)
117+
}
118+
119+
func NewGlobal(conf *Config, sink MetricSink) (*Metrics, error) {
120+
return metrics.NewGlobal(conf, sink)
121+
}
122+
123+
func NewStatsdSink(addr string) (*StatsdSink, error) {
124+
return metrics.NewStatsdSink(addr)
125+
}
126+
127+
func NewStatsiteSink(addr string) (*StatsiteSink, error) {
128+
return metrics.NewStatsiteSink(addr)
129+
}

0 commit comments

Comments
 (0)