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

Introduce compat package to ease migration from the old armon/go-metrice module name to the current hashicorp/go-metrics name #169

Merged
merged 3 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from 2 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
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,46 @@ By default, both `Config.AllowedLabels` and `Config.BlockedLabels` are nil, mean
no tags are filtered at all, but it allows a user to globally block some tags with high
cardinality at the application level.

Backwards Compatibility
-----------------------
v0.5.0 of the library renamed the Go module from `github.com/armon/go-metrics` to `github.com/hashicorp/go-metrics`.
While this did not introduce any breaking changes to the API, the change did subtly break backwards compatibility.

In essence, Go treats a renamed module as entirely distinct and will happily compile both modules into the same binary.
Due to most uses of the go-metrics library involving emitting metrics via the global metrics handler, having two global
metrics handlers could cause a subset of metrics to be effectively lost. As an example, if your application configures
go-metrics exporting via the `armon` namespace, then any metrics sent to go-metrics via the `hashicorp` namespaced module
will never get exported.

Eventually all usage of `armon/go-metrics` should be replaced with usage of `hashicorp/go-metrics`. However, a single
point-in-time coordinated update across all libraries than an application may depend on isn't always feasible. To faciliate migrations,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: typo
... across all libraries that an application ...
... To facilitate migrations ...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this is fixed now.

a `github.com/hashicorp/go-metrics/compat` package has been introduced. This package and sub-packages are API compatible with
`armon/go-metrics`. Libraries should be updated to use this package for emitting metrics via the global handlers. Internally,
the package will route metrics to either `armon/go-metrics` or `hashicorp/go-metrics`. This is achieved at a global level
within an application via the use of Go build tags.

**Build Tags**
* `armonmetrics` - Using this tag will cause metrics to be routed to `armon/go-metrics`
* `hashicorpmetrics` - Using this tag will cause all metrics to be routed to `hashicorp/go-metrics`

If no build tag is specified, the default behavior is to use `armon/go-metrics`. The overall migration path would be as follows:

1. Upgrade libraries using `armon/go-metrics` to consume `hashicorp/go-metrics/compat` instead.
2. Update library dependencies of applications that use `armon/go-metrics`.
* This doesn't need to be one big atomic update but can be slower due to the default behavior remaining unaltered.
* At this point all metrics will still be emitted to `armon/go-metrics`
3. Update the application to use `hashicorp/go-metrics`
* Replace all application imports of `github.com/armon/go-metrics` with `github.com/hashicorp/go-metrics`
* Libraries are unaltered at this stage.
* Instrument your build system to build with the `hashicorpmetrics` tag.

Your migration is effectively finished and your application is now exclusively using `hashicorp/go-metrics`. A future release of the library
will change the default behavior to use `hashicorp/go-metrics` instead of `armon/go-metrics`. At that point in time, any application that
needs more time before performing the migration must instrument their build system to include the `armonmetrics` tag. A subsequent release
after that will eventually remove the compatibility layer all together. The rough timeline for this will be mid-2025 for changing the default
behavior and then the end of 2025 for removal of the compatibility layer.


Examples
--------

Expand Down
129 changes: 129 additions & 0 deletions compat/armon.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
//go:build armonmetrics || ignore || !hashicorpmetrics
// +build armonmetrics ignore !hashicorpmetrics

package metrics

import (
"io"
"net/url"
"syscall"
"time"

"github.com/armon/go-metrics"
)

const (
// DefaultSignal is used with DefaultInmemSignal
DefaultSignal = metrics.DefaultSignal
)

func AddSample(key []string, val float32) {
metrics.AddSample(key, val)
}
func AddSampleWithLabels(key []string, val float32, labels []Label) {
metrics.AddSampleWithLabels(key, val, labels)
}
func EmitKey(key []string, val float32) {
metrics.EmitKey(key, val)
}
func IncrCounter(key []string, val float32) {
metrics.IncrCounter(key, val)
}
func IncrCounterWithLabels(key []string, val float32, labels []Label) {
metrics.IncrCounterWithLabels(key, val, labels)
}
func MeasureSince(key []string, start time.Time) {
metrics.MeasureSince(key, start)
}
func MeasureSinceWithLabels(key []string, start time.Time, labels []Label) {
metrics.MeasureSinceWithLabels(key, start, labels)
}
func SetGauge(key []string, val float32) {
metrics.SetGauge(key, val)
}
func SetGaugeWithLabels(key []string, val float32, labels []Label) {
metrics.SetGaugeWithLabels(key, val, labels)
}
func Shutdown() {
metrics.Shutdown()
}
func UpdateFilter(allow, block []string) {
metrics.UpdateFilter(allow, block)
}
func UpdateFilterAndLabels(allow, block, allowedLabels, blockedLabels []string) {
metrics.UpdateFilterAndLabels(allow, block, allowedLabels, blockedLabels)
}

type AggregateSample = metrics.AggregateSample
type BlackholeSink = metrics.BlackholeSink
type Config = metrics.Config
type Encoder = metrics.Encoder
type FanoutSink = metrics.FanoutSink
type GaugeValue = metrics.GaugeValue
type InmemSignal = metrics.InmemSignal
type InmemSink = metrics.InmemSink
type IntervalMetrics = metrics.IntervalMetrics
type Label = metrics.Label
type MetricSink = metrics.MetricSink
type Metrics = metrics.Metrics
type MetricsSummary = metrics.MetricsSummary
type PointValue = metrics.PointValue
type SampledValue = metrics.SampledValue
type ShutdownSink = metrics.ShutdownSink
type StatsdSink = metrics.StatsdSink
type StatsiteSink = metrics.StatsiteSink

func DefaultConfig(serviceName string) *Config {
return metrics.DefaultConfig(serviceName)
}

func DefaultInmemSignal(inmem *InmemSink) *InmemSignal {
return metrics.DefaultInmemSignal(inmem)
}
func NewInmemSignal(inmem *InmemSink, sig syscall.Signal, w io.Writer) *InmemSignal {
return metrics.NewInmemSignal(inmem, sig, w)
}

func NewInmemSink(interval, retain time.Duration) *InmemSink {
return metrics.NewInmemSink(interval, retain)
}

func NewIntervalMetrics(intv time.Time) *IntervalMetrics {
return metrics.NewIntervalMetrics(intv)
}

func NewInmemSinkFromURL(u *url.URL) (MetricSink, error) {
return metrics.NewInmemSinkFromURL(u)
}

func NewMetricSinkFromURL(urlStr string) (MetricSink, error) {
return metrics.NewMetricSinkFromURL(urlStr)
}

func NewStatsdSinkFromURL(u *url.URL) (MetricSink, error) {
return metrics.NewStatsdSinkFromURL(u)
}

func NewStatsiteSinkFromURL(u *url.URL) (MetricSink, error) {
return metrics.NewStatsiteSinkFromURL(u)
}

func Default() *Metrics {
return metrics.Default()
}

func New(conf *Config, sink MetricSink) (*Metrics, error) {
return metrics.New(conf, sink)
}

func NewGlobal(conf *Config, sink MetricSink) (*Metrics, error) {
return metrics.NewGlobal(conf, sink)
}

func NewStatsdSink(addr string) (*StatsdSink, error) {
return metrics.NewStatsdSink(addr)
}

func NewStatsiteSink(addr string) (*StatsiteSink, error) {
return metrics.NewStatsiteSink(addr)
}
15 changes: 15 additions & 0 deletions compat/circonus/armon.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//go:build armonmetrics || ignore || !hashicorpmetrics
// +build armonmetrics ignore !hashicorpmetrics

package circonus

import (
"github.com/armon/go-metrics/circonus"
)

type CirconusSink = circonus.CirconusSink
type Config = circonus.Config

func NewCirconusSink(cc *Config) (*CirconusSink, error) {
return circonus.NewCirconusSink(cc)
}
15 changes: 15 additions & 0 deletions compat/circonus/hashicorp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//go:build hashicorpmetrics
// +build hashicorpmetrics

package circonus

import (
"github.com/hashicorp/go-metrics/circonus"
)

type CirconusSink = circonus.CirconusSink
type Config = circonus.Config

func NewCirconusSink(cc *Config) (*CirconusSink, error) {
return circonus.NewCirconusSink(cc)
}
14 changes: 14 additions & 0 deletions compat/datadog/armon.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//go:build armonmetrics || ignore || !hashicorpmetrics
// +build armonmetrics ignore !hashicorpmetrics

package datadog

import (
"github.com/armon/go-metrics/datadog"
)

type DogStatsdSink = datadog.DogStatsdSink

func NewDogStatsdSink(addr string, hostName string) (*DogStatsdSink, error) {
return datadog.NewDogStatsdSink(addr, hostName)
}
14 changes: 14 additions & 0 deletions compat/datadog/hashicorp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//go:build hashicorpmetrics
// +build hashicorpmetrics

package datadog

import (
"github.com/hashicorp/go-metrics/datadog"
)

type DogStatsdSink = datadog.DogStatsdSink

func NewDogStatsdSink(addr string, hostName string) (*DogStatsdSink, error) {
return datadog.NewDogStatsdSink(addr, hostName)
}
129 changes: 129 additions & 0 deletions compat/hashicorp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
//go:build hashicorpmetrics
// +build hashicorpmetrics

package metrics

import (
"io"
"net/url"
"syscall"
"time"

"github.com/hashicorp/go-metrics"
)

const (
// DefaultSignal is used with DefaultInmemSignal
DefaultSignal = metrics.DefaultSignal
)

func AddSample(key []string, val float32) {
metrics.AddSample(key, val)
}
func AddSampleWithLabels(key []string, val float32, labels []Label) {
metrics.AddSampleWithLabels(key, val, labels)
}
func EmitKey(key []string, val float32) {
metrics.EmitKey(key, val)
}
func IncrCounter(key []string, val float32) {
metrics.IncrCounter(key, val)
}
func IncrCounterWithLabels(key []string, val float32, labels []Label) {
metrics.IncrCounterWithLabels(key, val, labels)
}
func MeasureSince(key []string, start time.Time) {
metrics.MeasureSince(key, start)
}
func MeasureSinceWithLabels(key []string, start time.Time, labels []Label) {
metrics.MeasureSinceWithLabels(key, start, labels)
}
func SetGauge(key []string, val float32) {
metrics.SetGauge(key, val)
}
func SetGaugeWithLabels(key []string, val float32, labels []Label) {
metrics.SetGaugeWithLabels(key, val, labels)
}
func Shutdown() {
metrics.Shutdown()
}
func UpdateFilter(allow, block []string) {
metrics.UpdateFilter(allow, block)
}
func UpdateFilterAndLabels(allow, block, allowedLabels, blockedLabels []string) {
metrics.UpdateFilterAndLabels(allow, block, allowedLabels, blockedLabels)
}

type AggregateSample = metrics.AggregateSample
type BlackholeSink = metrics.BlackholeSink
type Config = metrics.Config
type Encoder = metrics.Encoder
type FanoutSink = metrics.FanoutSink
type GaugeValue = metrics.GaugeValue
type InmemSignal = metrics.InmemSignal
type InmemSink = metrics.InmemSink
type IntervalMetrics = metrics.IntervalMetrics
type Label = metrics.Label
type MetricSink = metrics.MetricSink
type Metrics = metrics.Metrics
type MetricsSummary = metrics.MetricsSummary
type PointValue = metrics.PointValue
type SampledValue = metrics.SampledValue
type ShutdownSink = metrics.ShutdownSink
type StatsdSink = metrics.StatsdSink
type StatsiteSink = metrics.StatsiteSink

func DefaultConfig(serviceName string) *Config {
return metrics.DefaultConfig(serviceName)
}

func DefaultInmemSignal(inmem *InmemSink) *InmemSignal {
return metrics.DefaultInmemSignal(inmem)
}
func NewInmemSignal(inmem *InmemSink, sig syscall.Signal, w io.Writer) *InmemSignal {
return metrics.NewInmemSignal(inmem, sig, w)
}

func NewInmemSink(interval, retain time.Duration) *InmemSink {
return metrics.NewInmemSink(interval, retain)
}

func NewIntervalMetrics(intv time.Time) *IntervalMetrics {
return metrics.NewIntervalMetrics(intv)
}

func NewInmemSinkFromURL(u *url.URL) (MetricSink, error) {
return metrics.NewInmemSinkFromURL(u)
}

func NewMetricSinkFromURL(urlStr string) (MetricSink, error) {
return metrics.NewMetricSinkFromURL(urlStr)
}

func NewStatsdSinkFromURL(u *url.URL) (MetricSink, error) {
return metrics.NewStatsdSinkFromURL(u)
}

func NewStatsiteSinkFromURL(u *url.URL) (MetricSink, error) {
return metrics.NewStatsiteSinkFromURL(u)
}

func Default() *Metrics {
return metrics.Default()
}

func New(conf *Config, sink MetricSink) (*Metrics, error) {
return metrics.New(conf, sink)
}

func NewGlobal(conf *Config, sink MetricSink) (*Metrics, error) {
return metrics.NewGlobal(conf, sink)
}

func NewStatsdSink(addr string) (*StatsdSink, error) {
return metrics.NewStatsdSink(addr)
}

func NewStatsiteSink(addr string) (*StatsiteSink, error) {
return metrics.NewStatsiteSink(addr)
}
Loading