-
Notifications
You must be signed in to change notification settings - Fork 819
uplift: Add combined metrics package from evm repositories #4135
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
Merged
Merged
Changes from all commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
b13eebf
add combined metrics package
JonathanOppenheimer ff47252
support GaugeInfo from subnet-evm
JonathanOppenheimer 45f25b0
lint update
JonathanOppenheimer b1d230a
Merge branch 'master' into uplift-evm-metrics
JonathanOppenheimer 846aa13
Merge branch 'master' into uplift-evm-metrics
JonathanOppenheimer 9a08a58
Update vms/evm/metrics/metricstest/metrics.go
JonathanOppenheimer d5e51fe
Update vms/evm/metrics/metricstest/metrics.go
JonathanOppenheimer c162667
Update vms/evm/metrics/prometheus/enabled_test.go
JonathanOppenheimer 1ce92b9
Update vms/evm/metrics/prometheus/prometheus_test.go
JonathanOppenheimer b82fcce
Update vms/evm/metrics/prometheus/interfaces.go
JonathanOppenheimer 32038aa
Update vms/evm/metrics/prometheus/interfaces.go
JonathanOppenheimer 6e7fced
Update vms/evm/metrics/prometheus/prometheus.go
JonathanOppenheimer 7179722
Update vms/evm/metrics/prometheus/prometheus_test.go
JonathanOppenheimer 6af4cd1
Update vms/evm/metrics/prometheus/prometheus_test.go
JonathanOppenheimer 739310c
Maintain initial metrics.Enabled value
JonathanOppenheimer c90b0d6
Prometheus variable organization
JonathanOppenheimer c6b8a18
Refactor vms/evm/metrics/prometheus/prometheus_test.go
JonathanOppenheimer 0999f21
Accumulate errors in Gather()
JonathanOppenheimer 8af978f
Proper import order
JonathanOppenheimer 83290c2
Add continue to swtich case
JonathanOppenheimer cff5859
Merge branch 'master' into uplift-evm-metrics
JonathanOppenheimer 4ccc7ec
Merge branch 'master' into uplift-evm-metrics
JonathanOppenheimer 19d4194
Update vms/evm/metrics/metricstest/metrics.go
JonathanOppenheimer 8980eb1
Update vms/evm/metrics/prometheus/prometheus.go
JonathanOppenheimer 2e5d18a
Update vms/evm/metrics/prometheus/prometheus.go
JonathanOppenheimer 149e8c2
Update vms/evm/metrics/prometheus/prometheus.go
JonathanOppenheimer 36b98e9
Fix TestGatherer_Gather test case
JonathanOppenheimer 0a4e60a
lint error
JonathanOppenheimer 2ce2d42
Address final nits (#4148)
StephenButtolph 22ea450
Remove weird edge case
StephenButtolph File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| // Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved. | ||
| // See the file LICENSE for licensing terms. | ||
|
|
||
| package metricstest | ||
|
|
||
| import ( | ||
| "sync" | ||
| "testing" | ||
|
|
||
| "github.com/ava-labs/libevm/metrics" | ||
| ) | ||
|
|
||
| var metricsLock sync.Mutex | ||
|
|
||
| // WithMetrics enables [metrics.Enabled] for the test and prevents any other | ||
| // tests with metrics from running concurrently. | ||
| // | ||
| // [metrics.Enabled] is restored to its original value during testing cleanup. | ||
| func WithMetrics(t testing.TB) { | ||
| metricsLock.Lock() | ||
| initialValue := metrics.Enabled | ||
| metrics.Enabled = true | ||
| t.Cleanup(func() { | ||
| metrics.Enabled = initialValue | ||
| metricsLock.Unlock() | ||
| }) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| // Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved. | ||
| // See the file LICENSE for licensing terms. | ||
|
|
||
| package prometheus_test | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "github.com/ava-labs/libevm/metrics" | ||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| // This test assumes that there are no imported packages that might change the | ||
| // default value of [metrics.Enabled]. It is therefore in package | ||
| // `prometheus_test` in case any other tests modify the variable. If any imports | ||
| // here or in the implementation do actually do so then this test may have false | ||
| // negatives. | ||
| func TestMetricsEnabledByDefault(t *testing.T) { | ||
| require.True(t, metrics.Enabled, "libevm/metrics.Enabled") | ||
| require.IsType(t, (*metrics.StandardCounter)(nil), metrics.NewCounter(), "metrics.NewCounter() returned wrong type") | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| // Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved. | ||
| // See the file LICENSE for licensing terms. | ||
|
|
||
| package prometheus | ||
|
|
||
| import "github.com/ava-labs/libevm/metrics" | ||
|
|
||
| var _ Registry = metrics.Registry(nil) | ||
|
|
||
JonathanOppenheimer marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| type Registry interface { | ||
| // Call the given function for each registered metric. | ||
| Each(func(name string, metric any)) | ||
| // Get the metric by the given name or nil if none is registered. | ||
| Get(name string) any | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,198 @@ | ||
| // Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved. | ||
| // See the file LICENSE for licensing terms. | ||
|
|
||
| package prometheus | ||
|
|
||
| import ( | ||
| "errors" | ||
| "fmt" | ||
| "slices" | ||
| "strings" | ||
|
|
||
| "github.com/ava-labs/libevm/metrics" | ||
| "github.com/prometheus/client_golang/prometheus" | ||
|
|
||
| dto "github.com/prometheus/client_model/go" | ||
| ) | ||
|
|
||
| var ( | ||
| _ prometheus.Gatherer = (*Gatherer)(nil) | ||
|
|
||
| errMetricSkip = errors.New("metric skipped") | ||
| errMetricTypeNotSupported = errors.New("metric type is not supported") | ||
| quantiles = []float64{.5, .75, .95, .99, .999, .9999} | ||
| pvShortPercent = []float64{50, 95, 99} | ||
| ) | ||
|
|
||
| // Gatherer implements the [prometheus.Gatherer] interface by gathering all | ||
| // metrics from a [Registry]. | ||
| type Gatherer struct { | ||
| registry Registry | ||
| } | ||
|
|
||
| // Gather gathers metrics from the registry and converts them to | ||
| // a slice of metric families. | ||
| func (g *Gatherer) Gather() ([]*dto.MetricFamily, error) { | ||
| // Gather and pre-sort the metrics to avoid random listings | ||
| var names []string | ||
| g.registry.Each(func(name string, _ any) { | ||
| names = append(names, name) | ||
| }) | ||
| slices.Sort(names) | ||
|
|
||
| var ( | ||
| mfs = make([]*dto.MetricFamily, 0, len(names)) | ||
| errs []error | ||
| ) | ||
| for _, name := range names { | ||
| mf, err := metricFamily(g.registry, name) | ||
| switch { | ||
| case err == nil: | ||
| mfs = append(mfs, mf) | ||
| case !errors.Is(err, errMetricSkip): | ||
| errs = append(errs, err) | ||
| } | ||
| } | ||
|
|
||
| return mfs, errors.Join(errs...) | ||
| } | ||
|
|
||
| // NewGatherer returns a [Gatherer] using the given registry. | ||
| func NewGatherer(registry Registry) *Gatherer { | ||
| return &Gatherer{ | ||
| registry: registry, | ||
| } | ||
| } | ||
|
|
||
| func metricFamily(registry Registry, name string) (mf *dto.MetricFamily, err error) { | ||
| metric := registry.Get(name) | ||
| name = strings.ReplaceAll(name, "/", "_") | ||
|
|
||
| switch m := metric.(type) { | ||
| case metrics.NilCounter, metrics.NilCounterFloat64, metrics.NilEWMA, | ||
| metrics.NilGauge, metrics.NilGaugeFloat64, metrics.NilGaugeInfo, | ||
| metrics.NilHealthcheck, metrics.NilHistogram, metrics.NilMeter, | ||
| metrics.NilResettingTimer, metrics.NilSample, metrics.NilTimer: | ||
| return nil, fmt.Errorf("%w: %q metric is nil", errMetricSkip, name) | ||
| case metrics.Counter: | ||
| return &dto.MetricFamily{ | ||
| Name: &name, | ||
| Type: dto.MetricType_COUNTER.Enum(), | ||
| Metric: []*dto.Metric{{ | ||
| Counter: &dto.Counter{ | ||
| Value: ptrTo(float64(m.Snapshot().Count())), | ||
| }, | ||
| }}, | ||
| }, nil | ||
| case metrics.CounterFloat64: | ||
| return &dto.MetricFamily{ | ||
| Name: &name, | ||
| Type: dto.MetricType_COUNTER.Enum(), | ||
| Metric: []*dto.Metric{{ | ||
| Counter: &dto.Counter{ | ||
| Value: ptrTo(m.Snapshot().Count()), | ||
| }, | ||
| }}, | ||
| }, nil | ||
| case metrics.Gauge: | ||
| return &dto.MetricFamily{ | ||
| Name: &name, | ||
| Type: dto.MetricType_GAUGE.Enum(), | ||
| Metric: []*dto.Metric{{ | ||
| Gauge: &dto.Gauge{ | ||
| Value: ptrTo(float64(m.Snapshot().Value())), | ||
| }, | ||
| }}, | ||
| }, nil | ||
| case metrics.GaugeFloat64: | ||
| return &dto.MetricFamily{ | ||
| Name: &name, | ||
| Type: dto.MetricType_GAUGE.Enum(), | ||
| Metric: []*dto.Metric{{ | ||
| Gauge: &dto.Gauge{ | ||
| Value: ptrTo(m.Snapshot().Value()), | ||
| }, | ||
| }}, | ||
| }, nil | ||
| case metrics.GaugeInfo: | ||
| return nil, fmt.Errorf("%w: %q is a %T", errMetricSkip, name, m) | ||
| case metrics.Histogram: | ||
| snapshot := m.Snapshot() | ||
| thresholds := snapshot.Percentiles(quantiles) | ||
| dtoQuantiles := make([]*dto.Quantile, len(quantiles)) | ||
| for i := range thresholds { | ||
| dtoQuantiles[i] = &dto.Quantile{ | ||
| Quantile: ptrTo(quantiles[i]), | ||
| Value: ptrTo(thresholds[i]), | ||
| } | ||
| } | ||
| return &dto.MetricFamily{ | ||
| Name: &name, | ||
| Type: dto.MetricType_SUMMARY.Enum(), | ||
| Metric: []*dto.Metric{{ | ||
| Summary: &dto.Summary{ | ||
| SampleCount: ptrTo(uint64(snapshot.Count())), | ||
| SampleSum: ptrTo(float64(snapshot.Sum())), | ||
| Quantile: dtoQuantiles, | ||
| }, | ||
| }}, | ||
| }, nil | ||
| case metrics.Meter: | ||
| return &dto.MetricFamily{ | ||
| Name: &name, | ||
| Type: dto.MetricType_GAUGE.Enum(), | ||
| Metric: []*dto.Metric{{ | ||
| Gauge: &dto.Gauge{ | ||
| Value: ptrTo(float64(m.Snapshot().Count())), | ||
| }, | ||
| }}, | ||
| }, nil | ||
| case metrics.Timer: | ||
| snapshot := m.Snapshot() | ||
| thresholds := snapshot.Percentiles(quantiles) | ||
| dtoQuantiles := make([]*dto.Quantile, len(quantiles)) | ||
| for i := range thresholds { | ||
| dtoQuantiles[i] = &dto.Quantile{ | ||
| Quantile: ptrTo(quantiles[i]), | ||
| Value: ptrTo(thresholds[i]), | ||
| } | ||
| } | ||
| return &dto.MetricFamily{ | ||
| Name: &name, | ||
| Type: dto.MetricType_SUMMARY.Enum(), | ||
| Metric: []*dto.Metric{{ | ||
| Summary: &dto.Summary{ | ||
| SampleCount: ptrTo(uint64(snapshot.Count())), | ||
| SampleSum: ptrTo(float64(snapshot.Sum())), | ||
| Quantile: dtoQuantiles, | ||
| }, | ||
| }}, | ||
| }, nil | ||
| case metrics.ResettingTimer: | ||
| snapshot := m.Snapshot() | ||
| thresholds := snapshot.Percentiles(pvShortPercent) | ||
| dtoQuantiles := make([]*dto.Quantile, len(pvShortPercent)) | ||
| for i := range pvShortPercent { | ||
| dtoQuantiles[i] = &dto.Quantile{ | ||
| Quantile: ptrTo(pvShortPercent[i]), | ||
| Value: ptrTo(thresholds[i]), | ||
| } | ||
| } | ||
| count := snapshot.Count() | ||
| return &dto.MetricFamily{ | ||
| Name: &name, | ||
| Type: dto.MetricType_SUMMARY.Enum(), | ||
| Metric: []*dto.Metric{{ | ||
| Summary: &dto.Summary{ | ||
| SampleCount: ptrTo(uint64(count)), | ||
| SampleSum: ptrTo(float64(count) * snapshot.Mean()), | ||
| Quantile: dtoQuantiles, | ||
| }, | ||
| }}, | ||
| }, nil | ||
| default: | ||
| return nil, fmt.Errorf("%w: metric %q type %T", errMetricTypeNotSupported, name, metric) | ||
| } | ||
| } | ||
|
|
||
| func ptrTo[T any](x T) *T { return &x } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.