diff --git a/.chloggen/resourceprocessor-profiles.yaml b/.chloggen/resourceprocessor-profiles.yaml new file mode 100644 index 0000000000000..d3ab06ff9bbd2 --- /dev/null +++ b/.chloggen/resourceprocessor-profiles.yaml @@ -0,0 +1,27 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: resourceprocessor + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: "Introduce support for Profiles signal type." + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [37513] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# If your change doesn't affect end users or the exported elements of any package, +# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [] diff --git a/processor/resourceprocessor/README.md b/processor/resourceprocessor/README.md index 19c93b68acdf9..8d1ce0ff6df8e 100644 --- a/processor/resourceprocessor/README.md +++ b/processor/resourceprocessor/README.md @@ -3,11 +3,13 @@ | Status | | | ------------- |-----------| -| Stability | [beta]: traces, metrics, logs | +| Stability | [development]: profiles | +| | [beta]: traces, metrics, logs | | Distributions | [core], [contrib], [k8s] | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aopen%20label%3Aprocessor%2Fresource%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Aprocessor%2Fresource) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aclosed%20label%3Aprocessor%2Fresource%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aclosed+is%3Aissue+label%3Aprocessor%2Fresource) | | [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@dmitryax](https://www.github.com/dmitryax) | +[development]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#development [beta]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#beta [core]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol [contrib]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib diff --git a/processor/resourceprocessor/factory.go b/processor/resourceprocessor/factory.go index 69ec5220b17ad..8748150a0b43f 100644 --- a/processor/resourceprocessor/factory.go +++ b/processor/resourceprocessor/factory.go @@ -8,8 +8,11 @@ import ( "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" + "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/processorhelper" + "go.opentelemetry.io/collector/processor/processorhelper/xprocessorhelper" + "go.opentelemetry.io/collector/processor/xprocessor" "github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal/attraction" "github.com/open-telemetry/opentelemetry-collector-contrib/processor/resourceprocessor/internal/metadata" @@ -19,12 +22,13 @@ var processorCapabilities = consumer.Capabilities{MutatesData: true} // NewFactory returns a new factory for the Resource processor. func NewFactory() processor.Factory { - return processor.NewFactory( + return xprocessor.NewFactory( metadata.Type, createDefaultConfig, - processor.WithTraces(createTracesProcessor, metadata.TracesStability), - processor.WithMetrics(createMetricsProcessor, metadata.MetricsStability), - processor.WithLogs(createLogsProcessor, metadata.LogsStability)) + xprocessor.WithTraces(createTracesProcessor, metadata.TracesStability), + xprocessor.WithMetrics(createMetricsProcessor, metadata.MetricsStability), + xprocessor.WithLogs(createLogsProcessor, metadata.LogsStability), + xprocessor.WithProfiles(createProfilesProcessor, metadata.ProfilesStability)) } // Note: This isn't a valid configuration because the processor would do no work. @@ -91,3 +95,23 @@ func createLogsProcessor( proc.processLogs, processorhelper.WithCapabilities(processorCapabilities)) } + +func createProfilesProcessor( + ctx context.Context, + set processor.Settings, + cfg component.Config, + nextConsumer xconsumer.Profiles, +) (xprocessor.Profiles, error) { + attrProc, err := attraction.NewAttrProc(&attraction.Settings{Actions: cfg.(*Config).AttributesActions}) + if err != nil { + return nil, err + } + proc := &resourceProcessor{logger: set.Logger, attrProc: attrProc} + return xprocessorhelper.NewProfiles( + ctx, + set, + cfg, + nextConsumer, + proc.processProfiles, + xprocessorhelper.WithCapabilities(processorCapabilities)) +} diff --git a/processor/resourceprocessor/go.mod b/processor/resourceprocessor/go.mod index cefa3c99781b8..1d5157781829b 100644 --- a/processor/resourceprocessor/go.mod +++ b/processor/resourceprocessor/go.mod @@ -12,9 +12,13 @@ require ( go.opentelemetry.io/collector/confmap/xconfmap v0.120.1-0.20250226024140-8099e51f9a77 go.opentelemetry.io/collector/consumer v1.26.1-0.20250226024140-8099e51f9a77 go.opentelemetry.io/collector/consumer/consumertest v0.120.1-0.20250226024140-8099e51f9a77 + go.opentelemetry.io/collector/consumer/xconsumer v0.120.1-0.20250226024140-8099e51f9a77 go.opentelemetry.io/collector/pdata v1.26.1-0.20250226024140-8099e51f9a77 + go.opentelemetry.io/collector/pdata/pprofile v0.120.1-0.20250226024140-8099e51f9a77 go.opentelemetry.io/collector/processor v0.120.1-0.20250226024140-8099e51f9a77 + go.opentelemetry.io/collector/processor/processorhelper/xprocessorhelper v0.120.1-0.20250226024140-8099e51f9a77 go.opentelemetry.io/collector/processor/processortest v0.120.1-0.20250226024140-8099e51f9a77 + go.opentelemetry.io/collector/processor/xprocessor v0.120.1-0.20250226024140-8099e51f9a77 go.uber.org/goleak v1.3.0 go.uber.org/zap v1.27.0 ) @@ -40,21 +44,18 @@ require ( go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/collector/client v1.26.1-0.20250226024140-8099e51f9a77 // indirect go.opentelemetry.io/collector/component/componentstatus v0.120.1-0.20250226024140-8099e51f9a77 // indirect - go.opentelemetry.io/collector/consumer/xconsumer v0.120.1-0.20250226024140-8099e51f9a77 // indirect - go.opentelemetry.io/collector/pdata/pprofile v0.120.1-0.20250226024140-8099e51f9a77 // indirect go.opentelemetry.io/collector/pdata/testdata v0.120.1-0.20250226024140-8099e51f9a77 // indirect go.opentelemetry.io/collector/pipeline v0.120.1-0.20250226024140-8099e51f9a77 // indirect - go.opentelemetry.io/collector/processor/xprocessor v0.120.1-0.20250226024140-8099e51f9a77 // indirect go.opentelemetry.io/otel v1.34.0 // indirect go.opentelemetry.io/otel/metric v1.34.0 // indirect go.opentelemetry.io/otel/sdk v1.34.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.34.0 // indirect go.opentelemetry.io/otel/trace v1.34.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/net v0.33.0 // indirect + golang.org/x/net v0.35.0 // indirect golang.org/x/sys v0.30.0 // indirect golang.org/x/text v0.22.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250212204824-5a70512c5d8b // indirect google.golang.org/grpc v1.70.0 // indirect google.golang.org/protobuf v1.36.5 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/processor/resourceprocessor/go.sum b/processor/resourceprocessor/go.sum index 2baf4c487a5e7..c95f9012f64df 100644 --- a/processor/resourceprocessor/go.sum +++ b/processor/resourceprocessor/go.sum @@ -82,6 +82,8 @@ go.opentelemetry.io/collector/pipeline v0.120.1-0.20250226024140-8099e51f9a77 h1 go.opentelemetry.io/collector/pipeline v0.120.1-0.20250226024140-8099e51f9a77/go.mod h1:TO02zju/K6E+oFIOdi372Wk0MXd+Szy72zcTsFQwXl4= go.opentelemetry.io/collector/processor v0.120.1-0.20250226024140-8099e51f9a77 h1:OdaWd0agFemPODKVGvgcJtGH/C5BpVedE7bhehv3kk8= go.opentelemetry.io/collector/processor v0.120.1-0.20250226024140-8099e51f9a77/go.mod h1:4zaJGLZCK8XKChkwlGC/gn0Dj4Yke04gQCu4LGbJGro= +go.opentelemetry.io/collector/processor/processorhelper/xprocessorhelper v0.120.1-0.20250226024140-8099e51f9a77 h1:atI6onBIeJT06OnmWFgEEZ5kTB127bbijNeBul/OuEM= +go.opentelemetry.io/collector/processor/processorhelper/xprocessorhelper v0.120.1-0.20250226024140-8099e51f9a77/go.mod h1:ALMYNJNnGvGEiHrbLHzg4xV3Cjs2Y/V2C2capETsRmY= go.opentelemetry.io/collector/processor/processortest v0.120.1-0.20250226024140-8099e51f9a77 h1:2G96TWC2dyN5ORbhyq7jfwAVnguDAW5+Wez7kr6DLkI= go.opentelemetry.io/collector/processor/processortest v0.120.1-0.20250226024140-8099e51f9a77/go.mod h1:me+IVxPsj4IgK99I0pgKLX34XnJtcLwqtgTuVLhhYDI= go.opentelemetry.io/collector/processor/xprocessor v0.120.1-0.20250226024140-8099e51f9a77 h1:F054v6iLprh8gmkppbYuObtzi++awJ6/b1wN+yI+2J8= @@ -111,8 +113,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -133,8 +135,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a h1:hgh8P4EuoxpsuKMXX/To36nOFD7vixReXgn8lPGnt+o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250212204824-5a70512c5d8b h1:FQtJ1MxbXoIIrZHZ33M+w5+dAP9o86rgpjoKr/ZmT7k= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250212204824-5a70512c5d8b/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk= google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= diff --git a/processor/resourceprocessor/internal/metadata/generated_status.go b/processor/resourceprocessor/internal/metadata/generated_status.go index 9b63270669643..e609844c2a1d5 100644 --- a/processor/resourceprocessor/internal/metadata/generated_status.go +++ b/processor/resourceprocessor/internal/metadata/generated_status.go @@ -12,7 +12,8 @@ var ( ) const ( - TracesStability = component.StabilityLevelBeta - MetricsStability = component.StabilityLevelBeta - LogsStability = component.StabilityLevelBeta + ProfilesStability = component.StabilityLevelDevelopment + TracesStability = component.StabilityLevelBeta + MetricsStability = component.StabilityLevelBeta + LogsStability = component.StabilityLevelBeta ) diff --git a/processor/resourceprocessor/metadata.yaml b/processor/resourceprocessor/metadata.yaml index 51277506c27f8..a46dd2dd7d920 100644 --- a/processor/resourceprocessor/metadata.yaml +++ b/processor/resourceprocessor/metadata.yaml @@ -4,6 +4,7 @@ status: class: processor stability: beta: [traces, metrics, logs] + development: [profiles] distributions: [core, contrib, k8s] codeowners: active: [dmitryax] diff --git a/processor/resourceprocessor/resource_processor.go b/processor/resourceprocessor/resource_processor.go index a7588418415f0..3fed3c6a5f2c9 100644 --- a/processor/resourceprocessor/resource_processor.go +++ b/processor/resourceprocessor/resource_processor.go @@ -8,6 +8,7 @@ import ( "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" + "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/ptrace" "go.uber.org/zap" @@ -42,3 +43,11 @@ func (rp *resourceProcessor) processLogs(ctx context.Context, ld plog.Logs) (plo } return ld, nil } + +func (rp *resourceProcessor) processProfiles(ctx context.Context, pd pprofile.Profiles) (pprofile.Profiles, error) { + rps := pd.ResourceProfiles() + for i := 0; i < rps.Len(); i++ { + rp.attrProc.Process(ctx, rp.logger, rps.At(i).Resource().Attributes()) + } + return pd, nil +} diff --git a/processor/resourceprocessor/resource_processor_test.go b/processor/resourceprocessor/resource_processor_test.go index 4ea74db68cd13..33f1e344ac643 100644 --- a/processor/resourceprocessor/resource_processor_test.go +++ b/processor/resourceprocessor/resource_processor_test.go @@ -12,6 +12,7 @@ import ( "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" + "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/processor/processortest" @@ -19,6 +20,7 @@ import ( "github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal/testdata" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest/plogtest" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest/pmetrictest" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest/pprofiletest" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest/ptracetest" "github.com/open-telemetry/opentelemetry-collector-contrib/processor/resourceprocessor/internal/metadata" ) @@ -130,6 +132,20 @@ func TestResourceProcessorAttributesUpsert(t *testing.T) { logs := tln.AllLogs() require.Len(t, logs, 1) assert.NoError(t, plogtest.CompareLogs(wantLogData, logs[0])) + + // Test profiles consumer + tpn := new(consumertest.ProfilesSink) + rpp, err := createProfilesProcessor(context.Background(), processortest.NewNopSettings(metadata.Type), tt.config, tpn) + require.NoError(t, err) + assert.True(t, rpp.Capabilities().MutatesData) + + sourceProfileData := generateProfileData(tt.sourceAttributes) + wantProfileData := generateProfileData(tt.wantAttributes) + err = rpp.ConsumeProfiles(context.Background(), sourceProfileData) + require.NoError(t, err) + profiles := tpn.AllProfiles() + require.Len(t, profiles, 1) + assert.NoError(t, pprofiletest.CompareProfiles(wantProfileData, profiles[0])) }) } } @@ -169,3 +185,15 @@ func generateLogData(attributes map[string]string) plog.Logs { } return ld } + +func generateProfileData(attributes map[string]string) pprofile.Profiles { + pd := testdata.GenerateProfilesOneEmptyResourceProfiles() + if attributes == nil { + return pd + } + resource := pd.ResourceProfiles().At(0).Resource() + for k, v := range attributes { + resource.Attributes().PutStr(k, v) + } + return pd +}