diff --git a/agent/hcp/client/metrics_client.go b/agent/hcp/client/metrics_client.go index a45d6343fc466..2c37a24a07549 100644 --- a/agent/hcp/client/metrics_client.go +++ b/agent/hcp/client/metrics_client.go @@ -17,6 +17,8 @@ import ( metricpb "go.opentelemetry.io/proto/otlp/metrics/v1" "golang.org/x/oauth2" "google.golang.org/protobuf/proto" + + "github.com/hashicorp/consul/version" ) const ( @@ -72,8 +74,9 @@ func NewMetricsClient(cfg CloudConfig, ctx context.Context) (MetricsClient, erro } header := make(http.Header) - header.Set("Content-Type", "application/x-protobuf") + header.Set("content-type", "application/x-protobuf") header.Set("x-hcp-resource-id", r.String()) + header.Set("x-channel", fmt.Sprintf("consul/%s", version.GetHumanVersion())) return &otlpClient{ client: c, @@ -124,36 +127,28 @@ func (o *otlpClient) ExportMetrics(ctx context.Context, protoMetrics *metricpb.R body, err := proto.Marshal(pbRequest) if err != nil { - return fmt.Errorf("failed to export metrics: %v", err) + return fmt.Errorf("failed to marshal the request: %w", err) } req, err := retryablehttp.NewRequest(http.MethodPost, endpoint, bytes.NewBuffer(body)) if err != nil { - return fmt.Errorf("failed to export metrics: %v", err) + return fmt.Errorf("failed to create request: %w", err) } req.Header = *o.header resp, err := o.client.Do(req.WithContext(ctx)) if err != nil { - return fmt.Errorf("failed to export metrics: %v", err) + return fmt.Errorf("failed to post metrics: %w", err) } defer resp.Body.Close() var respData bytes.Buffer if _, err := io.Copy(&respData, resp.Body); err != nil { - return fmt.Errorf("failed to export metrics: %v", err) + return fmt.Errorf("failed to read body: %w", err) } - if respData.Len() != 0 { - var respProto colmetricpb.ExportMetricsServiceResponse - if err := proto.Unmarshal(respData.Bytes(), &respProto); err != nil { - return fmt.Errorf("failed to export metrics: %v", err) - } - - if respProto.PartialSuccess != nil { - msg := respProto.PartialSuccess.GetErrorMessage() - return fmt.Errorf("failed to export metrics: partial success: %s", msg) - } + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("failed to export metrics: code %d: %s", resp.StatusCode, string(body)) } return nil diff --git a/agent/hcp/client/metrics_client_test.go b/agent/hcp/client/metrics_client_test.go index ee4c4262bba9f..e80996fcf5eb0 100644 --- a/agent/hcp/client/metrics_client_test.go +++ b/agent/hcp/client/metrics_client_test.go @@ -11,6 +11,8 @@ import ( colpb "go.opentelemetry.io/proto/otlp/collector/metrics/v1" metricpb "go.opentelemetry.io/proto/otlp/metrics/v1" "google.golang.org/protobuf/proto" + + "github.com/hashicorp/consul/version" ) func TestNewMetricsClient(t *testing.T) { @@ -72,22 +74,17 @@ func TestExportMetrics(t *testing.T) { }, "failsWithNonRetryableError": { status: http.StatusBadRequest, - wantErr: "failed to export metrics", + wantErr: "failed to export metrics: code 400", }, } { t.Run(name, func(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - require.Equal(t, r.Header.Get("Content-Type"), "application/x-protobuf") + require.Equal(t, r.Header.Get("content-type"), "application/x-protobuf") require.Equal(t, r.Header.Get("x-hcp-resource-id"), testResourceID) + require.Equal(t, r.Header.Get("x-channel"), fmt.Sprintf("consul/%s", version.GetHumanVersion())) require.Equal(t, r.Header.Get("Authorization"), "Bearer test-token") body := colpb.ExportMetricsServiceResponse{} - - if test.wantErr != "" { - body.PartialSuccess = &colpb.ExportMetricsPartialSuccess{ - ErrorMessage: "partial failure", - } - } bytes, err := proto.Marshal(&body) require.NoError(t, err) diff --git a/agent/hcp/deps.go b/agent/hcp/deps.go index fcf2a6ef78002..f4ad161daba4a 100644 --- a/agent/hcp/deps.go +++ b/agent/hcp/deps.go @@ -5,6 +5,7 @@ package hcp import ( "context" + "fmt" "net/url" "time" @@ -24,20 +25,24 @@ type Deps struct { Sink metrics.MetricSink } -func NewDeps(cfg config.CloudConfig, logger hclog.Logger, nodeID types.NodeID) (d Deps, err error) { - d.Client, err = hcpclient.NewClient(cfg) +func NewDeps(cfg config.CloudConfig, logger hclog.Logger, nodeID types.NodeID) (Deps, error) { + client, err := hcpclient.NewClient(cfg) if err != nil { - return + return Deps{}, fmt.Errorf("failed to init client: %w:", err) } - d.Provider, err = scada.New(cfg, logger.Named("hcp.scada")) + provider, err := scada.New(cfg, logger.Named("scada")) if err != nil { - return + return Deps{}, fmt.Errorf("failed to init scada: %w", err) } - d.Sink = sink(d.Client, &cfg, logger, nodeID) + sink := sink(client, &cfg, logger.Named("sink"), nodeID) - return + return Deps{ + Client: client, + Provider: provider, + Sink: sink, + }, nil } // sink provides initializes an OTELSink which forwards Consul metrics to HCP. @@ -86,5 +91,7 @@ func sink(hcpClient hcpclient.Client, cfg hcpclient.CloudConfig, logger hclog.Lo return nil } + logger.Debug("initialized HCP metrics sink") + return sink } diff --git a/agent/hcp/telemetry/custom_metrics.go b/agent/hcp/telemetry/custom_metrics.go new file mode 100644 index 0000000000000..746dc56cbe419 --- /dev/null +++ b/agent/hcp/telemetry/custom_metrics.go @@ -0,0 +1,14 @@ +package telemetry + +// Keys for custom Go Metrics metrics emitted only for the OTEL +// export (exporter.go) and transform (transform.go) failures and successes. +// These enable us to monitor OTEL operations. +var ( + internalMetricTransformFailure []string = []string{"hcp", "otel", "transform", "failure"} + + internalMetricExportSuccess []string = []string{"hcp", "otel", "exporter", "export", "sucess"} + internalMetricExportFailure []string = []string{"hcp", "otel", "exporter", "export", "failure"} + + internalMetricExporterShutdown []string = []string{"hcp", "otel", "exporter", "shutdown"} + internalMetricExporterForceFlush []string = []string{"hcp", "otel", "exporter", "force_flush"} +) diff --git a/agent/hcp/telemetry/otel_exporter.go b/agent/hcp/telemetry/otel_exporter.go index 2512706f5353c..76c8f5b000b55 100644 --- a/agent/hcp/telemetry/otel_exporter.go +++ b/agent/hcp/telemetry/otel_exporter.go @@ -2,8 +2,10 @@ package telemetry import ( "context" + "fmt" "net/url" + goMetrics "github.com/armon/go-metrics" "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/metric/aggregation" "go.opentelemetry.io/otel/sdk/metric/metricdata" @@ -56,17 +58,24 @@ func (e *OTELExporter) Export(ctx context.Context, metrics *metricdata.ResourceM if isEmpty(otlpMetrics) { return nil } - return e.client.ExportMetrics(ctx, otlpMetrics, e.endpoint.String()) + err := e.client.ExportMetrics(ctx, otlpMetrics, e.endpoint.String()) + if err != nil { + goMetrics.IncrCounter(internalMetricExportFailure, 1) + return fmt.Errorf("failed to export metrics: %w", err) + } + + goMetrics.IncrCounter(internalMetricExportSuccess, 1) + return nil } // ForceFlush is a no-op, as the MetricsClient client holds no state. func (e *OTELExporter) ForceFlush(ctx context.Context) error { - // TODO: Emit metric when this operation occurs. + goMetrics.IncrCounter(internalMetricExporterForceFlush, 1) return ctx.Err() } // Shutdown is a no-op, as the MetricsClient is a HTTP client that requires no graceful shutdown. func (e *OTELExporter) Shutdown(ctx context.Context) error { - // TODO: Emit metric when this operation occurs. + goMetrics.IncrCounter(internalMetricExporterShutdown, 1) return ctx.Err() } diff --git a/agent/hcp/telemetry/otel_exporter_test.go b/agent/hcp/telemetry/otel_exporter_test.go index 72e6b84d242c6..bc1a626f1c169 100644 --- a/agent/hcp/telemetry/otel_exporter_test.go +++ b/agent/hcp/telemetry/otel_exporter_test.go @@ -4,8 +4,11 @@ import ( "context" "fmt" "net/url" + "strings" "testing" + "time" + "github.com/armon/go-metrics" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/metric/aggregation" @@ -16,6 +19,14 @@ import ( "github.com/hashicorp/consul/agent/hcp/client" ) +type mockMetricsClient struct { + exportErr error +} + +func (m *mockMetricsClient) ExportMetrics(ctx context.Context, protoMetrics *metricpb.ResourceMetrics, endpoint string) error { + return m.exportErr +} + func TestTemporality(t *testing.T) { t.Parallel() exp := &OTELExporter{} @@ -50,14 +61,6 @@ func TestAggregation(t *testing.T) { } } -type mockMetricsClient struct { - exportErr error -} - -func (m *mockMetricsClient) ExportMetrics(ctx context.Context, protoMetrics *metricpb.ResourceMetrics, endpoint string) error { - return m.exportErr -} - func TestExport(t *testing.T) { t.Parallel() for name, test := range map[string]struct { @@ -111,6 +114,72 @@ func TestExport(t *testing.T) { } } +// TestExport_CustomMetrics tests that a custom metric (hcp.otel.exporter.*) is emitted +// for exporter operations. This test cannot be run in parallel as the metrics.NewGlobal() +// sets a shared global sink. +func TestExport_CustomMetrics(t *testing.T) { + for name, tc := range map[string]struct { + client client.MetricsClient + metricKey []string + operation string + }{ + "exportSuccessEmitsCustomMetric": { + client: &mockMetricsClient{}, + metricKey: internalMetricExportSuccess, + operation: "export", + }, + "exportFailureEmitsCustomMetric": { + client: &mockMetricsClient{ + exportErr: fmt.Errorf("client err"), + }, + metricKey: internalMetricExportFailure, + operation: "export", + }, + "shutdownEmitsCustomMetric": { + metricKey: internalMetricExporterShutdown, + operation: "shutdown", + }, + "forceFlushEmitsCustomMetric": { + metricKey: internalMetricExporterForceFlush, + operation: "flush", + }, + } { + t.Run(name, func(t *testing.T) { + // Init global sink. + serviceName := "test.transform" + cfg := metrics.DefaultConfig(serviceName) + cfg.EnableHostname = false + + sink := metrics.NewInmemSink(10*time.Second, 10*time.Second) + metrics.NewGlobal(cfg, sink) + + // Perform operation that emits metric. + exp := NewOTELExporter(tc.client, &url.URL{}) + + ctx := context.Background() + switch tc.operation { + case "flush": + exp.ForceFlush(ctx) + case "shutdown": + exp.Shutdown(ctx) + default: + exp.Export(ctx, inputResourceMetrics) + } + + // Collect sink metrics. + intervals := sink.Data() + require.Len(t, intervals, 1) + key := serviceName + "." + strings.Join(tc.metricKey, ".") + sv := intervals[0].Counters[key] + + // Verify count for transform failure metric. + require.NotNil(t, sv) + require.NotNil(t, sv.AggregateSample) + require.Equal(t, 1, sv.AggregateSample.Count) + }) + } +} + func TestForceFlush(t *testing.T) { t.Parallel() exp := &OTELExporter{} diff --git a/agent/hcp/telemetry/otlp_transform.go b/agent/hcp/telemetry/otlp_transform.go index 7ba1650ffd05d..76e20552a0d4e 100644 --- a/agent/hcp/telemetry/otlp_transform.go +++ b/agent/hcp/telemetry/otlp_transform.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" + goMetrics "github.com/armon/go-metrics" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/metric/metricdata" cpb "go.opentelemetry.io/proto/otlp/common/v1" @@ -70,7 +71,7 @@ func metricsToPB(metrics []metricdata.Metrics) []*mpb.Metric { for _, m := range metrics { o, err := metricTypeToPB(m) if err != nil { - // TODO: Emit metric when a transformation failure occurs. + goMetrics.IncrCounter(internalMetricTransformFailure, 1) continue } out = append(out, o) diff --git a/agent/hcp/telemetry/otlp_transform_test.go b/agent/hcp/telemetry/otlp_transform_test.go index 1c22e9a5cd755..8f6beb7d489db 100644 --- a/agent/hcp/telemetry/otlp_transform_test.go +++ b/agent/hcp/telemetry/otlp_transform_test.go @@ -1,9 +1,11 @@ package telemetry import ( + "strings" "testing" "time" + "github.com/armon/go-metrics" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/attribute" @@ -17,7 +19,6 @@ import ( ) var ( - // Common attributes for test cases. start = time.Date(2000, time.January, 01, 0, 0, 0, 0, time.FixedZone("GMT", 0)) end = start.Add(30 * time.Second) @@ -127,37 +128,43 @@ var ( }, } + validFloat64Gauge = metricdata.Metrics{ + Name: "float64-gauge", + Description: "Gauge with float64 values", + Unit: "1", + Data: metricdata.Gauge[float64]{DataPoints: inputDP}, + } + + validFloat64Sum = metricdata.Metrics{ + Name: "float64-sum", + Description: "Sum with float64 values", + Unit: "1", + Data: metricdata.Sum[float64]{ + Temporality: metricdata.CumulativeTemporality, + IsMonotonic: false, + DataPoints: inputDP, + }, + } + + validFloat64Hist = metricdata.Metrics{ + Name: "float64-histogram", + Description: "Histogram", + Unit: "1", + Data: metricdata.Histogram[float64]{ + Temporality: metricdata.CumulativeTemporality, + DataPoints: inputHDP, + }, + } + // Metrics Test Case // - 3 invalid metrics and 3 Valid to test filtering - // - 1 invalid metric type - // - 2 invalid cummulative temporalities (only cummulative supported) + // - 1 invalid metric type + // - 2 invalid cummulative temporalities (only cummulative supported) // - 3 types (Gauge, Counter, and Histogram) supported inputMetrics = []metricdata.Metrics{ - { - Name: "float64-gauge", - Description: "Gauge with float64 values", - Unit: "1", - Data: metricdata.Gauge[float64]{DataPoints: inputDP}, - }, - { - Name: "float64-sum", - Description: "Sum with float64 values", - Unit: "1", - Data: metricdata.Sum[float64]{ - Temporality: metricdata.CumulativeTemporality, - IsMonotonic: false, - DataPoints: inputDP, - }, - }, - { - Name: "float64-histogram", - Description: "Histogram", - Unit: "1", - Data: metricdata.Histogram[float64]{ - Temporality: metricdata.CumulativeTemporality, - DataPoints: inputHDP, - }, - }, + validFloat64Gauge, + validFloat64Sum, + validFloat64Hist, invalidSumTemporality, invalidHistTemporality, invalidSumAgg, @@ -273,3 +280,63 @@ func TestTransformOTLP(t *testing.T) { rm := transformOTLP(inputResourceMetrics) require.Equal(t, expectedResourceMetrics, rm) } + +// TestTransformOTLP_CustomMetrics tests that a custom metric (hcp.otel.transform.failure) is emitted +// when transform fails. This test cannot be run in parallel as the metrics.NewGlobal() +// sets a shared global sink. +func TestTransformOTLP_CustomMetrics(t *testing.T) { + for name, tc := range map[string]struct { + inputRM *metricdata.ResourceMetrics + expectedMetricCount int + }{ + "successNoMetric": { + inputRM: &metricdata.ResourceMetrics{ + // 3 valid metrics. + ScopeMetrics: []metricdata.ScopeMetrics{ + { + Metrics: []metricdata.Metrics{ + validFloat64Gauge, + validFloat64Hist, + validFloat64Sum, + }, + }, + }, + }, + }, + "failureEmitsMetric": { + // inputScopeMetrics contains 3 bad metrics. + inputRM: inputResourceMetrics, + expectedMetricCount: 3, + }, + } { + tc := tc + t.Run(name, func(t *testing.T) { + // Init global sink. + serviceName := "test.transform" + cfg := metrics.DefaultConfig(serviceName) + cfg.EnableHostname = false + + sink := metrics.NewInmemSink(10*time.Second, 10*time.Second) + metrics.NewGlobal(cfg, sink) + + // Perform operation that emits metric. + transformOTLP(tc.inputRM) + + // Collect sink metrics. + intervals := sink.Data() + require.Len(t, intervals, 1) + key := serviceName + "." + strings.Join(internalMetricTransformFailure, ".") + sv := intervals[0].Counters[key] + + if tc.expectedMetricCount == 0 { + require.Empty(t, sv) + return + } + + // Verify count for transform failure metric. + require.NotNil(t, sv) + require.NotNil(t, sv.AggregateSample) + require.Equal(t, 3, sv.AggregateSample.Count) + }) + } +} diff --git a/agent/setup.go b/agent/setup.go index 6e6bb322681d0..9ed993aaf4a6a 100644 --- a/agent/setup.go +++ b/agent/setup.go @@ -104,7 +104,7 @@ func NewBaseDeps(configLoader ConfigLoader, logOut io.Writer, providedLogger hcl var extraSinks []metrics.MetricSink if cfg.IsCloudEnabled() { - d.HCP, err = hcp.NewDeps(cfg.Cloud, d.Logger, cfg.NodeID) + d.HCP, err = hcp.NewDeps(cfg.Cloud, d.Logger.Named("hcp"), cfg.NodeID) if err != nil { return d, err } diff --git a/go.mod b/go.mod index e4e32cea37329..89ef735d985de 100644 --- a/go.mod +++ b/go.mod @@ -62,7 +62,7 @@ require ( github.com/hashicorp/golang-lru v0.5.4 github.com/hashicorp/hcl v1.0.0 github.com/hashicorp/hcp-scada-provider v0.2.3 - github.com/hashicorp/hcp-sdk-go v0.46.1-0.20230519164650-51657675d9e7 + github.com/hashicorp/hcp-sdk-go v0.48.0 github.com/hashicorp/hil v0.0.0-20200423225030-a18a1cd20038 github.com/hashicorp/memberlist v0.5.0 github.com/hashicorp/raft v1.5.0 @@ -94,12 +94,12 @@ require ( github.com/rboyer/safeio v0.2.1 github.com/ryanuber/columnize v2.1.2+incompatible github.com/shirou/gopsutil/v3 v3.22.8 - github.com/stretchr/testify v1.8.2 + github.com/stretchr/testify v1.8.3 go.etcd.io/bbolt v1.3.6 - go.opentelemetry.io/otel v1.16.0-rc.1.0.20230510144741-7dea2225a218 - go.opentelemetry.io/otel/metric v1.16.0-rc.1 - go.opentelemetry.io/otel/sdk v1.16.0-rc.1.0.20230510144741-7dea2225a218 - go.opentelemetry.io/otel/sdk/metric v0.39.0-rc.1.0.20230510144741-7dea2225a218 + go.opentelemetry.io/otel 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.opentelemetry.io/proto/otlp v0.19.0 go.uber.org/goleak v1.1.10 golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d @@ -231,7 +231,7 @@ require ( github.com/yusufpapurcu/wmi v1.2.2 // indirect go.mongodb.org/mongo-driver v1.11.0 // indirect go.opencensus.io v0.23.0 // indirect - go.opentelemetry.io/otel/trace v1.16.0-rc.1 // indirect + go.opentelemetry.io/otel/trace v1.16.0 // indirect go.uber.org/atomic v1.9.0 // indirect golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect diff --git a/go.sum b/go.sum index bffefaaf6aab5..59ebf57327e0c 100644 --- a/go.sum +++ b/go.sum @@ -610,8 +610,8 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcp-scada-provider v0.2.3 h1:AarYR+/Pcv+cMvPdAlb92uOBmZfEH6ny4+DT+4NY2VQ= github.com/hashicorp/hcp-scada-provider v0.2.3/go.mod h1:ZFTgGwkzNv99PLQjTsulzaCplCzOTBh0IUQsPKzrQFo= -github.com/hashicorp/hcp-sdk-go v0.46.1-0.20230519164650-51657675d9e7 h1:/7/5kyyCT5tCeRanKIJAfP8Z6JnjEV55PNuI6phn2k0= -github.com/hashicorp/hcp-sdk-go v0.46.1-0.20230519164650-51657675d9e7/go.mod h1:hZqky4HEzsKwvLOt4QJlZUrjeQmb4UCZUhDP2HyQFfc= +github.com/hashicorp/hcp-sdk-go v0.48.0 h1:LWpFR7YVDz4uG4C/ixcy2tRbg7/BgjMcTh1bRkKaeBQ= +github.com/hashicorp/hcp-sdk-go v0.48.0/go.mod h1:hZqky4HEzsKwvLOt4QJlZUrjeQmb4UCZUhDP2HyQFfc= github.com/hashicorp/hil v0.0.0-20200423225030-a18a1cd20038 h1:n9J0rwVWXDpNd5iZnwY7w4WZyq53/rROeI7OVvLW8Ok= github.com/hashicorp/hil v0.0.0-20200423225030-a18a1cd20038/go.mod h1:n2TSygSNwsLJ76m8qFXTSc7beTb+auJxYdqrnoqwZWE= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= @@ -1011,8 +1011,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.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -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/tencentcloud/tencentcloud-sdk-go v1.0.162 h1:8fDzz4GuVg4skjY2B0nMN7h6uN61EDVkuLyI2+qGHhI= github.com/tencentcloud/tencentcloud-sdk-go v1.0.162/go.mod h1:asUz5BPXxgoPGaRgZaVm1iGcUAuHyYUo1nXqKa83cvI= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= @@ -1079,16 +1080,16 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/otel v1.16.0-rc.1.0.20230510144741-7dea2225a218 h1:aKv7ueCXRlBdHGBNfot8BYwcvp4jwJ/rK/T/KQ3uXoA= -go.opentelemetry.io/otel v1.16.0-rc.1.0.20230510144741-7dea2225a218/go.mod h1:dGSTwGyzvw5Dzn8nE8HrfOXnWIDrL0GIzQdOpTnJ2CM= -go.opentelemetry.io/otel/metric v1.16.0-rc.1 h1:R9MPFw2jA+z91ejfOVU7QRYSdb37E5Ak6jJUwNMQbR8= -go.opentelemetry.io/otel/metric v1.16.0-rc.1/go.mod h1:0I+4bYjKHaoXGw7uXAABYA5wyptQdXeXOhi3SBgD6GM= -go.opentelemetry.io/otel/sdk v1.16.0-rc.1.0.20230510144741-7dea2225a218 h1:YC5ikDtSM7s+sJprqR7edyP9EBKMHGaAnWfte7EsQCI= -go.opentelemetry.io/otel/sdk v1.16.0-rc.1.0.20230510144741-7dea2225a218/go.mod h1:tY+q2LQ4iuvdwcN0zrt/2NdF3ntVodUPbiHPMRZnXyo= -go.opentelemetry.io/otel/sdk/metric v0.39.0-rc.1.0.20230510144741-7dea2225a218 h1:5Ehgy+TyY7Jh3orDVIn7uVJ7UkFm3yP5lXXQN8ia+00= -go.opentelemetry.io/otel/sdk/metric v0.39.0-rc.1.0.20230510144741-7dea2225a218/go.mod h1:VKkJz/K+pb4rkqXlBH5DMJi1ebQLYhV82fTSK3WvOOQ= -go.opentelemetry.io/otel/trace v1.16.0-rc.1 h1:/dPBlZrzSSXglIEKgy/A3kyiACcmgNMFWKTIHHxxd/o= -go.opentelemetry.io/otel/trace v1.16.0-rc.1/go.mod h1:xqretMbHfSU24I2KKbSEG+aVHsNtBCr5L4BGaNqTx68= +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/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=