diff --git a/CHANGELOG.md b/CHANGELOG.md index f724d8857182..e9bf625a1768 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,16 @@ internal API changes are not present. Main (unreleased) ----------------- +### Breaking changes + +- The algorithm for the "hash" action of `otelcol.processor.attributes` has changed. + The change was made in PR [#22831](https://github.com/open-telemetry/opentelemetry-collector-contrib/pull/22831) of opentelemetry-collector-contrib. (@ptodev) + +- `otelcol.exporter.loki` now includes the instrumentation scope in its output. (@ptodev) + +- `otelcol.extension.jaeger_remote_sampling` removes the `\` HTTP endpoint. The `/sampling` endpoint is still functional. + The change was made in PR [#18070](https://github.com/open-telemetry/opentelemetry-collector-contrib/pull/18070) of opentelemetry-collector-contrib. (@ptodev) + ### Features - The Pyroscope scrape component computes and sends delta profiles automatically when required to reduce bandwidth usage. (@cyriltovena) @@ -18,7 +28,6 @@ Main (unreleased) - Integrations: Introduce the `squid` integration. (@armstrmi) - - New Grafana Agent Flow components: - `prometheus.exporter.kafka` collects metrics from Kafka Server (@oliver-zhang) @@ -40,6 +49,8 @@ Main (unreleased) - Update `node_exporter` dependency to v1.6.0. (@spartan0x117) +- Update OpenTelemetry Collector dependencies from v0.63.0 to v0.79.0. (@ptodev) + ### Bugfixes - Add signing region to remote.s3 component for use with custom endpoints so that Authorization Headers work correctly when diff --git a/component/otelcol/config_grpc.go b/component/otelcol/config_grpc.go index 64a7a1b87025..9852d40dbd0c 100644 --- a/component/otelcol/config_grpc.go +++ b/component/otelcol/config_grpc.go @@ -137,11 +137,11 @@ type GRPCClientArguments struct { TLS TLSClientArguments `river:"tls,block,optional"` Keepalive *KeepaliveClientArguments `river:"keepalive,block,optional"` - ReadBufferSize units.Base2Bytes `river:"read_buffer_size,attr,optional"` - WriteBufferSize units.Base2Bytes `river:"write_buffer_size,attr,optional"` - WaitForReady bool `river:"wait_for_ready,attr,optional"` - Headers map[string]configopaque.String `river:"headers,attr,optional"` - BalancerName string `river:"balancer_name,attr,optional"` + ReadBufferSize units.Base2Bytes `river:"read_buffer_size,attr,optional"` + WriteBufferSize units.Base2Bytes `river:"write_buffer_size,attr,optional"` + WaitForReady bool `river:"wait_for_ready,attr,optional"` + Headers map[string]string `river:"headers,attr,optional"` + BalancerName string `river:"balancer_name,attr,optional"` // Auth is a binding to an otelcol.auth.* component extension which handles // authentication. @@ -154,6 +154,11 @@ func (args *GRPCClientArguments) Convert() *otelconfiggrpc.GRPCClientSettings { return nil } + opaqueHeaders := make(map[string]configopaque.String) + for headerName, headerVal := range args.Headers { + opaqueHeaders[headerName] = configopaque.String(headerVal) + } + // Configure the authentication if args.Auth is set. var auth *otelconfigauth.Authentication if args.Auth != nil { @@ -171,7 +176,7 @@ func (args *GRPCClientArguments) Convert() *otelconfiggrpc.GRPCClientSettings { ReadBufferSize: int(args.ReadBufferSize), WriteBufferSize: int(args.WriteBufferSize), WaitForReady: args.WaitForReady, - Headers: args.Headers, + Headers: opaqueHeaders, BalancerName: args.BalancerName, Auth: auth, diff --git a/component/otelcol/config_http.go b/component/otelcol/config_http.go index ff9baae64443..13ddaf306996 100644 --- a/component/otelcol/config_http.go +++ b/component/otelcol/config_http.go @@ -8,7 +8,7 @@ import ( otelcomponent "go.opentelemetry.io/collector/component" otelconfigauth "go.opentelemetry.io/collector/config/configauth" otelconfighttp "go.opentelemetry.io/collector/config/confighttp" - otelconfigopaque "go.opentelemetry.io/collector/config/configopaque" + "go.opentelemetry.io/collector/config/configopaque" otelextension "go.opentelemetry.io/collector/extension" ) @@ -80,10 +80,10 @@ type HTTPClientArguments struct { TLS TLSClientArguments `river:"tls,block,optional"` - ReadBufferSize units.Base2Bytes `river:"read_buffer_size,attr,optional"` - WriteBufferSize units.Base2Bytes `river:"write_buffer_size,attr,optional"` - Timeout time.Duration `river:"timeout,attr,optional"` - Headers map[string]otelconfigopaque.String `river:"headers,attr,optional"` + ReadBufferSize units.Base2Bytes `river:"read_buffer_size,attr,optional"` + WriteBufferSize units.Base2Bytes `river:"write_buffer_size,attr,optional"` + Timeout time.Duration `river:"timeout,attr,optional"` + Headers map[string]string `river:"headers,attr,optional"` // CustomRoundTripper func(next http.RoundTripper) (http.RoundTripper, error) TODO (@tpaschalis) MaxIdleConns *int `river:"max_idle_conns,attr,optional"` MaxIdleConnsPerHost *int `river:"max_idle_conns_per_host,attr,optional"` @@ -107,6 +107,11 @@ func (args *HTTPClientArguments) Convert() *otelconfighttp.HTTPClientSettings { auth = &otelconfigauth.Authentication{AuthenticatorID: args.Auth.ID} } + opaqueHeaders := make(map[string]configopaque.String) + for headerName, headerVal := range args.Headers { + opaqueHeaders[headerName] = configopaque.String(headerVal) + } + return &otelconfighttp.HTTPClientSettings{ Endpoint: args.Endpoint, @@ -117,7 +122,7 @@ func (args *HTTPClientArguments) Convert() *otelconfighttp.HTTPClientSettings { ReadBufferSize: int(args.ReadBufferSize), WriteBufferSize: int(args.WriteBufferSize), Timeout: args.Timeout, - Headers: args.Headers, + Headers: opaqueHeaders, // CustomRoundTripper: func(http.RoundTripper) (http.RoundTripper, error) { panic("not implemented") }, TODO (@tpaschalis) MaxIdleConns: args.MaxIdleConns, MaxIdleConnsPerHost: args.MaxIdleConnsPerHost, diff --git a/component/otelcol/exporter/jaeger/jaeger.go b/component/otelcol/exporter/jaeger/jaeger.go index 0dea790f8aea..29fdce5548f7 100644 --- a/component/otelcol/exporter/jaeger/jaeger.go +++ b/component/otelcol/exporter/jaeger/jaeger.go @@ -9,7 +9,6 @@ import ( "github.com/grafana/agent/component/otelcol/exporter" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/jaegerexporter" otelcomponent "go.opentelemetry.io/collector/component" - "go.opentelemetry.io/collector/config/configopaque" otelpexporterhelper "go.opentelemetry.io/collector/exporter/exporterhelper" otelextension "go.opentelemetry.io/collector/extension" ) @@ -83,7 +82,7 @@ type GRPCClientArguments otelcol.GRPCClientArguments // DefaultGRPCClientArguments holds component-specific default settings for // GRPCClientArguments. var DefaultGRPCClientArguments = GRPCClientArguments{ - Headers: map[string]configopaque.String{}, + Headers: map[string]string{}, Compression: otelcol.CompressionTypeGzip, WriteBufferSize: 512 * 1024, } diff --git a/component/otelcol/exporter/loki/internal/convert/convert.go b/component/otelcol/exporter/loki/internal/convert/convert.go index 404dbb88328e..61f4ecb50b99 100644 --- a/component/otelcol/exporter/loki/internal/convert/convert.go +++ b/component/otelcol/exporter/loki/internal/convert/convert.go @@ -10,16 +10,14 @@ package convert import ( "context" - "fmt" - "strings" "sync" "github.com/go-kit/log" "github.com/go-kit/log/level" "github.com/grafana/agent/component/common/loki" + loki_translator "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/loki" "github.com/prometheus/client_golang/prometheus" "go.opentelemetry.io/collector/consumer" - "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" ) @@ -69,31 +67,7 @@ func (conv *Converter) ConsumeLogs(ctx context.Context, ld plog.Logs) error { for k := 0; k < logs.Len(); k++ { conv.metrics.entriesTotal.Inc() - // we may remove attributes, so to avoid mutating the original - // log entry, we make our own copy and change that instead. - log := plog.NewLogRecord() - logs.At(k).CopyTo(log) - - // similarly, we may remove resources, so to avoid mutating the - // original log entry, we make and use our own copy instead. - resource := pcommon.NewResource() - rls.At(i).Resource().CopyTo(resource) - - // adds level attribute from log.severityNumber - addLogLevelAttributeAndHint(log) - - // TODO (@tpaschalis) If we want to pre-populate a tenant - // label from the OTel hint, it should happen here. with the - // upstream getTenantFromTenantHint helper. - - format := getFormatFromFormatHint(log.Attributes(), resource.Attributes()) - - mergedLabels := convertAttributesAndMerge(log.Attributes(), resource.Attributes()) - // remove the attributes that were promoted to labels - removeAttributes(log.Attributes(), mergedLabels) - removeAttributes(resource.Attributes(), mergedLabels) - - entry, err := convertLogToLokiEntry(log, resource, format, scope) + entry, err := loki_translator.LogToLokiEntry(logs.At(k), rls.At(i).Resource(), scope) if err != nil { level.Error(conv.log).Log("msg", "failed to convert log to loki entry", "err", err) conv.metrics.entriesFailed.Inc() @@ -102,8 +76,8 @@ func (conv *Converter) ConsumeLogs(ctx context.Context, ld plog.Logs) error { conv.metrics.entriesProcessed.Inc() entries = append(entries, loki.Entry{ - Labels: mergedLabels, - Entry: *entry, + Labels: entry.Labels, + Entry: *entry.Entry, }) } } @@ -131,63 +105,3 @@ func (conv *Converter) UpdateFanout(fanout []loki.LogsReceiver) { conv.next = fanout } - -func addLogLevelAttributeAndHint(log plog.LogRecord) { - if log.SeverityNumber() == plog.SeverityNumberUnspecified { - return - } - addHint(log) - if _, found := log.Attributes().Get(levelAttributeName); !found { - level := severityNumberToLevel[log.SeverityNumber().String()] - log.Attributes().PutStr(levelAttributeName, level) - } -} - -func addHint(log plog.LogRecord) { - if value, found := log.Attributes().Get(hintAttributes); found && !strings.Contains(value.AsString(), levelAttributeName) { - log.Attributes().PutStr(hintAttributes, fmt.Sprintf("%s,%s", value.AsString(), levelAttributeName)) - } else { - log.Attributes().PutStr(hintAttributes, levelAttributeName) - } -} - -var severityNumberToLevel = map[string]string{ - plog.SeverityNumberUnspecified.String(): "UNSPECIFIED", - plog.SeverityNumberTrace.String(): "TRACE", - plog.SeverityNumberTrace2.String(): "TRACE2", - plog.SeverityNumberTrace3.String(): "TRACE3", - plog.SeverityNumberTrace4.String(): "TRACE4", - plog.SeverityNumberDebug.String(): "DEBUG", - plog.SeverityNumberDebug2.String(): "DEBUG2", - plog.SeverityNumberDebug3.String(): "DEBUG3", - plog.SeverityNumberDebug4.String(): "DEBUG4", - plog.SeverityNumberInfo.String(): "INFO", - plog.SeverityNumberInfo2.String(): "INFO2", - plog.SeverityNumberInfo3.String(): "INFO3", - plog.SeverityNumberInfo4.String(): "INFO4", - plog.SeverityNumberWarn.String(): "WARN", - plog.SeverityNumberWarn2.String(): "WARN2", - plog.SeverityNumberWarn3.String(): "WARN3", - plog.SeverityNumberWarn4.String(): "WARN4", - plog.SeverityNumberError.String(): "ERROR", - plog.SeverityNumberError2.String(): "ERROR2", - plog.SeverityNumberError3.String(): "ERROR3", - plog.SeverityNumberError4.String(): "ERROR4", - plog.SeverityNumberFatal.String(): "FATAL", - plog.SeverityNumberFatal2.String(): "FATAL2", - plog.SeverityNumberFatal3.String(): "FATAL3", - plog.SeverityNumberFatal4.String(): "FATAL4", -} - -func getFormatFromFormatHint(logAttr pcommon.Map, resourceAttr pcommon.Map) string { - format := formatJSON - formatVal, found := resourceAttr.Get(hintFormat) - if !found { - formatVal, found = logAttr.Get(hintFormat) - } - - if found { - format = formatVal.AsString() - } - return format -} diff --git a/component/otelcol/exporter/loki/internal/convert/convert_loki.go b/component/otelcol/exporter/loki/internal/convert/convert_loki.go deleted file mode 100644 index 916203d7b66d..000000000000 --- a/component/otelcol/exporter/loki/internal/convert/convert_loki.go +++ /dev/null @@ -1,175 +0,0 @@ -package convert - -// This file is a near copy of -// https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/v0.63.0/pkg/translator/loki/convert.go -// -// A copy was made because the upstream package contains some unexported -// definitions. If they're ever made public, our copy can be removed. -// -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import ( - "fmt" - "strings" - "time" - - "github.com/grafana/loki/pkg/logproto" - "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/loki" - "github.com/prometheus/common/model" - "go.opentelemetry.io/collector/pdata/pcommon" - "go.opentelemetry.io/collector/pdata/plog" -) - -const ( - hintAttributes = "loki.attribute.labels" - hintResources = "loki.resource.labels" - hintTenant = "loki.tenant" - hintFormat = "loki.format" - levelAttributeName = "level" -) - -const ( - formatJSON string = "json" - formatLogfmt string = "logfmt" -) - -var defaultExporterLabels = model.LabelSet{"exporter": "OTLP"} -var timeNow = time.Now - -func convertAttributesAndMerge(logAttrs pcommon.Map, resAttrs pcommon.Map) model.LabelSet { - out := defaultExporterLabels - - if resourcesToLabel, found := resAttrs.Get(hintResources); found { - labels := convertAttributesToLabels(resAttrs, resourcesToLabel) - out = out.Merge(labels) - } - - // get the hint from the log attributes, not from the resource - // the value can be a single resource name to use as label - // or a slice of string values - if resourcesToLabel, found := logAttrs.Get(hintResources); found { - labels := convertAttributesToLabels(resAttrs, resourcesToLabel) - out = out.Merge(labels) - } - - if attributesToLabel, found := logAttrs.Get(hintAttributes); found { - labels := convertAttributesToLabels(logAttrs, attributesToLabel) - out = out.Merge(labels) - } - - // get tenant hint from resource attributes, fallback to record attributes - // if it is not found - if resourcesToLabel, found := resAttrs.Get(hintTenant); !found { - if attributesToLabel, found := logAttrs.Get(hintTenant); found { - labels := convertAttributesToLabels(logAttrs, attributesToLabel) - out = out.Merge(labels) - } - } else { - labels := convertAttributesToLabels(resAttrs, resourcesToLabel) - out = out.Merge(labels) - } - - return out -} - -func convertAttributesToLabels(attributes pcommon.Map, attrsToSelect pcommon.Value) model.LabelSet { - out := model.LabelSet{} - - attrs := parseAttributeNames(attrsToSelect) - for _, attr := range attrs { - attr = strings.TrimSpace(attr) - av, ok := attributes.Get(attr) // do we need to trim this? - if ok { - out[model.LabelName(attr)] = model.LabelValue(av.AsString()) - } - } - - return out -} - -func parseAttributeNames(attrsToSelect pcommon.Value) []string { - var out []string - - switch attrsToSelect.Type() { - case pcommon.ValueTypeStr: - out = strings.Split(attrsToSelect.AsString(), ",") - case pcommon.ValueTypeSlice: - as := attrsToSelect.Slice().AsRaw() - for _, a := range as { - out = append(out, fmt.Sprintf("%v", a)) - } - default: - // trying to make the most of bad data - out = append(out, attrsToSelect.AsString()) - } - - return out -} - -func removeAttributes(attrs pcommon.Map, labels model.LabelSet) { - attrs.RemoveIf(func(s string, v pcommon.Value) bool { - if s == hintAttributes || s == hintResources || s == hintTenant || s == hintFormat { - return true - } - - _, exists := labels[model.LabelName(s)] - return exists - }) -} - -func convertLogToJSONEntry(lr plog.LogRecord, res pcommon.Resource, scope pcommon.InstrumentationScope) (*logproto.Entry, error) { - line, err := loki.Encode(lr, res, scope) - if err != nil { - return nil, err - } - return &logproto.Entry{ - Timestamp: timestampFromLogRecord(lr), - Line: line, - }, nil -} - -func convertLogToLogfmtEntry(lr plog.LogRecord, res pcommon.Resource, scope pcommon.InstrumentationScope) (*logproto.Entry, error) { - line, err := loki.EncodeLogfmt(lr, res, scope) - if err != nil { - return nil, err - } - return &logproto.Entry{ - Timestamp: timestampFromLogRecord(lr), - Line: line, - }, nil -} - -func convertLogToLokiEntry(lr plog.LogRecord, res pcommon.Resource, format string, scope pcommon.InstrumentationScope) (*logproto.Entry, error) { - switch format { - case formatJSON: - return convertLogToJSONEntry(lr, res, scope) - case formatLogfmt: - return convertLogToLogfmtEntry(lr, res, scope) - default: - return nil, fmt.Errorf("invalid format %s. Expected one of: %s, %s", format, formatJSON, formatLogfmt) - } -} - -func timestampFromLogRecord(lr plog.LogRecord) time.Time { - if lr.Timestamp() != 0 { - return time.Unix(0, int64(lr.Timestamp())) - } - - if lr.ObservedTimestamp() != 0 { - return time.Unix(0, int64(lr.ObservedTimestamp())) - } - - return time.Unix(0, int64(pcommon.NewTimestampFromTime(timeNow()))) -} diff --git a/component/otelcol/exporter/loki/internal/convert/convert_test.go b/component/otelcol/exporter/loki/internal/convert/convert_test.go deleted file mode 100644 index 840d4a5e903a..000000000000 --- a/component/otelcol/exporter/loki/internal/convert/convert_test.go +++ /dev/null @@ -1,481 +0,0 @@ -package convert_test - -import ( - "context" - "testing" - "time" - - "github.com/grafana/agent/component/common/loki" - "github.com/grafana/agent/component/otelcol/exporter/loki/internal/convert" - "github.com/grafana/agent/pkg/util" - "github.com/prometheus/client_golang/prometheus" - "github.com/stretchr/testify/require" - "go.opentelemetry.io/collector/pdata/plog" -) - -func TestConverter(t *testing.T) { - tt := []struct { - name string - input string - expectLine string - expectLabels string - expectTimestamp time.Time - }{ - { - name: "log line without format hint", - input: `{ - "resourceLogs": [ - { - "resource": { - "attributes": [ - { - "key": "host.name", - "value": { - "stringValue": "testHost" - } - } - ], - "droppedAttributesCount": 1 - }, - "scopeLogs": [ - { - "scope": { - "name": "name", - "version": "version", - "droppedAttributesCount": 1 - }, - "logRecords": [ - { - "timeUnixNano": "1672827031972869000", - "observedTimeUnixNano": "1672827031972869000", - "severityNumber": 17, - "severityText": "Error", - "body": { - "stringValue": "hello world" - }, - "attributes": [ - { - "key": "sdkVersion", - "value": { - "stringValue": "1.0.1" - } - } - ], - "droppedAttributesCount": 1, - "traceId": "0102030405060708090a0b0c0d0e0f10", - "spanId": "1112131415161718" - } - ], - "schemaUrl": "ScopeLogsSchemaURL" - } - ], - "schemaUrl": "testSchemaURL" - } - ] -}`, - expectLine: `{"body":"hello world","traceid":"0102030405060708090a0b0c0d0e0f10","spanid":"1112131415161718","severity":"Error","attributes":{"sdkVersion":"1.0.1"},"resources":{"host.name":"testHost"},"instrumentation_scope":{"name":"name","version":"version"}}`, - expectLabels: `{exporter="OTLP", level="ERROR"}`, - expectTimestamp: time.Date(2023, time.January, 4, 10, 10, 31, 972869000, time.UTC), - }, - { - name: "log line with logfmt format hint in resource attributes", - input: `{ - "resourceLogs": [ - { - "resource": { - "attributes": [ - { - "key": "host.name", - "value": { - "stringValue": "testHost" - } - }, - { - "key": "loki.format", - "value": { - "stringValue": "logfmt" - } - } - ], - "droppedAttributesCount": 1 - }, - "scopeLogs": [ - { - "scope": { - "name": "name", - "version": "version", - "droppedAttributesCount": 1 - }, - "logRecords": [ - { - "timeUnixNano": "1672827031972869000", - "observedTimeUnixNano": "1672827031972869000", - "severityNumber": 17, - "severityText": "Error", - "body": { - "stringValue": "msg=\"hello world\"" - }, - "attributes": [ - { - "key": "sdkVersion", - "value": { - "stringValue": "1.0.1" - } - } - ], - "droppedAttributesCount": 1, - "traceId": "0102030405060708090a0b0c0d0e0f10", - "spanId": "1112131415161718" - } - ], - "schemaUrl": "ScopeLogsSchemaURL" - } - ], - "schemaUrl": "testSchemaURL" - } - ] -}`, - expectLine: `msg="hello world" traceID=0102030405060708090a0b0c0d0e0f10 spanID=1112131415161718 severity=Error attribute_sdkVersion=1.0.1 resource_host.name=testHost instrumentation_scope_name=name instrumentation_scope_version=version`, - expectLabels: `{exporter="OTLP", level="ERROR"}`, - expectTimestamp: time.Date(2023, time.January, 4, 10, 10, 31, 972869000, time.UTC), - }, - { - name: "log line with logfmt format hint in log attributes", - input: `{ - "resourceLogs": [ - { - "resource": { - "attributes": [ - { - "key": "host.name", - "value": { - "stringValue": "testHost" - } - } - ], - "droppedAttributesCount": 1 - }, - "scopeLogs": [ - { - "scope": { - "name": "name", - "version": "version", - "droppedAttributesCount": 1 - }, - "logRecords": [ - { - "timeUnixNano": "1672827031972869000", - "observedTimeUnixNano": "1672827031972869000", - "severityNumber": 17, - "severityText": "Error", - "body": { - "stringValue": "msg=\"hello world\"" - }, - "attributes": [ - { - "key": "sdkVersion", - "value": { - "stringValue": "1.0.1" - } - }, - { - "key": "loki.format", - "value": { - "stringValue": "logfmt" - } - } - ], - "droppedAttributesCount": 1, - "traceId": "0102030405060708090a0b0c0d0e0f10", - "spanId": "1112131415161718" - } - ], - "schemaUrl": "ScopeLogsSchemaURL" - } - ], - "schemaUrl": "testSchemaURL" - } - ] -}`, - expectLine: `msg="hello world" traceID=0102030405060708090a0b0c0d0e0f10 spanID=1112131415161718 severity=Error attribute_sdkVersion=1.0.1 resource_host.name=testHost instrumentation_scope_name=name instrumentation_scope_version=version`, - expectLabels: `{exporter="OTLP", level="ERROR"}`, - expectTimestamp: time.Date(2023, time.January, 4, 10, 10, 31, 972869000, time.UTC), - }, - { - name: "resource attributes converted to labels", - input: `{ - "resourceLogs": [ - { - "resource": { - "attributes": [ - { - "key": "host.name", - "value": { - "stringValue": "testHost" - } - }, - { - "key": "loki.resource.labels", - "value": { - "stringValue": "mylabel_1,mylabel_2" - } - }, - { - "key": "mylabel_1", - "value": { - "stringValue": "value_1" - } - }, - { - "key": "mylabel_2", - "value": { - "intValue": "42" - } - }, - { - "key": "mylabel_3", - "value": { - "stringValue": "value_3" - } - } - ], - "droppedAttributesCount": 1 - }, - "scopeLogs": [ - { - "scope": { - "name": "name", - "version": "version", - "droppedAttributesCount": 1 - }, - "logRecords": [ - { - "timeUnixNano": "1672827031972869000", - "observedTimeUnixNano": "1672827031972869000", - "severityNumber": 17, - "severityText": "Error", - "body": { - "stringValue": "msg=\"hello world\"" - }, - "attributes": [ - { - "key": "sdkVersion", - "value": { - "stringValue": "1.0.1" - } - }, - { - "key": "loki.format", - "value": { - "stringValue": "logfmt" - } - } - ], - "droppedAttributesCount": 1, - "traceId": "0102030405060708090a0b0c0d0e0f10", - "spanId": "1112131415161718" - } - ], - "schemaUrl": "ScopeLogsSchemaURL" - } - ], - "schemaUrl": "testSchemaURL" - } - ] -}`, - expectLine: `msg="hello world" traceID=0102030405060708090a0b0c0d0e0f10 spanID=1112131415161718 severity=Error attribute_sdkVersion=1.0.1 resource_host.name=testHost resource_mylabel_3=value_3 instrumentation_scope_name=name instrumentation_scope_version=version`, - expectLabels: `{exporter="OTLP", level="ERROR", mylabel_1="value_1", mylabel_2="42"}`, - expectTimestamp: time.Date(2023, time.January, 4, 10, 10, 31, 972869000, time.UTC), - }, - { - name: "log attributes converted to labels", - input: `{ - "resourceLogs": [ - { - "resource": { - "attributes": [ - { - "key": "host.name", - "value": { - "stringValue": "testHost" - } - } - ], - "droppedAttributesCount": 1 - }, - "scopeLogs": [ - { - "scope": { - "name": "name", - "version": "version", - "droppedAttributesCount": 1 - }, - "logRecords": [ - { - "timeUnixNano": "1672827031972869000", - "observedTimeUnixNano": "1672827031972869000", - "severityNumber": 17, - "severityText": "Error", - "body": { - "stringValue": "msg=\"hello world\"" - }, - "attributes": [ - { - "key": "sdkVersion", - "value": { - "stringValue": "1.0.1" - } - }, - { - "key": "loki.format", - "value": { - "stringValue": "logfmt" - } - }, - { - "key": "loki.attribute.labels", - "value": { - "stringValue": "mylabel_1,mylabel_2" - } - }, - { - "key": "mylabel_1", - "value": { - "stringValue": "value_1" - } - }, - { - "key": "mylabel_2", - "value": { - "intValue": "42" - } - }, - { - "key": "mylabel_3", - "value": { - "stringValue": "value_3" - } - } - ], - "droppedAttributesCount": 1, - "traceId": "0102030405060708090a0b0c0d0e0f10", - "spanId": "1112131415161718" - } - ], - "schemaUrl": "ScopeLogsSchemaURL" - } - ], - "schemaUrl": "testSchemaURL" - } - ] -}`, - expectLine: `msg="hello world" traceID=0102030405060708090a0b0c0d0e0f10 spanID=1112131415161718 severity=Error attribute_sdkVersion=1.0.1 attribute_mylabel_3=value_3 resource_host.name=testHost instrumentation_scope_name=name instrumentation_scope_version=version`, - expectLabels: `{exporter="OTLP", level="ERROR", mylabel_1="value_1", mylabel_2="42"}`, - expectTimestamp: time.Date(2023, time.January, 4, 10, 10, 31, 972869000, time.UTC), - }, - { - name: "tenant resource attribute converted to label", - input: `{ - "resourceLogs": [ - { - "resource": { - "attributes": [ - { - "key": "host.name", - "value": { - "stringValue": "testHost" - } - } - ], - "droppedAttributesCount": 1 - }, - "scopeLogs": [ - { - "scope": { - "name": "name", - "version": "version", - "droppedAttributesCount": 1 - }, - "logRecords": [ - { - "timeUnixNano": "1672827031972869000", - "observedTimeUnixNano": "1672827031972869000", - "severityNumber": 17, - "severityText": "Error", - "body": { - "stringValue": "hello world" - }, - "attributes": [ - { - "key": "sdkVersion", - "value": { - "stringValue": "1.0.1" - } - }, - { - "key": "loki.format", - "value": { - "stringValue": "json" - } - }, - { - "key": "loki.tenant", - "value": { - "stringValue": "tenant.id" - } - }, - { - "key": "tenant.id", - "value": { - "stringValue": "tenant_2" - } - } - ], - "droppedAttributesCount": 1, - "traceId": "0102030405060708090a0b0c0d0e0f10", - "spanId": "1112131415161718" - } - ], - "schemaUrl": "ScopeLogsSchemaURL" - } - ], - "schemaUrl": "testSchemaURL" - } - ] -}`, - expectLine: `{"body":"hello world","traceid":"0102030405060708090a0b0c0d0e0f10","spanid":"1112131415161718","severity":"Error","attributes":{"sdkVersion":"1.0.1"},"resources":{"host.name":"testHost"},"instrumentation_scope":{"name":"name","version":"version"}}`, - expectLabels: `{exporter="OTLP", level="ERROR", tenant.id="tenant_2"}`, - expectTimestamp: time.Date(2023, time.January, 4, 10, 10, 31, 972869000, time.UTC), - }, - } - - decoder := &plog.JSONUnmarshaler{} - for _, tc := range tt { - t.Run(tc.name, func(t *testing.T) { - payload, err := decoder.UnmarshalLogs([]byte(tc.input)) - require.NoError(t, err) - - l := util.TestLogger(t) - ch1, ch2 := make(loki.LogsReceiver), make(loki.LogsReceiver) - conv := convert.New(l, prometheus.NewRegistry(), []loki.LogsReceiver{ch1, ch2}) - go func() { - require.NoError(t, conv.ConsumeLogs(context.Background(), payload)) - }() - - for i := 0; i < 2; i++ { - select { - case l := <-ch1: - require.Equal(t, tc.expectLine, l.Line) - require.Equal(t, tc.expectLabels, l.Labels.String()) - require.Equal(t, tc.expectTimestamp, l.Timestamp.UTC()) - case l := <-ch2: - require.Equal(t, tc.expectLine, l.Line) - require.Equal(t, tc.expectLabels, l.Labels.String()) - require.Equal(t, tc.expectTimestamp, l.Timestamp.UTC()) - case <-time.After(time.Second): - require.FailNow(t, "failed waiting for logs") - } - } - }) - } -} diff --git a/component/otelcol/exporter/otlp/otlp.go b/component/otelcol/exporter/otlp/otlp.go index b42ab78f0bae..baf3240af5e2 100644 --- a/component/otelcol/exporter/otlp/otlp.go +++ b/component/otelcol/exporter/otlp/otlp.go @@ -8,7 +8,6 @@ import ( "github.com/grafana/agent/component/otelcol" "github.com/grafana/agent/component/otelcol/exporter" otelcomponent "go.opentelemetry.io/collector/component" - "go.opentelemetry.io/collector/config/configopaque" otelpexporterhelper "go.opentelemetry.io/collector/exporter/exporterhelper" "go.opentelemetry.io/collector/exporter/otlpexporter" otelextension "go.opentelemetry.io/collector/extension" @@ -83,7 +82,7 @@ type GRPCClientArguments otelcol.GRPCClientArguments // DefaultGRPCClientArguments holds component-specific default settings for // GRPCClientArguments. var DefaultGRPCClientArguments = GRPCClientArguments{ - Headers: map[string]configopaque.String{}, + Headers: map[string]string{}, Compression: otelcol.CompressionTypeGzip, WriteBufferSize: 512 * 1024, } diff --git a/component/otelcol/exporter/otlphttp/otlphttp.go b/component/otelcol/exporter/otlphttp/otlphttp.go index fc06f6c08162..8d6e9fc23c3f 100644 --- a/component/otelcol/exporter/otlphttp/otlphttp.go +++ b/component/otelcol/exporter/otlphttp/otlphttp.go @@ -9,7 +9,6 @@ import ( "github.com/grafana/agent/component/otelcol" "github.com/grafana/agent/component/otelcol/exporter" otelcomponent "go.opentelemetry.io/collector/component" - "go.opentelemetry.io/collector/config/configopaque" "go.opentelemetry.io/collector/exporter/otlphttpexporter" otelextension "go.opentelemetry.io/collector/extension" ) @@ -98,7 +97,7 @@ var ( IdleConnTimeout: &DefaultIdleConnTimeout, Timeout: 30 * time.Second, - Headers: map[string]configopaque.String{}, + Headers: map[string]string{}, Compression: otelcol.CompressionTypeGzip, ReadBufferSize: 0, WriteBufferSize: 512 * 1024, diff --git a/component/otelcol/receiver/prometheus/internal/prom_to_otlp_test.go b/component/otelcol/receiver/prometheus/internal/prom_to_otlp_test.go index 5612479e4b5f..63f167ca5363 100644 --- a/component/otelcol/receiver/prometheus/internal/prom_to_otlp_test.go +++ b/component/otelcol/receiver/prometheus/internal/prom_to_otlp_test.go @@ -283,8 +283,6 @@ func TestCreateNodeAndResourcePromToOTLP(t *testing.T) { tt := tt t.Run(tt.name, func(t *testing.T) { got := CreateResource(tt.job, tt.instance, tt.sdLabels) - // It is no longer possible ot sort the attributes. For comparisons in tests we now use AsRaw(): - // https://github.com/open-telemetry/opentelemetry-collector/pull/6989 require.Equal(t, tt.want.Attributes().AsRaw(), got.Attributes().AsRaw()) require.Equal(t, tt.want.DroppedAttributesCount(), got.DroppedAttributesCount()) }) diff --git a/component/otelcol/receiver/prometheus/internal/transaction_test.go b/component/otelcol/receiver/prometheus/internal/transaction_test.go index 58db6fe02bb0..deb47ff989d5 100644 --- a/component/otelcol/receiver/prometheus/internal/transaction_test.go +++ b/component/otelcol/receiver/prometheus/internal/transaction_test.go @@ -61,33 +61,25 @@ var ( ) func TestTransactionCommitWithoutAdding(t *testing.T) { - recv, err := nopObsRecv() - assert.NoError(t, err) - tr := newTransaction(scrapeCtx, &startTimeAdjuster{startTime: startTimestamp}, consumertest.NewNop(), nil, receivertest.NewNopCreateSettings(), recv) + tr := newTransaction(scrapeCtx, &startTimeAdjuster{startTime: startTimestamp}, consumertest.NewNop(), nil, receivertest.NewNopCreateSettings(), nopObsRecv(t)) assert.NoError(t, tr.Commit()) } func TestTransactionRollbackDoesNothing(t *testing.T) { - recv, err := nopObsRecv() - assert.NoError(t, err) - tr := newTransaction(scrapeCtx, &startTimeAdjuster{startTime: startTimestamp}, consumertest.NewNop(), nil, receivertest.NewNopCreateSettings(), recv) + tr := newTransaction(scrapeCtx, &startTimeAdjuster{startTime: startTimestamp}, consumertest.NewNop(), nil, receivertest.NewNopCreateSettings(), nopObsRecv(t)) assert.NoError(t, tr.Rollback()) } func TestTransactionUpdateMetadataDoesNothing(t *testing.T) { - recv, err := nopObsRecv() - assert.NoError(t, err) - tr := newTransaction(scrapeCtx, &startTimeAdjuster{startTime: startTimestamp}, consumertest.NewNop(), nil, receivertest.NewNopCreateSettings(), recv) - _, err = tr.UpdateMetadata(0, labels.New(), metadata.Metadata{}) + tr := newTransaction(scrapeCtx, &startTimeAdjuster{startTime: startTimestamp}, consumertest.NewNop(), nil, receivertest.NewNopCreateSettings(), nopObsRecv(t)) + _, err := tr.UpdateMetadata(0, labels.New(), metadata.Metadata{}) assert.NoError(t, err) } func TestTransactionAppendNoTarget(t *testing.T) { - recv, err := nopObsRecv() - assert.NoError(t, err) badLabels := labels.FromStrings(model.MetricNameLabel, "counter_test") - tr := newTransaction(scrapeCtx, &startTimeAdjuster{startTime: startTimestamp}, consumertest.NewNop(), nil, receivertest.NewNopCreateSettings(), recv) - _, err = tr.Append(0, badLabels, time.Now().Unix()*1000, 1.0) + tr := newTransaction(scrapeCtx, &startTimeAdjuster{startTime: startTimestamp}, consumertest.NewNop(), nil, receivertest.NewNopCreateSettings(), nopObsRecv(t)) + _, err := tr.Append(0, badLabels, time.Now().Unix()*1000, 1.0) assert.Error(t, err) } @@ -96,20 +88,16 @@ func TestTransactionAppendNoMetricName(t *testing.T) { model.InstanceLabel: "localhost:8080", model.JobLabel: "test2", }) - recv, err := nopObsRecv() - assert.NoError(t, err) - tr := newTransaction(scrapeCtx, &startTimeAdjuster{startTime: startTimestamp}, consumertest.NewNop(), nil, receivertest.NewNopCreateSettings(), recv) - _, err = tr.Append(0, jobNotFoundLb, time.Now().Unix()*1000, 1.0) + tr := newTransaction(scrapeCtx, &startTimeAdjuster{startTime: startTimestamp}, consumertest.NewNop(), nil, receivertest.NewNopCreateSettings(), nopObsRecv(t)) + _, err := tr.Append(0, jobNotFoundLb, time.Now().Unix()*1000, 1.0) assert.ErrorIs(t, err, errMetricNameNotFound) assert.ErrorIs(t, tr.Commit(), errNoDataToBuild) } func TestTransactionAppendEmptyMetricName(t *testing.T) { - recv, err := nopObsRecv() - assert.NoError(t, err) - tr := newTransaction(scrapeCtx, &startTimeAdjuster{startTime: startTimestamp}, consumertest.NewNop(), nil, receivertest.NewNopCreateSettings(), recv) - _, err = tr.Append(0, labels.FromMap(map[string]string{ + tr := newTransaction(scrapeCtx, &startTimeAdjuster{startTime: startTimestamp}, consumertest.NewNop(), nil, receivertest.NewNopCreateSettings(), nopObsRecv(t)) + _, err := tr.Append(0, labels.FromMap(map[string]string{ model.InstanceLabel: "localhost:8080", model.JobLabel: "test2", model.MetricNameLabel: "", @@ -119,10 +107,8 @@ func TestTransactionAppendEmptyMetricName(t *testing.T) { func TestTransactionAppendResource(t *testing.T) { sink := new(consumertest.MetricsSink) - recv, err := nopObsRecv() - assert.NoError(t, err) - tr := newTransaction(scrapeCtx, &startTimeAdjuster{startTime: startTimestamp}, sink, nil, receivertest.NewNopCreateSettings(), recv) - _, err = tr.Append(0, labels.FromMap(map[string]string{ + tr := newTransaction(scrapeCtx, &startTimeAdjuster{startTime: startTimestamp}, sink, nil, receivertest.NewNopCreateSettings(), nopObsRecv(t)) + _, err := tr.Append(0, labels.FromMap(map[string]string{ model.InstanceLabel: "localhost:8080", model.JobLabel: "test", model.MetricNameLabel: "counter_test", @@ -150,10 +136,8 @@ func TestTransactionCommitErrorWhenAdjusterError(t *testing.T) { }) sink := new(consumertest.MetricsSink) adjusterErr := errors.New("adjuster error") - recv, err := nopObsRecv() - assert.NoError(t, err) - tr := newTransaction(scrapeCtx, &errorAdjuster{err: adjusterErr}, sink, nil, receivertest.NewNopCreateSettings(), recv) - _, err = tr.Append(0, goodLabels, time.Now().Unix()*1000, 1.0) + tr := newTransaction(scrapeCtx, &errorAdjuster{err: adjusterErr}, sink, nil, receivertest.NewNopCreateSettings(), nopObsRecv(t)) + _, err := tr.Append(0, goodLabels, time.Now().Unix()*1000, 1.0) assert.NoError(t, err) assert.ErrorIs(t, tr.Commit(), adjusterErr) } @@ -161,9 +145,7 @@ func TestTransactionCommitErrorWhenAdjusterError(t *testing.T) { // Ensure that we reject duplicate label keys. See https://github.com/open-telemetry/wg-prometheus/issues/44. func TestTransactionAppendDuplicateLabels(t *testing.T) { sink := new(consumertest.MetricsSink) - recv, err := nopObsRecv() - assert.NoError(t, err) - tr := newTransaction(scrapeCtx, &startTimeAdjuster{startTime: startTimestamp}, sink, nil, receivertest.NewNopCreateSettings(), recv) + tr := newTransaction(scrapeCtx, &startTimeAdjuster{startTime: startTimestamp}, sink, nil, receivertest.NewNopCreateSettings(), nopObsRecv(t)) dupLabels := labels.FromStrings( model.InstanceLabel, "0.0.0.0:8855", @@ -174,16 +156,14 @@ func TestTransactionAppendDuplicateLabels(t *testing.T) { "z", "9", ) - _, err = tr.Append(0, dupLabels, 1917, 1.0) + _, err := tr.Append(0, dupLabels, 1917, 1.0) require.Error(t, err) assert.Contains(t, err.Error(), `invalid sample: non-unique label names: "a"`) } func TestTransactionAppendHistogramNoLe(t *testing.T) { sink := new(consumertest.MetricsSink) - recv, err := nopObsRecv() - assert.NoError(t, err) - tr := newTransaction(scrapeCtx, &startTimeAdjuster{startTime: startTimestamp}, sink, nil, receivertest.NewNopCreateSettings(), recv) + tr := newTransaction(scrapeCtx, &startTimeAdjuster{startTime: startTimestamp}, sink, nil, receivertest.NewNopCreateSettings(), nopObsRecv(t)) goodLabels := labels.FromStrings( model.InstanceLabel, "0.0.0.0:8855", @@ -191,15 +171,13 @@ func TestTransactionAppendHistogramNoLe(t *testing.T) { model.MetricNameLabel, "hist_test_bucket", ) - _, err = tr.Append(0, goodLabels, 1917, 1.0) + _, err := tr.Append(0, goodLabels, 1917, 1.0) require.ErrorIs(t, err, errEmptyLeLabel) } func TestTransactionAppendSummaryNoQuantile(t *testing.T) { sink := new(consumertest.MetricsSink) - recv, err := nopObsRecv() - assert.NoError(t, err) - tr := newTransaction(scrapeCtx, &startTimeAdjuster{startTime: startTimestamp}, sink, nil, receivertest.NewNopCreateSettings(), recv) + tr := newTransaction(scrapeCtx, &startTimeAdjuster{startTime: startTimestamp}, sink, nil, receivertest.NewNopCreateSettings(), nopObsRecv(t)) goodLabels := labels.FromStrings( model.InstanceLabel, "0.0.0.0:8855", @@ -207,16 +185,19 @@ func TestTransactionAppendSummaryNoQuantile(t *testing.T) { model.MetricNameLabel, "summary_test", ) - _, err = tr.Append(0, goodLabels, 1917, 1.0) + _, err := tr.Append(0, goodLabels, 1917, 1.0) require.ErrorIs(t, err, errEmptyQuantileLabel) } -func nopObsRecv() (*obsreport.Receiver, error) { - return obsreport.NewReceiver(obsreport.ReceiverSettings{ +func nopObsRecv(t *testing.T) *obsreport.Receiver { + res, err := obsreport.NewReceiver(obsreport.ReceiverSettings{ ReceiverID: component.NewID("prometheus"), Transport: transport, ReceiverCreateSettings: receivertest.NewNopCreateSettings(), }) + + assert.NoError(t, err) + return res } func TestMetricBuilderCounters(t *testing.T) { @@ -1047,9 +1028,7 @@ func (tt buildTestData) run(t *testing.T) { st := ts for i, page := range tt.inputs { sink := new(consumertest.MetricsSink) - recv, err := nopObsRecv() - assert.NoError(t, err) - tr := newTransaction(scrapeCtx, &startTimeAdjuster{startTime: startTimestamp}, sink, nil, receivertest.NewNopCreateSettings(), recv) + tr := newTransaction(scrapeCtx, &startTimeAdjuster{startTime: startTimestamp}, sink, nil, receivertest.NewNopCreateSettings(), nopObsRecv(t)) for _, pt := range page.pts { // set ts for testing pt.t = st diff --git a/docs/sources/flow/reference/components/otelcol.auth.bearer.md b/docs/sources/flow/reference/components/otelcol.auth.bearer.md index eefd25c13fb1..a3dd7a32381a 100644 --- a/docs/sources/flow/reference/components/otelcol.auth.bearer.md +++ b/docs/sources/flow/reference/components/otelcol.auth.bearer.md @@ -51,14 +51,14 @@ configuration. `otelcol.auth.bearer` does not expose any component-specific debug information. -## Example +## Examples ### Default scheme via gRPC transport The example below configures [otelcol.exporter.otlp][] to use a bearer token authentication. -If we assume that the value of the `API_KEY` environment variable is `SECRET_API_KEY`, then -the `Authorization` RPC metadata will be set to `Bearer SECRET_API_KEY`. +If we assume that the value of the `API_KEY` environment variable is `SECRET_API_KEY`, then +the `Authorization` RPC metadata is set to `Bearer SECRET_API_KEY`. ```river otelcol.exporter.otlp "example" { @@ -77,8 +77,8 @@ otelcol.auth.bearer "creds" { The example below configures [otelcol.exporter.otlphttp][] to use a bearer token authentication. -If we assume that the value of the `API_KEY` environment variable is `SECRET_API_KEY`, then -the `Authorization` HTTP header will be set to `MyScheme SECRET_API_KEY`. +If we assume that the value of the `API_KEY` environment variable is `SECRET_API_KEY`, then +the `Authorization` HTTP header is set to `MyScheme SECRET_API_KEY`. ```river otelcol.exporter.otlphttp "example" { diff --git a/pkg/traces/instance.go b/pkg/traces/instance.go index 2e6950f07d17..6e92d43bab80 100644 --- a/pkg/traces/instance.go +++ b/pkg/traces/instance.go @@ -132,6 +132,20 @@ func (i *Instance) buildAndStartPipeline(ctx context.Context, cfg InstanceConfig Version: build.Version, } + // useOtelForInternalMetrics is required so that the Collector service configures Collector components using the Otel SDK + // instead of OpenCensus. If this is not specified, then the OtelMetricViews and OtelMetricReader parameters which we + // pass to service.New() below will not be taken into account. This would mean that metrics from custom components such as + // the one in pkg/traces/servicegraphprocessor would not work. + // + // disableHighCardinalityMetrics is required so that we don't include labels containing ports and IP addresses in gRPC metrics. + // Example metric with high cardinality... + // rpc_server_duration_bucket{net_sock_peer_addr="127.0.0.1",net_sock_peer_port="59947",rpc_grpc_status_code="0",rpc_method="Export",rpc_service="opentelemetry.proto.collector.trace.v1.TraceService",rpc_system="grpc",traces_config="default",le="7500"} 294 + // ... the same metric when disableHighCardinalityMetrics is switched on looks like this: + // rpc_server_duration_bucket{rpc_grpc_status_code="0",rpc_method="Export",rpc_service="opentelemetry.proto.collector.trace.v1.TraceService",rpc_system="grpc",traces_config="default",le="7500"} 32 + // For more context: + // https://opentelemetry.io/docs/specs/otel/metrics/semantic_conventions/rpc-metrics/ + // https://github.com/open-telemetry/opentelemetry-go-contrib/pull/2700 + // https://github.com/open-telemetry/opentelemetry-collector/pull/6788/files err = enableOtelFeatureGates( "telemetry.useOtelForInternalMetrics", "telemetry.disableHighCardinalityMetrics") @@ -139,7 +153,7 @@ func (i *Instance) buildAndStartPipeline(ctx context.Context, cfg InstanceConfig return err } - promExporter, err := traceutils.PromeheusExporter(reg) + promExporter, err := traceutils.PrometheusExporter(reg) if err != nil { return fmt.Errorf("error creating otel prometheus exporter: %w", err) } diff --git a/pkg/traces/internal/traceutils/otel_meter_settings.go b/pkg/traces/internal/traceutils/otel_meter_settings.go index 2752a30ae66b..b02a3cb07a4a 100644 --- a/pkg/traces/internal/traceutils/otel_meter_settings.go +++ b/pkg/traces/internal/traceutils/otel_meter_settings.go @@ -5,7 +5,7 @@ import ( otelprom "go.opentelemetry.io/otel/exporters/prometheus" ) -func PromeheusExporter(reg prometheus.Registerer) (*otelprom.Exporter, error) { +func PrometheusExporter(reg prometheus.Registerer) (*otelprom.Exporter, error) { return otelprom.New( otelprom.WithRegisterer(reg), otelprom.WithoutUnits(), diff --git a/pkg/traces/servicegraphprocessor/processor_test.go b/pkg/traces/servicegraphprocessor/processor_test.go index 273f6995f962..f9e0d9cb6219 100644 --- a/pkg/traces/servicegraphprocessor/processor_test.go +++ b/pkg/traces/servicegraphprocessor/processor_test.go @@ -109,7 +109,7 @@ func TestConsumeMetrics(t *testing.T) { } func getTestMeterProvider(t *testing.T, reg prometheus.Registerer) *sdkmetric.MeterProvider { - promExporter, err := traceutils.PromeheusExporter(reg) + promExporter, err := traceutils.PrometheusExporter(reg) require.NoError(t, err) mp := sdkmetric.NewMeterProvider(