From 2fbe8cda7851b070baf1971af8fe69c2b0c399c3 Mon Sep 17 00:00:00 2001 From: Francesco Casula Date: Mon, 3 Jul 2023 11:46:20 +0200 Subject: [PATCH] chore: otel stable metric API update v1.16.0 / v0.39.0 (#72) --- go.mod | 24 +++++------ go.sum | 47 +++++++++++----------- stats/internal/otel/otel.go | 3 +- stats/internal/otel/otel_test.go | 32 +++++++-------- stats/internal/otel/prometheus/config.go | 20 +++++++++ stats/internal/otel/prometheus/exporter.go | 17 +++++--- stats/otel.go | 46 +++++++-------------- stats/otel_measurement.go | 16 ++++---- stats/otel_test.go | 14 +++---- stats/stats.go | 5 ++- 10 files changed, 117 insertions(+), 107 deletions(-) diff --git a/go.mod b/go.mod index 6f80e278..1bbf4703 100644 --- a/go.mod +++ b/go.mod @@ -24,15 +24,15 @@ require ( github.com/shirou/gopsutil/v3 v3.23.4 github.com/spf13/cast v1.5.0 github.com/spf13/viper v1.15.0 - github.com/stretchr/testify v1.8.2 + github.com/stretchr/testify v1.8.3 github.com/throttled/throttled/v2 v2.11.0 github.com/zenizh/go-capturer v0.0.0-20211219060012-52ea6c8fed04 - go.opentelemetry.io/otel v1.14.0 - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.37.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0 - go.opentelemetry.io/otel/metric v0.37.0 - go.opentelemetry.io/otel/sdk v1.14.0 - go.opentelemetry.io/otel/sdk/metric v0.37.0 + go.opentelemetry.io/otel v1.16.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.39.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 + go.opentelemetry.io/otel/metric v1.16.0 + go.opentelemetry.io/otel/sdk v1.16.0 + go.opentelemetry.io/otel/sdk/metric v0.39.0 go.uber.org/zap v1.24.0 golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0 golang.org/x/oauth2 v0.8.0 @@ -62,7 +62,7 @@ require ( github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/gogo/protobuf v1.3.2 // indirect @@ -113,10 +113,10 @@ require ( github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.37.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 // indirect - go.opentelemetry.io/otel/trace v1.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 // indirect + go.opentelemetry.io/otel/trace v1.16.0 // indirect go.opentelemetry.io/proto/otlp v0.19.0 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.9.0 // indirect diff --git a/go.sum b/go.sum index 624e690d..3bdf79a5 100644 --- a/go.sum +++ b/go.sum @@ -144,8 +144,8 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= @@ -392,8 +392,9 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= @@ -431,26 +432,26 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/otel v0.14.0/go.mod h1:vH5xEuwy7Rts0GNtsCW3HYQoZDY+OmBJ6t1bFGGlxgw= -go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM= -go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 h1:/fXHZHGvro6MVqV34fJzDhi7sHGpX3Ej/Qjmfn003ho= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0/go.mod h1:UFG7EBMRdXyFstOwH028U0sVf+AvukSGhF0g8+dmNG8= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.37.0 h1:22J9c9mxNAZugv86zhwjBnER0DbO0VVpW9Oo/j3jBBQ= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.37.0/go.mod h1:QD8SSO9fgtBOvXYpcX5NXW+YnDJByTnh7a/9enQWFmw= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.37.0 h1:CI6DSdsSkJxX1rsfPSQ0SciKx6klhdDRBXqKb+FwXG8= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.37.0/go.mod h1:WLBYPrz8srktckhCjFaau4VHSfGaMuqoKSXwpzaiRZg= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 h1:TKf2uAs2ueguzLaxOCBXNpHxfO/aC7PAdDsSH0IbeRQ= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0/go.mod h1:HrbCVv40OOLTABmOn1ZWty6CHXkU8DK/Urc43tHug70= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0 h1:ap+y8RXX3Mu9apKVtOkM6WSFESLM8K3wNQyOU8sWHcc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0/go.mod h1:5w41DY6S9gZrbjuq6Y+753e96WfPha5IcsOSZTtullM= -go.opentelemetry.io/otel/metric v0.37.0 h1:pHDQuLQOZwYD+Km0eb657A25NaRzy0a+eLyKfDXedEs= -go.opentelemetry.io/otel/metric v0.37.0/go.mod h1:DmdaHfGt54iV6UKxsV9slj2bBRJcKC1B1uvDLIioc1s= -go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY= -go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM= -go.opentelemetry.io/otel/sdk/metric v0.37.0 h1:haYBBtZZxiI3ROwSmkZnI+d0+AVzBWeviuYQDeBWosU= -go.opentelemetry.io/otel/sdk/metric v0.37.0/go.mod h1:mO2WV1AZKKwhwHTV3AKOoIEb9LbUaENZDuGUQd+j4A0= -go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M= -go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= +go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= +go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 h1:t4ZwRPU+emrcvM2e9DHd0Fsf0JTPVcbfa/BhTDF03d0= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0/go.mod h1:vLarbg68dH2Wa77g71zmKQqlQ8+8Rq3GRG31uc0WcWI= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.39.0 h1:f6BwB2OACc3FCbYVznctQ9V6KK7Vq6CjmYXJ7DeSs4E= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.39.0/go.mod h1:UqL5mZ3qs6XYhDnZaW1Ps4upD+PX6LipH40AoeuIlwU= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.39.0 h1:rm+Fizi7lTM2UefJ1TO347fSRcwmIsUAaZmYmIGBRAo= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.39.0/go.mod h1:sWFbI3jJ+6JdjOVepA5blpv/TJ20Hw+26561iMbWcwU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 h1:cbsD4cUcviQGXdw8+bo5x2wazq10SKz8hEbtCRPcU78= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0/go.mod h1:JgXSGah17croqhJfhByOLVY719k1emAXC8MVhCIJlRs= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 h1:TVQp/bboR4mhZSav+MdgXB8FaRho1RC8UwVn3T0vjVc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0/go.mod h1:I33vtIe0sR96wfrUcilIzLoA3mLHhRmz9S9Te0S3gDo= +go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= +go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= +go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= +go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= +go.opentelemetry.io/otel/sdk/metric v0.39.0 h1:Kun8i1eYf48kHH83RucG93ffz0zGV1sh46FAScOTuDI= +go.opentelemetry.io/otel/sdk/metric v0.39.0/go.mod h1:piDIRgjcK7u0HCL5pCA4e74qpK/jk3NiUoAHATVAmiI= +go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= +go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= diff --git a/stats/internal/otel/otel.go b/stats/internal/otel/otel.go index c679011c..fff7345d 100644 --- a/stats/internal/otel/otel.go +++ b/stats/internal/otel/otel.go @@ -10,7 +10,6 @@ import ( "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" - "go.opentelemetry.io/otel/metric/global" "go.opentelemetry.io/otel/propagation" sdkmetric "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/resource" @@ -93,7 +92,7 @@ func (m *Manager) Setup( return nil, nil, err } if c.meterProviderConfig.global { - global.SetMeterProvider(m.mp) + otel.SetMeterProvider(m.mp) } } diff --git a/stats/internal/otel/otel_test.go b/stats/internal/otel/otel_test.go index 073d7c8f..6100c4c8 100644 --- a/stats/internal/otel/otel_test.go +++ b/stats/internal/otel/otel_test.go @@ -20,7 +20,7 @@ import ( "github.com/stretchr/testify/require" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/metric/global" + "go.opentelemetry.io/otel/metric" sdkmetric "go.opentelemetry.io/otel/sdk/metric" "github.com/rudderlabs/rudder-go-kit/httputil" @@ -38,7 +38,7 @@ var ( {Name: ptr("service_version"), Value: ptr("v1.2.3")}, {Name: ptr("telemetry_sdk_language"), Value: ptr("go")}, {Name: ptr("telemetry_sdk_name"), Value: ptr("opentelemetry")}, - {Name: ptr("telemetry_sdk_version"), Value: ptr("1.14.0")}, + {Name: ptr("telemetry_sdk_version"), Value: ptr("1.16.0")}, {Name: ptr("instanceName"), Value: ptr("my-instance-id")}, } globalGRPCDefaultAttrs = append(globalDefaultAttrs, @@ -83,7 +83,7 @@ func TestMetrics(t *testing.T) { require.NoError(t, err) t.Cleanup(func() { require.NoError(t, om.Shutdown(context.Background())) }) require.NotEqual(t, tp, otel.GetTracerProvider()) - require.NotEqual(t, mp, global.MeterProvider()) + require.NotEqual(t, mp, otel.GetMeterProvider()) metricsEndpoint := fmt.Sprintf("http://localhost:%d/metrics", dt.GetHostPort(t, metricsPort, container)) return mp, metricsEndpoint @@ -112,7 +112,7 @@ func TestMetrics(t *testing.T) { require.NoError(t, err) t.Cleanup(func() { require.NoError(t, om.Shutdown(context.Background())) }) require.Nil(t, tp) - require.NotEqual(t, mp, global.MeterProvider()) + require.NotEqual(t, mp, otel.GetMeterProvider()) ts := httptest.NewServer(promhttp.InstrumentMetricHandler( registry, promhttp.HandlerFor(registry, promhttp.HandlerOpts{}), @@ -131,7 +131,7 @@ func TestMetrics(t *testing.T) { // foo counter counter, err := m.Int64Counter("foo") require.NoError(t, err) - counter.Add(ctx, 1, attribute.String("hello", "world")) + counter.Add(ctx, 1, metric.WithAttributes(attribute.String("hello", "world"))) // bar counter counter, err = m.Int64Counter("bar") require.NoError(t, err) @@ -139,11 +139,11 @@ func TestMetrics(t *testing.T) { // baz histogram h1, err := m.Int64Histogram("baz") require.NoError(t, err) - h1.Record(ctx, 20, attribute.String("a", "b")) + h1.Record(ctx, 20, metric.WithAttributes(attribute.String("a", "b"))) // qux histogram h2, err := m.Int64Histogram("qux") require.NoError(t, err) - h2.Record(ctx, 2, attribute.String("c", "d")) + h2.Record(ctx, 2, metric.WithAttributes(attribute.String("c", "d"))) // Run assertions metrics := requireMetrics(t, metricsEndpoint, "foo", "bar", "baz", "qux") @@ -232,7 +232,7 @@ func TestHistogramBuckets(t *testing.T) { ) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, om.Shutdown(context.Background())) }) - require.NotEqual(t, mp, global.MeterProvider()) + require.NotEqual(t, mp, otel.GetMeterProvider()) metricsEndpoint := fmt.Sprintf("http://localhost:%d/metrics", dt.GetHostPort(t, metricsPort, container)) return mp, metricsEndpoint @@ -257,7 +257,7 @@ func TestHistogramBuckets(t *testing.T) { require.NoError(t, err) t.Cleanup(func() { require.NoError(t, om.Shutdown(context.Background())) }) require.Nil(t, tp) - require.NotEqual(t, mp, global.MeterProvider()) + require.NotEqual(t, mp, otel.GetMeterProvider()) ts := httptest.NewServer(promhttp.InstrumentMetricHandler( registry, promhttp.HandlerFor(registry, promhttp.HandlerOpts{}), @@ -279,12 +279,12 @@ func TestHistogramBuckets(t *testing.T) { // foo histogram on meter-1 h, err := mp.Meter("meter-1").Int64Histogram("foo") require.NoError(t, err) - h.Record(ctx, 20, attribute.String("a", "b")) + h.Record(ctx, 20, metric.WithAttributes(attribute.String("a", "b"))) // bar histogram on meter-2 h, err = mp.Meter("meter-2").Int64Histogram("bar") require.NoError(t, err) - h.Record(ctx, 30, attribute.String("c", "d")) + h.Record(ctx, 30, metric.WithAttributes(attribute.String("c", "d"))) metrics := requireMetrics(t, metricsEndpoint, "foo", "bar") @@ -331,17 +331,17 @@ func TestHistogramBuckets(t *testing.T) { // foo histogram h, err := mp.Meter("meter-1").Int64Histogram("foo") require.NoError(t, err) - h.Record(ctx, 20, attribute.String("a", "b")) + h.Record(ctx, 20, metric.WithAttributes(attribute.String("a", "b"))) // bar histogram h, err = mp.Meter("meter-1").Int64Histogram("bar") require.NoError(t, err) - h.Record(ctx, 50, attribute.String("c", "d")) + h.Record(ctx, 50, metric.WithAttributes(attribute.String("c", "d"))) // baz histogram h, err = mp.Meter("meter-1").Int64Histogram("baz") require.NoError(t, err) - h.Record(ctx, 80, attribute.String("e", "f")) + h.Record(ctx, 80, metric.WithAttributes(attribute.String("e", "f"))) metrics := requireMetrics(t, metricsEndpoint, "foo", "bar", "baz") @@ -433,7 +433,7 @@ func TestCollectorGlobals(t *testing.T) { require.NoError(t, err) t.Cleanup(func() { require.NoError(t, om.Shutdown(context.Background())) }) require.Equal(t, tp, otel.GetTracerProvider()) - require.Equal(t, mp, global.MeterProvider()) + require.Equal(t, mp, otel.GetMeterProvider()) } func TestNonBlockingConnection(t *testing.T) { @@ -472,7 +472,7 @@ func TestNonBlockingConnection(t *testing.T) { require.NoError(t, err) // this counter will not be lost even though the container isn't even started. see MaxElapsedTime. - fooCounter.Add(ctx, 123, attribute.String("hello", "world")) + fooCounter.Add(ctx, 123, metric.WithAttributes(attribute.String("hello", "world"))) cwd, err := os.Getwd() require.NoError(t, err) diff --git a/stats/internal/otel/prometheus/config.go b/stats/internal/otel/prometheus/config.go index e95c9b08..0533ff40 100644 --- a/stats/internal/otel/prometheus/config.go +++ b/stats/internal/otel/prometheus/config.go @@ -1,6 +1,8 @@ package prometheus import ( + "strings" + "github.com/prometheus/client_golang/prometheus" "go.opentelemetry.io/otel/sdk/metric" ) @@ -16,6 +18,7 @@ type config struct { disableTargetInfo bool withoutUnits bool aggregation metric.AggregationSelector + namespace string logger logger } @@ -101,6 +104,23 @@ func WithoutUnits() Option { }) } +// WithNamespace configures the Exporter to prefix metric with the given namespace. +// Metadata metrics such as target_info and otel_scope_info are not prefixed since these +// have special behavior based on their name. +func WithNamespace(ns string) Option { + return optionFunc(func(cfg config) config { + ns = sanitizeName(ns) + if !strings.HasSuffix(ns, "_") { + // namespace and metric names should be separated with an underscore, + // adds a trailing underscore if there is not one already. + ns = ns + "_" + } + + cfg.namespace = ns + return cfg + }) +} + // WithLogger enables the logger func WithLogger(l logger) Option { return optionFunc(func(cfg config) config { diff --git a/stats/internal/otel/prometheus/exporter.go b/stats/internal/otel/prometheus/exporter.go index ba401b0b..c78994e9 100644 --- a/stats/internal/otel/prometheus/exporter.go +++ b/stats/internal/otel/prometheus/exporter.go @@ -64,6 +64,7 @@ type collector struct { createTargetInfoOnce sync.Once scopeInfos map[instrumentation.Scope]prometheus.Metric metricFamilies map[string]*dto.MetricFamily + namespace string } // New returns a Prometheus Exporter. @@ -81,6 +82,7 @@ func New(opts ...Option) (*Exporter, error) { withoutUnits: cfg.withoutUnits, scopeInfos: make(map[instrumentation.Scope]prometheus.Metric), metricFamilies: make(map[string]*dto.MetricFamily), + namespace: cfg.namespace, } if err := cfg.registerer.Register(collector); err != nil { @@ -135,7 +137,9 @@ func (c *collector) Collect(ch chan<- prometheus.Metric) { for _, scopeMetrics := range metrics.ScopeMetrics { for _, m := range scopeMetrics.Metrics { switch v := m.Data.(type) { - case metricdata.Histogram: + case metricdata.Histogram[int64]: + addHistogramMetric(ch, v, m, scopeKeys, scopeValues, c.getName(m), c.metricFamilies, c.logger) + case metricdata.Histogram[float64]: addHistogramMetric(ch, v, m, scopeKeys, scopeValues, c.getName(m), c.metricFamilies, c.logger) case metricdata.Sum[int64]: addSumMetric(ch, v, m, scopeKeys, scopeValues, c.getName(m), c.metricFamilies, c.logger) @@ -150,8 +154,8 @@ func (c *collector) Collect(ch chan<- prometheus.Metric) { } } -func addHistogramMetric( - ch chan<- prometheus.Metric, histogram metricdata.Histogram, m metricdata.Metrics, +func addHistogramMetric[N int64 | float64]( + ch chan<- prometheus.Metric, histogram metricdata.Histogram[N], m metricdata.Metrics, ks, vs []string, name string, mfs map[string]*dto.MetricFamily, l logger, ) { drop, help := validateMetrics(name, m.Description, dto.MetricType_HISTOGRAM.Enum(), mfs, l) @@ -173,7 +177,7 @@ func addHistogramMetric( cumulativeCount += dp.BucketCounts[i] buckets[bound] = cumulativeCount } - m, err := prometheus.NewConstHistogram(desc, dp.Count, dp.Sum, buckets, values...) + m, err := prometheus.NewConstHistogram(desc, dp.Count, float64(dp.Sum), buckets, values...) if err != nil { otel.Handle(err) continue @@ -294,9 +298,12 @@ var unitSuffixes = map[string]string{ "ms": "_milliseconds", } -// getName returns the sanitized name, including unit suffix. +// getName returns the sanitized name, prefixed with the namespace and suffixed with unit. func (c *collector) getName(m metricdata.Metrics) string { name := sanitizeName(m.Name) + if c.namespace != "" { + name = c.namespace + name + } if c.withoutUnits { return name } diff --git a/stats/otel.go b/stats/otel.go index 1f040cd5..46d3096c 100644 --- a/stats/otel.go +++ b/stats/otel.go @@ -15,7 +15,6 @@ import ( "github.com/spf13/cast" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" - "go.opentelemetry.io/otel/metric/instrument" "github.com/rudderlabs/rudder-go-kit/logger" "github.com/rudderlabs/rudder-go-kit/stats/internal/otel" @@ -32,13 +31,13 @@ type otelStats struct { resourceAttrs map[string]struct{} meter metric.Meter - counters map[string]instrument.Int64Counter + counters map[string]metric.Int64Counter countersMu sync.Mutex gauges map[string]*otelGauge gaugesMu sync.Mutex - timers map[string]instrument.Float64Histogram + timers map[string]metric.Float64Histogram timersMu sync.Mutex - histograms map[string]instrument.Float64Histogram + histograms map[string]metric.Float64Histogram histogramsMu sync.Mutex otelManager otel.Manager @@ -286,7 +285,9 @@ func (s *otelStats) getMeasurement(name, statType string, tags Tags) Measurement } } -func (s *otelStats) getGauge(meter metric.Meter, name string, attributes []attribute.KeyValue, tagsKey string) *otelGauge { +func (s *otelStats) getGauge( + meter metric.Meter, name string, attributes []attribute.KeyValue, tagsKey string, +) *otelGauge { var ( ok bool og *otelGauge @@ -313,7 +314,7 @@ func (s *otelStats) getGauge(meter metric.Meter, name string, attributes []attri }} _, err = meter.RegisterCallback(func(ctx context.Context, o metric.Observer) error { if value := og.getValue(); value != nil { - o.ObserveFloat64(g, cast.ToFloat64(value), og.attributes...) + o.ObserveFloat64(g, cast.ToFloat64(value), metric.WithAttributes(attributes...)) } return nil }, g) @@ -327,7 +328,7 @@ func (s *otelStats) getGauge(meter metric.Meter, name string, attributes []attri } func buildOTelInstrument[T any]( - meter metric.Meter, name string, m map[string]T, mu *sync.Mutex, opts ...instrument.Option, + meter metric.Meter, name string, m map[string]T, mu *sync.Mutex, ) T { var ( ok bool @@ -335,23 +336,21 @@ func buildOTelInstrument[T any]( ) mu.Lock() + defer mu.Unlock() if m == nil { m = make(map[string]T) } else { instr, ok = m[name] } - mu.Unlock() if !ok { var err error var value interface{} switch any(m).(type) { - case map[string]instrument.Int64Counter: - value, err = meter.Int64Counter(name, castOptions[instrument.Int64Option](opts...)...) - case map[string]instrument.Int64Histogram: - value, err = meter.Int64Histogram(name, castOptions[instrument.Int64Option](opts...)...) - case map[string]instrument.Float64Histogram: - value, err = meter.Float64Histogram(name, castOptions[instrument.Float64Option](opts...)...) + case map[string]metric.Int64Counter: + value, err = meter.Int64Counter(name) + case map[string]metric.Float64Histogram: + value, err = meter.Float64Histogram(name) default: panic(fmt.Errorf("unknown instrument type %T", instr)) } @@ -359,29 +358,12 @@ func buildOTelInstrument[T any]( panic(fmt.Errorf("failed to create instrument %T(%s): %w", instr, name, err)) } instr = value.(T) - - mu.Lock() // the meter constructors might take some time so let's not hold the lock while that happens - if _, ok := m[name]; !ok { - m[name] = instr - } else { - instr = m[name] - } - mu.Unlock() + m[name] = instr } return instr } -func castOptions[T any](opts ...instrument.Option) []T { - var co []T - for _, opt := range opts { - if o, ok := opt.(T); ok { - co = append(co, o) - } - } - return co -} - type otelStatsConfig struct { tracesEndpoint string tracingSamplingRate float64 diff --git a/stats/otel_measurement.go b/stats/otel_measurement.go index 89df7d38..b941db53 100644 --- a/stats/otel_measurement.go +++ b/stats/otel_measurement.go @@ -6,7 +6,7 @@ import ( "time" "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/metric/instrument" + "go.opentelemetry.io/otel/metric" ) // otelMeasurement is the statsd-specific implementation of Measurement @@ -19,19 +19,19 @@ type otelMeasurement struct { // otelCounter represents a counter stat type otelCounter struct { *otelMeasurement - counter instrument.Int64Counter + counter metric.Int64Counter } func (c *otelCounter) Count(n int) { if !c.disabled { - c.counter.Add(context.TODO(), int64(n), c.attributes...) + c.counter.Add(context.TODO(), int64(n), metric.WithAttributes(c.attributes...)) } } // Increment increases the stat by 1. Is the Equivalent of Count(1). Only applies to CountType stats func (c *otelCounter) Increment() { if !c.disabled { - c.counter.Add(context.TODO(), 1, c.attributes...) + c.counter.Add(context.TODO(), 1, metric.WithAttributes(c.attributes...)) } } @@ -60,7 +60,7 @@ func (g *otelGauge) getValue() interface{} { type otelTimer struct { *otelMeasurement now func() time.Time - timer instrument.Float64Histogram + timer metric.Float64Histogram } // Since sends the time elapsed since duration start. Only applies to TimerType stats @@ -73,7 +73,7 @@ func (t *otelTimer) Since(start time.Time) { // SendTiming sends a timing for this stat. Only applies to TimerType stats func (t *otelTimer) SendTiming(duration time.Duration) { if !t.disabled { - t.timer.Record(context.TODO(), duration.Seconds(), t.attributes...) + t.timer.Record(context.TODO(), duration.Seconds(), metric.WithAttributes(t.attributes...)) } } @@ -98,12 +98,12 @@ func (t *otelTimer) RecordDuration() func() { // otelHistogram represents a histogram stat type otelHistogram struct { *otelMeasurement - histogram instrument.Float64Histogram + histogram metric.Float64Histogram } // Observe sends an observation func (h *otelHistogram) Observe(value float64) { if !h.disabled { - h.histogram.Record(context.TODO(), value, h.attributes...) + h.histogram.Record(context.TODO(), value, metric.WithAttributes(h.attributes...)) } } diff --git a/stats/otel_test.go b/stats/otel_test.go index bbf318ae..23f5013a 100644 --- a/stats/otel_test.go +++ b/stats/otel_test.go @@ -17,9 +17,9 @@ import ( "github.com/prometheus/client_golang/prometheus" promClient "github.com/prometheus/client_model/go" "github.com/stretchr/testify/require" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" otelMetric "go.opentelemetry.io/otel/metric" - "go.opentelemetry.io/otel/metric/global" sdkmetric "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/resource" @@ -44,11 +44,11 @@ var globalDefaultAttrs = []*promClient.LabelPair{ {Name: ptr("service_version"), Value: ptr("v1.2.3")}, {Name: ptr("telemetry_sdk_language"), Value: ptr("go")}, {Name: ptr("telemetry_sdk_name"), Value: ptr("opentelemetry")}, - {Name: ptr("telemetry_sdk_version"), Value: ptr("1.14.0")}, + {Name: ptr("telemetry_sdk_version"), Value: ptr("1.16.0")}, } func TestOTelMeasurementInvalidOperations(t *testing.T) { - s := &otelStats{meter: global.MeterProvider().Meter(t.Name())} + s := &otelStats{meter: otel.GetMeterProvider().Meter(t.Name())} t.Run("counter invalid operations", func(t *testing.T) { require.Panics(t, func() { @@ -177,7 +177,7 @@ func TestOTelMeasurementOperations(t *testing.T) { r, m := newReaderWithMeter(t) s := &otelStats{meter: m, config: statsConfig{enabled: atomicBool(true)}} s.NewStat("test-timer-1", TimerType).SendTiming(10 * time.Second) - md := getDataPoint[metricdata.Histogram](ctx, t, r, "test-timer-1", 0) + md := getDataPoint[metricdata.Histogram[float64]](ctx, t, r, "test-timer-1", 0) require.Len(t, md.DataPoints, 1) require.EqualValues(t, 1, md.DataPoints[0].Count) require.InDelta(t, 10.0, md.DataPoints[0].Sum, 0.001) @@ -187,7 +187,7 @@ func TestOTelMeasurementOperations(t *testing.T) { r, m := newReaderWithMeter(t) s := &otelStats{meter: m, config: statsConfig{enabled: atomicBool(true)}} s.NewStat("test-timer-2", TimerType).Since(time.Now().Add(-time.Second)) - md := getDataPoint[metricdata.Histogram](ctx, t, r, "test-timer-2", 0) + md := getDataPoint[metricdata.Histogram[float64]](ctx, t, r, "test-timer-2", 0) require.Len(t, md.DataPoints, 1) require.EqualValues(t, 1, md.DataPoints[0].Count) require.InDelta(t, 1.0, md.DataPoints[0].Sum, 0.001) @@ -201,7 +201,7 @@ func TestOTelMeasurementOperations(t *testing.T) { return time.Now().Add(-time.Second) } ot.RecordDuration()() - md := getDataPoint[metricdata.Histogram](ctx, t, r, "test-timer-3", 0) + md := getDataPoint[metricdata.Histogram[float64]](ctx, t, r, "test-timer-3", 0) require.Len(t, md.DataPoints, 1) require.EqualValues(t, 1, md.DataPoints[0].Count) require.InDelta(t, 1.0, md.DataPoints[0].Sum, 0.001) @@ -211,7 +211,7 @@ func TestOTelMeasurementOperations(t *testing.T) { r, m := newReaderWithMeter(t) s := &otelStats{meter: m, config: statsConfig{enabled: atomicBool(true)}} s.NewStat("test-hist-1", HistogramType).Observe(1.2) - md := getDataPoint[metricdata.Histogram](ctx, t, r, "test-hist-1", 0) + md := getDataPoint[metricdata.Histogram[float64]](ctx, t, r, "test-hist-1", 0) require.Len(t, md.DataPoints, 1) require.EqualValues(t, 1, md.DataPoints[0].Count) require.EqualValues(t, 1.2, md.DataPoints[0].Sum) diff --git a/stats/stats.go b/stats/stats.go index 0c923474..64f654ee 100644 --- a/stats/stats.go +++ b/stats/stats.go @@ -10,7 +10,7 @@ import ( "unicode" "github.com/prometheus/client_golang/prometheus" - "go.opentelemetry.io/otel/metric/global" + "go.opentelemetry.io/otel" "github.com/rudderlabs/rudder-go-kit/config" "github.com/rudderlabs/rudder-go-kit/logger" @@ -47,6 +47,7 @@ type Stats interface { // NewSampledTaggedStat creates a new Measurement with provided Name, Type and Tags // Deprecated: use NewTaggedStat instead + NewSampledTaggedStat(name, statType string, tags Tags) Measurement // Start starts the stats service and the collection of periodic stats. @@ -102,7 +103,7 @@ func NewStats( return &otelStats{ config: statsConfig, stopBackgroundCollection: func() {}, - meter: global.MeterProvider().Meter(defaultMeterName), + meter: otel.GetMeterProvider().Meter(defaultMeterName), logger: loggerFactory.NewLogger().Child("stats"), prometheusRegisterer: registerer, prometheusGatherer: gatherer,