diff --git a/.chloggen/anvoy-als-receiver.yaml b/.chloggen/anvoy-als-receiver.yaml new file mode 100644 index 000000000000..5b1686c06c48 --- /dev/null +++ b/.chloggen/anvoy-als-receiver.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: new_component + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: envoyalsreceiver + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Add a new receiver for the Envoy ALS (Access Log Service). + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [36464] + +# (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/.chloggen/elasticsearchexporter_logs_dynamic_id.yaml b/.chloggen/elasticsearchexporter_logs_dynamic_id.yaml new file mode 100644 index 000000000000..84867eac2a07 --- /dev/null +++ b/.chloggen/elasticsearchexporter_logs_dynamic_id.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: elasticsearchexporter + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Add config `logs_dynamic_id` to dynamically set the document ID of log records using log record attribute `elasticsearch.document_id` + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [36882] + +# (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: [user] diff --git a/.chloggen/expo-histogram-fix-downscaling.yaml b/.chloggen/expo-histogram-fix-downscaling.yaml new file mode 100644 index 000000000000..0e4e89e0ea36 --- /dev/null +++ b/.chloggen/expo-histogram-fix-downscaling.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: bug_fix + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: deltatocumulativeprocessor + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: In order to cap number of histogram buckets take the min of desired scale across negative and positive buckets instead of the max + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [37416] + +# (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/.github/CODEOWNERS b/.github/CODEOWNERS index 6ea4bb33db3b..b07cf95004b7 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -80,6 +80,7 @@ exporter/sapmexporter/ @open-telemetry exporter/sentryexporter/ @open-telemetry/collector-contrib-approvers @AbhiPrasad exporter/signalfxexporter/ @open-telemetry/collector-contrib-approvers @dmitryax @crobert-1 exporter/splunkhecexporter/ @open-telemetry/collector-contrib-approvers @atoulme @dmitryax +exporter/stefexporter/ @open-telemetry/collector-contrib-approvers @tigrannajaryan @dmitryax exporter/sumologicexporter/ @open-telemetry/collector-contrib-approvers @rnishtala-sumo @chan-tim-sumo exporter/syslogexporter/ @open-telemetry/collector-contrib-approvers @kasia-kujawa @rnishtala-sumo @andrzej-stencel exporter/tencentcloudlogserviceexporter/ @open-telemetry/collector-contrib-approvers @wgliang @@ -221,6 +222,7 @@ receiver/couchdbreceiver/ @open-telemetry receiver/datadogreceiver/ @open-telemetry/collector-contrib-approvers @boostchicken @gouthamve @MovieStoreGuy receiver/dockerstatsreceiver/ @open-telemetry/collector-contrib-approvers @jamesmoessis receiver/elasticsearchreceiver/ @open-telemetry/collector-contrib-approvers @djaglowski +receiver/envoyalsreceiver/ @open-telemetry/collector-contrib-approvers @evan-bradley receiver/expvarreceiver/ @open-telemetry/collector-contrib-approvers @jamesmoessis @MovieStoreGuy receiver/filelogreceiver/ @open-telemetry/collector-contrib-approvers @djaglowski receiver/filestatsreceiver/ @open-telemetry/collector-contrib-approvers @atoulme diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 920ad09c50af..95b022b70897 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -81,6 +81,7 @@ body: - exporter/sentry - exporter/signalfx - exporter/splunkhec + - exporter/stef - exporter/sumologic - exporter/syslog - exporter/tencentcloudlogservice @@ -219,6 +220,7 @@ body: - receiver/datadog - receiver/dockerstats - receiver/elasticsearch + - receiver/envoyals - receiver/expvar - receiver/filelog - receiver/filestats diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml index 0bcdcf6429d3..acf39e99429e 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yaml +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -75,6 +75,7 @@ body: - exporter/sentry - exporter/signalfx - exporter/splunkhec + - exporter/stef - exporter/sumologic - exporter/syslog - exporter/tencentcloudlogservice @@ -213,6 +214,7 @@ body: - receiver/datadog - receiver/dockerstats - receiver/elasticsearch + - receiver/envoyals - receiver/expvar - receiver/filelog - receiver/filestats diff --git a/.github/ISSUE_TEMPLATE/other.yaml b/.github/ISSUE_TEMPLATE/other.yaml index 945d7cf6a8de..a99efb30d46b 100644 --- a/.github/ISSUE_TEMPLATE/other.yaml +++ b/.github/ISSUE_TEMPLATE/other.yaml @@ -75,6 +75,7 @@ body: - exporter/sentry - exporter/signalfx - exporter/splunkhec + - exporter/stef - exporter/sumologic - exporter/syslog - exporter/tencentcloudlogservice @@ -213,6 +214,7 @@ body: - receiver/datadog - receiver/dockerstats - receiver/elasticsearch + - receiver/envoyals - receiver/expvar - receiver/filelog - receiver/filestats diff --git a/.github/ISSUE_TEMPLATE/unmaintained.yaml b/.github/ISSUE_TEMPLATE/unmaintained.yaml index c816002a0cc6..c7148dc20c9a 100644 --- a/.github/ISSUE_TEMPLATE/unmaintained.yaml +++ b/.github/ISSUE_TEMPLATE/unmaintained.yaml @@ -80,6 +80,7 @@ body: - exporter/sentry - exporter/signalfx - exporter/splunkhec + - exporter/stef - exporter/sumologic - exporter/syslog - exporter/tencentcloudlogservice @@ -218,6 +219,7 @@ body: - receiver/datadog - receiver/dockerstats - receiver/elasticsearch + - receiver/envoyals - receiver/expvar - receiver/filelog - receiver/filestats diff --git a/Makefile b/Makefile index 341c909dbfc3..768375b48ec7 100644 --- a/Makefile +++ b/Makefile @@ -423,6 +423,8 @@ update-otel:$(MULTIMOD) $(MAKE) genoteltestbedcol $(MAKE) generate $(MAKE) crosslink + # Tidy again after generating code + $(MAKE) gotidy $(MAKE) remove-toolchain git add . && git commit -s -m "[chore] mod and toolchain tidy" ; \ diff --git a/cmd/otelcontribcol/builder-config.yaml b/cmd/otelcontribcol/builder-config.yaml index 40551f955ffb..56f3f52ef02f 100644 --- a/cmd/otelcontribcol/builder-config.yaml +++ b/cmd/otelcontribcol/builder-config.yaml @@ -355,6 +355,7 @@ replaces: - github.com/open-telemetry/opentelemetry-collector-contrib/internal/aws/ecsutil => ../../internal/aws/ecsutil - github.com/open-telemetry/opentelemetry-collector-contrib/receiver/rabbitmqreceiver => ../../receiver/rabbitmqreceiver - github.com/open-telemetry/opentelemetry-collector-contrib/receiver/elasticsearchreceiver => ../../receiver/elasticsearchreceiver + - github.com/open-telemetry/opentelemetry-collector-contrib/receiver/envoyalsreceiver => ../../receiver/envoyalsreceiver - github.com/open-telemetry/opentelemetry-collector-contrib/processor/metricsgenerationprocessor => ../../processor/metricsgenerationprocessor - github.com/open-telemetry/opentelemetry-collector-contrib/processor/attributesprocessor => ../../processor/attributesprocessor - github.com/open-telemetry/opentelemetry-collector-contrib/receiver/sqlqueryreceiver => ../../receiver/sqlqueryreceiver diff --git a/exporter/datadogexporter/integrationtest/go.mod b/exporter/datadogexporter/integrationtest/go.mod index 363575858803..65b7307f844d 100644 --- a/exporter/datadogexporter/integrationtest/go.mod +++ b/exporter/datadogexporter/integrationtest/go.mod @@ -7,6 +7,7 @@ require ( github.com/DataDog/datadog-agent/pkg/proto v0.63.0-devel github.com/open-telemetry/opentelemetry-collector-contrib/connector/datadogconnector v0.118.0 github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter v0.118.0 + github.com/open-telemetry/opentelemetry-collector-contrib/internal/common v0.118.0 github.com/open-telemetry/opentelemetry-collector-contrib/processor/tailsamplingprocessor v0.118.0 github.com/open-telemetry/opentelemetry-collector-contrib/receiver/prometheusreceiver v0.118.0 github.com/stretchr/testify v1.10.0 @@ -254,7 +255,6 @@ require ( github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/open-telemetry/opentelemetry-collector-contrib/internal/aws/ecsutil v0.118.0 // indirect - github.com/open-telemetry/opentelemetry-collector-contrib/internal/common v0.118.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal v0.118.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter v0.118.0 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/internal/k8sconfig v0.118.0 // indirect diff --git a/exporter/datadogexporter/integrationtest/integration_test.go b/exporter/datadogexporter/integrationtest/integration_test.go index ef586f5423b6..0e4e4d203b33 100644 --- a/exporter/datadogexporter/integrationtest/integration_test.go +++ b/exporter/datadogexporter/integrationtest/integration_test.go @@ -47,6 +47,7 @@ import ( "github.com/open-telemetry/opentelemetry-collector-contrib/connector/datadogconnector" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/datadogexporter" + commonTestutil "github.com/open-telemetry/opentelemetry-collector-contrib/internal/common/testutil" "github.com/open-telemetry/opentelemetry-collector-contrib/processor/tailsamplingprocessor" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/prometheusreceiver" ) @@ -92,6 +93,10 @@ func testIntegration(t *testing.T) { server := testutil.DatadogServerMock(apmstatsRec.HandlerFunc, tracesRec.HandlerFunc) defer server.Close() t.Setenv("SERVER_URL", server.URL) + t.Setenv("PROM_SERVER", commonTestutil.GetAvailableLocalAddress(t)) + t.Setenv("OTLP_HTTP_SERVER", commonTestutil.GetAvailableLocalAddress(t)) + otlpGRPCEndpoint := commonTestutil.GetAvailableLocalAddress(t) + t.Setenv("OTLP_GRPC_SERVER", otlpGRPCEndpoint) // 2. Start in-process collector factories := getIntegrationTestComponents(t) @@ -104,7 +109,7 @@ func testIntegration(t *testing.T) { waitForReadiness(app) // 3. Generate and send traces - sendTraces(t) + sendTraces(t, otlpGRPCEndpoint) // 4. Validate traces and APM stats from the mock server var spans []*pb.Span @@ -223,11 +228,11 @@ func waitForReadiness(app *otelcol.Collector) { } } -func sendTraces(t *testing.T) { +func sendTraces(t *testing.T, endpoint string) { ctx := context.Background() // Set up OTel-Go SDK and exporter - traceExporter, err := otlptracegrpc.New(ctx, otlptracegrpc.WithInsecure()) + traceExporter, err := otlptracegrpc.New(ctx, otlptracegrpc.WithInsecure(), otlptracegrpc.WithEndpoint(endpoint)) require.NoError(t, err) bsp := sdktrace.NewBatchSpanProcessor(traceExporter) r1, _ := resource.New(ctx, resource.WithAttributes(attribute.String("k8s.node.name", "aaaa"))) @@ -284,6 +289,10 @@ func TestIntegrationComputeTopLevelBySpanKind(t *testing.T) { server := testutil.DatadogServerMock(apmstatsRec.HandlerFunc, tracesRec.HandlerFunc) defer server.Close() t.Setenv("SERVER_URL", server.URL) + t.Setenv("PROM_SERVER", commonTestutil.GetAvailableLocalAddress(t)) + t.Setenv("OTLP_HTTP_SERVER", commonTestutil.GetAvailableLocalAddress(t)) + otlpGRPCEndpoint := commonTestutil.GetAvailableLocalAddress(t) + t.Setenv("OTLP_GRPC_SERVER", otlpGRPCEndpoint) // 2. Start in-process collector factories := getIntegrationTestComponents(t) @@ -296,7 +305,7 @@ func TestIntegrationComputeTopLevelBySpanKind(t *testing.T) { waitForReadiness(app) // 3. Generate and send traces - sendTracesComputeTopLevelBySpanKind(t) + sendTracesComputeTopLevelBySpanKind(t, otlpGRPCEndpoint) // 4. Validate traces and APM stats from the mock server var spans []*pb.Span @@ -384,11 +393,11 @@ func TestIntegrationComputeTopLevelBySpanKind(t *testing.T) { } } -func sendTracesComputeTopLevelBySpanKind(t *testing.T) { +func sendTracesComputeTopLevelBySpanKind(t *testing.T, endpoint string) { ctx := context.Background() // Set up OTel-Go SDK and exporter - traceExporter, err := otlptracegrpc.New(ctx, otlptracegrpc.WithInsecure()) + traceExporter, err := otlptracegrpc.New(ctx, otlptracegrpc.WithInsecure(), otlptracegrpc.WithEndpoint(endpoint)) require.NoError(t, err) bsp := sdktrace.NewBatchSpanProcessor(traceExporter) r1, _ := resource.New(ctx, resource.WithAttributes(attribute.String("k8s.node.name", "aaaa"))) @@ -463,7 +472,12 @@ func TestIntegrationLogs(t *testing.T) { } }) defer server.Close() + thing := commonTestutil.GetAvailableLocalAddress(t) t.Setenv("SERVER_URL", server.URL) + t.Setenv("PROM_SERVER", thing) + t.Setenv("OTLP_HTTP_SERVER", commonTestutil.GetAvailableLocalAddress(t)) + otlpGRPCEndpoint := commonTestutil.GetAvailableLocalAddress(t) + t.Setenv("OTLP_GRPC_SERVER", otlpGRPCEndpoint) // 2. Start in-process collector factories := getIntegrationTestComponents(t) @@ -476,7 +490,7 @@ func TestIntegrationLogs(t *testing.T) { waitForReadiness(app) // 3. Generate and send logs - sendLogs(t, 5) + sendLogs(t, 5, otlpGRPCEndpoint) // 4. Validate logs and metrics from the mock server // Wait until `doneChannel` is closed and prometheus metrics are received. @@ -520,9 +534,9 @@ func TestIntegrationLogs(t *testing.T) { assert.Equal(t, 2, numSentLogRecords) } -func sendLogs(t *testing.T, numLogs int) { +func sendLogs(t *testing.T, numLogs int, endpoint string) { ctx := context.Background() - logExporter, err := otlploggrpc.New(ctx, otlploggrpc.WithInsecure()) + logExporter, err := otlploggrpc.New(ctx, otlploggrpc.WithInsecure(), otlploggrpc.WithEndpoint(endpoint)) assert.NoError(t, err) lr := make([]log.Record, numLogs) assert.NoError(t, logExporter.Export(ctx, lr)) diff --git a/exporter/datadogexporter/integrationtest/integration_test_config.yaml b/exporter/datadogexporter/integrationtest/integration_test_config.yaml index c32bf27da49e..b29a7ebf4f83 100644 --- a/exporter/datadogexporter/integrationtest/integration_test_config.yaml +++ b/exporter/datadogexporter/integrationtest/integration_test_config.yaml @@ -3,9 +3,9 @@ receivers: otlp: protocols: http: - endpoint: "localhost:4318" + endpoint: ${env:OTLP_HTTP_SERVER} grpc: - endpoint: "localhost:4317" + endpoint: ${env:OTLP_GRPC_SERVER} processors: tail_sampling: diff --git a/exporter/datadogexporter/integrationtest/integration_test_internal_metrics_config.yaml b/exporter/datadogexporter/integrationtest/integration_test_internal_metrics_config.yaml index 9100aecf8cad..1d1e6762b998 100644 --- a/exporter/datadogexporter/integrationtest/integration_test_internal_metrics_config.yaml +++ b/exporter/datadogexporter/integrationtest/integration_test_internal_metrics_config.yaml @@ -3,16 +3,16 @@ receivers: otlp: protocols: http: - endpoint: "localhost:4318" + endpoint: ${env:OTLP_HTTP_SERVER} grpc: - endpoint: "localhost:4317" + endpoint: ${env:OTLP_GRPC_SERVER} prometheus: config: scrape_configs: - job_name: 'otelcol' scrape_interval: 1s static_configs: - - targets: [ 'localhost:8888' ] + - targets: [ '${env:PROM_SERVER}' ] exporters: datadog: @@ -33,7 +33,7 @@ service: telemetry: metrics: level: basic - address: "localhost:8888" + address: ${env:PROM_SERVER} pipelines: traces: receivers: [otlp] diff --git a/exporter/datadogexporter/integrationtest/integration_test_logs_config.yaml b/exporter/datadogexporter/integrationtest/integration_test_logs_config.yaml index f02d45dafc16..ae2af2358967 100644 --- a/exporter/datadogexporter/integrationtest/integration_test_logs_config.yaml +++ b/exporter/datadogexporter/integrationtest/integration_test_logs_config.yaml @@ -3,16 +3,16 @@ receivers: otlp: protocols: http: - endpoint: "localhost:4318" + endpoint: ${env:OTLP_HTTP_SERVER} grpc: - endpoint: "localhost:4317" + endpoint: ${env:OTLP_GRPC_SERVER} prometheus: config: scrape_configs: - job_name: 'otelcol' scrape_interval: 1s static_configs: - - targets: [ 'localhost:8888' ] + - targets: [ '${env:PROM_SERVER}' ] metric_relabel_configs: - source_labels: [ __name__ ] regex: "(otelcol_receiver_accepted_log_records|otelcol_exporter_sent_log_records)" @@ -37,7 +37,7 @@ service: telemetry: metrics: level: basic - address: "localhost:8888" + address: ${env:PROM_SERVER} pipelines: logs: receivers: [otlp] diff --git a/exporter/datadogexporter/integrationtest/integration_test_toplevel_config.yaml b/exporter/datadogexporter/integrationtest/integration_test_toplevel_config.yaml index e542b95d3626..2a997226be99 100644 --- a/exporter/datadogexporter/integrationtest/integration_test_toplevel_config.yaml +++ b/exporter/datadogexporter/integrationtest/integration_test_toplevel_config.yaml @@ -3,9 +3,9 @@ receivers: otlp: protocols: http: - endpoint: "localhost:4318" + endpoint: ${env:OTLP_HTTP_SERVER} grpc: - endpoint: "localhost:4317" + endpoint: ${env:OTLP_GRPC_SERVER} connectors: datadog/connector: diff --git a/exporter/datadogexporter/integrationtest/no_race_integration_test.go b/exporter/datadogexporter/integrationtest/no_race_integration_test.go index a42262337550..82ec0724ff9e 100644 --- a/exporter/datadogexporter/integrationtest/no_race_integration_test.go +++ b/exporter/datadogexporter/integrationtest/no_race_integration_test.go @@ -14,19 +14,24 @@ import ( "github.com/DataDog/datadog-agent/comp/otelcol/otlp/testutil" "github.com/stretchr/testify/assert" + + commonTestutil "github.com/open-telemetry/opentelemetry-collector-contrib/internal/common/testutil" ) func TestIntegrationInternalMetrics(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("flaky test on windows https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/34836") } - // 1. Set up mock Datadog server seriesRec := &testutil.HTTPRequestRecorderWithChan{Pattern: testutil.MetricV2Endpoint, ReqChan: make(chan []byte, 100)} tracesRec := &testutil.HTTPRequestRecorderWithChan{Pattern: testutil.TraceEndpoint, ReqChan: make(chan []byte, 100)} server := testutil.DatadogServerMock(seriesRec.HandlerFunc, tracesRec.HandlerFunc) defer server.Close() t.Setenv("SERVER_URL", server.URL) + t.Setenv("PROM_SERVER", commonTestutil.GetAvailableLocalAddress(t)) + t.Setenv("OTLP_HTTP_SERVER", commonTestutil.GetAvailableLocalAddress(t)) + otlpGRPCEndpoint := commonTestutil.GetAvailableLocalAddress(t) + t.Setenv("OTLP_GRPC_SERVER", otlpGRPCEndpoint) // 2. Start in-process collector factories := getIntegrationTestComponents(t) @@ -39,7 +44,7 @@ func TestIntegrationInternalMetrics(t *testing.T) { waitForReadiness(app) // 3. Generate and send traces - sendTraces(t) + sendTraces(t, otlpGRPCEndpoint) // 4. Validate Datadog trace agent & OTel internal metrics are sent to the mock server expectedMetrics := map[string]struct{}{ diff --git a/exporter/elasticsearchexporter/README.md b/exporter/elasticsearchexporter/README.md index aa8bb6518ccd..d78d5cba8421 100644 --- a/exporter/elasticsearchexporter/README.md +++ b/exporter/elasticsearchexporter/README.md @@ -142,6 +142,9 @@ This can be customised through the following settings: - `prefix_separator`(default=`-`): Set a separator between logstash_prefix and date. - `date_format`(default=`%Y.%m.%d`): Time format (based on strftime) to generate the second part of the Index name. +- `logs_dynamic_id` (optional): Dynamically determines the document ID to be used in Elasticsearch based on a log record attribute. + - `enabled`(default=false): Enable/Disable dynamic ID for log records. If `elasticsearch.document_id` exists and is not an empty string in the log record attributes, it will be used as the document ID. Otherwise, the document ID will be generated by Elasticsearch. The attribute `elasticsearch.document_id` is removed from the final document. + ### Elasticsearch document mapping The Elasticsearch exporter supports several document schemas and preprocessing diff --git a/exporter/elasticsearchexporter/bulkindexer.go b/exporter/elasticsearchexporter/bulkindexer.go index 2200216be4ef..ded879d3a036 100644 --- a/exporter/elasticsearchexporter/bulkindexer.go +++ b/exporter/elasticsearchexporter/bulkindexer.go @@ -31,7 +31,7 @@ type bulkIndexer interface { type bulkIndexerSession interface { // Add adds a document to the bulk indexing session. - Add(ctx context.Context, index string, document io.WriterTo, dynamicTemplates map[string]string) error + Add(ctx context.Context, index string, docID string, document io.WriterTo, dynamicTemplates map[string]string) error // End must be called on the session object once it is no longer // needed, in order to release any associated resources. @@ -126,8 +126,9 @@ type syncBulkIndexerSession struct { } // Add adds an item to the sync bulk indexer session. -func (s *syncBulkIndexerSession) Add(ctx context.Context, index string, document io.WriterTo, dynamicTemplates map[string]string) error { - err := s.bi.Add(docappender.BulkIndexerItem{Index: index, Body: document, DynamicTemplates: dynamicTemplates}) +func (s *syncBulkIndexerSession) Add(ctx context.Context, index string, docID string, document io.WriterTo, dynamicTemplates map[string]string) error { + doc := docappender.BulkIndexerItem{Index: index, Body: document, DocumentID: docID, DynamicTemplates: dynamicTemplates} + err := s.bi.Add(doc) if err != nil { return err } @@ -248,10 +249,11 @@ func (a *asyncBulkIndexer) Close(ctx context.Context) error { // Add adds an item to the async bulk indexer session. // // Adding an item after a call to Close() will panic. -func (s asyncBulkIndexerSession) Add(ctx context.Context, index string, document io.WriterTo, dynamicTemplates map[string]string) error { +func (s asyncBulkIndexerSession) Add(ctx context.Context, index string, docID string, document io.WriterTo, dynamicTemplates map[string]string) error { item := docappender.BulkIndexerItem{ Index: index, Body: document, + DocumentID: docID, DynamicTemplates: dynamicTemplates, } select { diff --git a/exporter/elasticsearchexporter/bulkindexer_test.go b/exporter/elasticsearchexporter/bulkindexer_test.go index 2b3d86a30128..9f2139e83710 100644 --- a/exporter/elasticsearchexporter/bulkindexer_test.go +++ b/exporter/elasticsearchexporter/bulkindexer_test.go @@ -102,7 +102,7 @@ func TestAsyncBulkIndexer_flush(t *testing.T) { session, err := bulkIndexer.StartSession(context.Background()) require.NoError(t, err) - assert.NoError(t, session.Add(context.Background(), "foo", strings.NewReader(`{"foo": "bar"}`), nil)) + assert.NoError(t, session.Add(context.Background(), "foo", "", strings.NewReader(`{"foo": "bar"}`), nil)) // should flush time.Sleep(100 * time.Millisecond) assert.Equal(t, int64(1), bulkIndexer.stats.docsIndexed.Load()) @@ -229,7 +229,7 @@ func TestAsyncBulkIndexer_flush_error(t *testing.T) { session, err := bulkIndexer.StartSession(context.Background()) require.NoError(t, err) - assert.NoError(t, session.Add(context.Background(), "foo", strings.NewReader(`{"foo": "bar"}`), nil)) + assert.NoError(t, session.Add(context.Background(), "foo", "", strings.NewReader(`{"foo": "bar"}`), nil)) // should flush time.Sleep(100 * time.Millisecond) assert.Equal(t, int64(0), bulkIndexer.stats.docsIndexed.Load()) @@ -312,7 +312,7 @@ func runBulkIndexerOnce(t *testing.T, config *Config, client *elasticsearch.Clie session, err := bulkIndexer.StartSession(context.Background()) require.NoError(t, err) - assert.NoError(t, session.Add(context.Background(), "foo", strings.NewReader(`{"foo": "bar"}`), nil)) + assert.NoError(t, session.Add(context.Background(), "foo", "", strings.NewReader(`{"foo": "bar"}`), nil)) assert.NoError(t, bulkIndexer.Close(context.Background())) return bulkIndexer @@ -338,7 +338,7 @@ func TestSyncBulkIndexer_flushBytes(t *testing.T) { session, err := bi.StartSession(context.Background()) require.NoError(t, err) - assert.NoError(t, session.Add(context.Background(), "foo", strings.NewReader(`{"foo": "bar"}`), nil)) + assert.NoError(t, session.Add(context.Background(), "foo", "", strings.NewReader(`{"foo": "bar"}`), nil)) assert.Equal(t, int64(1), reqCnt.Load()) // flush due to flush::bytes assert.NoError(t, bi.Close(context.Background())) } diff --git a/exporter/elasticsearchexporter/config.go b/exporter/elasticsearchexporter/config.go index 40acdaf99497..bd246a398b8b 100644 --- a/exporter/elasticsearchexporter/config.go +++ b/exporter/elasticsearchexporter/config.go @@ -53,6 +53,9 @@ type Config struct { // fall back to pure TracesIndex, if 'elasticsearch.index.prefix' or 'elasticsearch.index.suffix' are not found in resource or attribute (prio: resource > attribute) TracesDynamicIndex DynamicIndexSetting `mapstructure:"traces_dynamic_index"` + // LogsDynamicID configures whether log record attribute `elasticsearch.document_id` is set as the document ID in ES. + LogsDynamicID DynamicIDSettings `mapstructure:"logs_dynamic_id"` + // Pipeline configures the ingest node pipeline name that should be used to process the // events. // @@ -112,6 +115,10 @@ type DynamicIndexSetting struct { Enabled bool `mapstructure:"enabled"` } +type DynamicIDSettings struct { + Enabled bool `mapstructure:"enabled"` +} + // AuthenticationSettings defines user authentication related settings. type AuthenticationSettings struct { // User is used to configure HTTP Basic Authentication. diff --git a/exporter/elasticsearchexporter/config_test.go b/exporter/elasticsearchexporter/config_test.go index 153001b149e2..51d3955ebbd7 100644 --- a/exporter/elasticsearchexporter/config_test.go +++ b/exporter/elasticsearchexporter/config_test.go @@ -73,6 +73,9 @@ func TestConfig(t *testing.T) { TracesDynamicIndex: DynamicIndexSetting{ Enabled: false, }, + LogsDynamicID: DynamicIDSettings{ + Enabled: false, + }, Pipeline: "mypipeline", ClientConfig: withDefaultHTTPClientConfig(func(cfg *confighttp.ClientConfig) { cfg.Timeout = 2 * time.Minute @@ -144,6 +147,9 @@ func TestConfig(t *testing.T) { TracesDynamicIndex: DynamicIndexSetting{ Enabled: false, }, + LogsDynamicID: DynamicIDSettings{ + Enabled: false, + }, Pipeline: "mypipeline", ClientConfig: withDefaultHTTPClientConfig(func(cfg *confighttp.ClientConfig) { cfg.Timeout = 2 * time.Minute @@ -215,6 +221,9 @@ func TestConfig(t *testing.T) { TracesDynamicIndex: DynamicIndexSetting{ Enabled: false, }, + LogsDynamicID: DynamicIDSettings{ + Enabled: false, + }, Pipeline: "mypipeline", ClientConfig: withDefaultHTTPClientConfig(func(cfg *confighttp.ClientConfig) { cfg.Timeout = 2 * time.Minute diff --git a/exporter/elasticsearchexporter/exporter.go b/exporter/elasticsearchexporter/exporter.go index b13d1336b94d..52bb13a599e3 100644 --- a/exporter/elasticsearchexporter/exporter.go +++ b/exporter/elasticsearchexporter/exporter.go @@ -22,6 +22,11 @@ import ( "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/elasticsearchexporter/internal/pool" ) +const ( + // documentIDAttributeName is the attribute name used to specify the document ID. + documentIDAttributeName = "elasticsearch.document_id" +) + type elasticsearchExporter struct { component.TelemetrySettings userAgent string @@ -176,13 +181,15 @@ func (e *elasticsearchExporter) pushLogRecord( } buf := e.bufferPool.NewPooledBuffer() + docID := e.extractDocumentIDAttribute(record.Attributes()) err := e.model.encodeLog(resource, resourceSchemaURL, record, scope, scopeSchemaURL, fIndex, buf.Buffer) if err != nil { buf.Recycle() return fmt.Errorf("failed to encode log event: %w", err) } + // not recycling after Add returns an error as we don't know if it's already recycled - return bulkIndexerSession.Add(ctx, fIndex.Index, buf, nil) + return bulkIndexerSession.Add(ctx, fIndex.Index, docID, buf, nil) } func (e *elasticsearchExporter) pushMetricsData( @@ -299,7 +306,7 @@ func (e *elasticsearchExporter) pushMetricsData( errs = append(errs, err) continue } - if err := session.Add(ctx, fIndex.Index, buf, dynamicTemplates); err != nil { + if err := session.Add(ctx, fIndex.Index, "", buf, dynamicTemplates); err != nil { // not recycling after Add returns an error as we don't know if it's already recycled if cerr := ctx.Err(); cerr != nil { return cerr @@ -422,7 +429,7 @@ func (e *elasticsearchExporter) pushTraceRecord( return fmt.Errorf("failed to encode trace record: %w", err) } // not recycling after Add returns an error as we don't know if it's already recycled - return bulkIndexerSession.Add(ctx, fIndex.Index, buf, nil) + return bulkIndexerSession.Add(ctx, fIndex.Index, "", buf, nil) } func (e *elasticsearchExporter) pushSpanEvent( @@ -454,5 +461,17 @@ func (e *elasticsearchExporter) pushSpanEvent( return nil } // not recycling after Add returns an error as we don't know if it's already recycled - return bulkIndexerSession.Add(ctx, fIndex.Index, buf, nil) + return bulkIndexerSession.Add(ctx, fIndex.Index, "", buf, nil) +} + +func (e *elasticsearchExporter) extractDocumentIDAttribute(m pcommon.Map) string { + if !e.config.LogsDynamicID.Enabled { + return "" + } + + v, ok := m.Get(documentIDAttributeName) + if !ok { + return "" + } + return v.AsString() } diff --git a/exporter/elasticsearchexporter/exporter_test.go b/exporter/elasticsearchexporter/exporter_test.go index b045ccb325d1..74a6ec5dfcfb 100644 --- a/exporter/elasticsearchexporter/exporter_test.go +++ b/exporter/elasticsearchexporter/exporter_test.go @@ -736,6 +736,82 @@ func TestExporterLogs(t *testing.T) { assert.JSONEq(t, `{"a":"a","a.b":"a.b"}`, gjson.GetBytes(doc, `resource.attributes`).Raw) }) + t.Run("publish logs with dynamic id", func(t *testing.T) { + t.Parallel() + exampleDocID := "abc123" + tableTests := []struct { + name string + expectedDocID string // "" means the _id will not be set + recordAttrs map[string]any + }{ + { + name: "missing document id attribute should not set _id", + expectedDocID: "", + }, + { + name: "empty document id attribute should not set _id", + expectedDocID: "", + recordAttrs: map[string]any{ + documentIDAttributeName: "", + }, + }, + { + name: "record attributes", + expectedDocID: exampleDocID, + recordAttrs: map[string]any{ + documentIDAttributeName: exampleDocID, + }, + }, + } + + cfgs := map[string]func(*Config){ + "async": func(cfg *Config) { + batcherEnabled := false + cfg.Batcher.Enabled = &batcherEnabled + }, + "sync": func(cfg *Config) { + batcherEnabled := true + cfg.Batcher.Enabled = &batcherEnabled + cfg.Batcher.FlushTimeout = 10 * time.Millisecond + }, + } + for _, tt := range tableTests { + for cfgName, cfgFn := range cfgs { + t.Run(tt.name+"/"+cfgName, func(t *testing.T) { + t.Parallel() + rec := newBulkRecorder() + server := newESTestServer(t, func(docs []itemRequest) ([]itemResponse, error) { + rec.Record(docs) + + if tt.expectedDocID == "" { + assert.NotContains(t, string(docs[0].Action), "_id", "expected _id to not be set") + } else { + assert.Equal(t, tt.expectedDocID, actionJSONToID(t, docs[0].Action), "expected _id to be set") + } + + // Ensure the document id attribute is removed from the final document. + assert.NotContains(t, string(docs[0].Document), documentIDAttributeName, "expected document id attribute to be removed") + return itemsAllOK(docs) + }) + + exporter := newTestLogsExporter(t, server.URL, func(cfg *Config) { + cfg.Mapping.Mode = "otel" + cfg.LogsDynamicID.Enabled = true + cfgFn(cfg) + }) + logs := newLogsWithAttributes( + tt.recordAttrs, + map[string]any{}, + map[string]any{}, + ) + logs.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).Body().SetStr("hello world") + mustSendLogs(t, exporter, logs) + + rec.WaitItems(1) + }) + } + } + }) t.Run("otel mode attribute complex value", func(t *testing.T) { rec := newBulkRecorder() server := newESTestServer(t, func(docs []itemRequest) ([]itemResponse, error) { @@ -1943,3 +2019,14 @@ func actionJSONToIndex(t *testing.T, actionJSON json.RawMessage) string { require.NoError(t, err) return action.Create.Index } + +func actionJSONToID(t *testing.T, actionJSON json.RawMessage) string { + action := struct { + Create struct { + ID string `json:"_id"` + } `json:"create"` + }{} + err := json.Unmarshal(actionJSON, &action) + require.NoError(t, err) + return action.Create.ID +} diff --git a/exporter/elasticsearchexporter/factory.go b/exporter/elasticsearchexporter/factory.go index 755a4e3d241b..c72ecbfc0fd1 100644 --- a/exporter/elasticsearchexporter/factory.go +++ b/exporter/elasticsearchexporter/factory.go @@ -62,6 +62,9 @@ func createDefaultConfig() component.Config { TracesDynamicIndex: DynamicIndexSetting{ Enabled: false, }, + LogsDynamicID: DynamicIDSettings{ + Enabled: false, + }, Retry: RetrySettings{ Enabled: true, MaxRetries: 0, // default is set in exporter code diff --git a/exporter/elasticsearchexporter/pdata_serializer.go b/exporter/elasticsearchexporter/pdata_serializer.go index 9d2fbf82f63c..76eb2a988372 100644 --- a/exporter/elasticsearchexporter/pdata_serializer.go +++ b/exporter/elasticsearchexporter/pdata_serializer.go @@ -298,7 +298,7 @@ func writeAttributes(v *json.Visitor, attributes pcommon.Map, stringifyMapValues _ = v.OnObjectStart(-1, structform.AnyType) attributes.Range(func(k string, val pcommon.Value) bool { switch k { - case dataStreamType, dataStreamDataset, dataStreamNamespace, elasticsearch.MappingHintsAttrKey: + case dataStreamType, dataStreamDataset, dataStreamNamespace, elasticsearch.MappingHintsAttrKey, documentIDAttributeName: return true } if isGeoAttribute(k, val) { diff --git a/exporter/elasticsearchexporter/pdata_serializer_test.go b/exporter/elasticsearchexporter/pdata_serializer_test.go index 6131ebbc6ee1..26d514757fd4 100644 --- a/exporter/elasticsearchexporter/pdata_serializer_test.go +++ b/exporter/elasticsearchexporter/pdata_serializer_test.go @@ -31,6 +31,7 @@ func TestSerializeLog(t *testing.T) { record.Attributes().PutDouble("double", 42.0) record.Attributes().PutInt("int", 42) record.Attributes().PutEmptyBytes("bytes").Append(42) + record.Attributes().PutStr(documentIDAttributeName, "my_id") _ = record.Attributes().PutEmptySlice("slice").FromRaw([]any{42, "foo"}) record.Attributes().PutEmptySlice("map_slice").AppendEmpty().SetEmptyMap().PutStr("foo.bar", "baz") mapAttr := record.Attributes().PutEmptyMap("map") diff --git a/exporter/prometheusremotewriteexporter/exporter.go b/exporter/prometheusremotewriteexporter/exporter.go index 6ad7d31981c0..6829bb57201c 100644 --- a/exporter/prometheusremotewriteexporter/exporter.go +++ b/exporter/prometheusremotewriteexporter/exporter.go @@ -353,7 +353,10 @@ func (prwe *prwExporter) execute(ctx context.Context, writeReq *prompb.WriteRequ if err != nil { return err } - defer resp.Body.Close() + defer func() { + _, _ = io.Copy(io.Discard, resp.Body) + resp.Body.Close() + }() // 2xx status code is considered a success // 5xx errors are recoverable and the exporter should retry diff --git a/exporter/prometheusremotewriteexporter/exporter_concurrency_test.go b/exporter/prometheusremotewriteexporter/exporter_concurrency_test.go index bf9fcbd968cc..5369b201e526 100644 --- a/exporter/prometheusremotewriteexporter/exporter_concurrency_test.go +++ b/exporter/prometheusremotewriteexporter/exporter_concurrency_test.go @@ -8,7 +8,7 @@ import ( "io" "net/http" "net/http/httptest" - "os" + "runtime" "strconv" "sync" "testing" @@ -32,9 +32,6 @@ import ( // Test everything works when there is more than one goroutine calling PushMetrics. // Today we only use 1 worker per exporter, but the intention of this test is to future-proof in case it changes. func Test_PushMetricsConcurrent(t *testing.T) { - if os.Getenv("ImageOs") == "win25" && os.Getenv("GITHUB_ACTIONS") == "true" { - t.Skip("Skipping test on Windows 2025 GH runners, see https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/37104") - } n := 1000 ms := make([]pmetric.Metrics, n) testIDKey := "test_id" @@ -137,15 +134,22 @@ func Test_PushMetricsConcurrent(t *testing.T) { resp, checkRequestErr := http.Get(server.URL) require.NoError(c, checkRequestErr) assert.NoError(c, resp.Body.Close()) - }, 5*time.Second, 100*time.Millisecond) + }, 15*time.Second, 100*time.Millisecond) var wg sync.WaitGroup wg.Add(n) + maxConcurrentGoroutines := runtime.NumCPU() * 4 + semaphore := make(chan struct{}, maxConcurrentGoroutines) for _, m := range ms { + semaphore <- struct{}{} go func() { + defer func() { + <-semaphore + wg.Done() + }() + err := prwe.PushMetrics(ctx, m) assert.NoError(t, err) - wg.Done() }() } wg.Wait() diff --git a/exporter/stefexporter/Makefile b/exporter/stefexporter/Makefile new file mode 100644 index 000000000000..c1496226e590 --- /dev/null +++ b/exporter/stefexporter/Makefile @@ -0,0 +1 @@ +include ../../Makefile.Common \ No newline at end of file diff --git a/exporter/stefexporter/README.md b/exporter/stefexporter/README.md new file mode 100644 index 000000000000..fbbd24cd03bb --- /dev/null +++ b/exporter/stefexporter/README.md @@ -0,0 +1,15 @@ +# STEF Exporter + + +| Status | | +| ------------- |-----------| +| Stability | [development]: metrics | +| Distributions | [] | +| Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aopen%20label%3Aexporter%2Fstef%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Aexporter%2Fstef) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aclosed%20label%3Aexporter%2Fstef%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aclosed+is%3Aissue+label%3Aexporter%2Fstef) | +| [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@tigrannajaryan](https://www.github.com/tigrannajaryan), [@dmitryax](https://www.github.com/dmitryax) | + +[development]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#development + + +Export data via gRPC using +[Otel/STEF format](https://github.com/splunk/stef/tree/main/go/otel) format. diff --git a/exporter/stefexporter/config.go b/exporter/stefexporter/config.go new file mode 100644 index 000000000000..76d273150f43 --- /dev/null +++ b/exporter/stefexporter/config.go @@ -0,0 +1,57 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package stefexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/stefexporter" + +import ( + "errors" + "fmt" + "net" + "regexp" + "strconv" + "strings" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/config/configgrpc" +) + +// Config defines configuration for logging exporter. +type Config struct { + configgrpc.ClientConfig `mapstructure:",squash"` // squash ensures fields are correctly decoded in embedded struct. +} + +var _ component.Config = (*Config)(nil) + +// Validate checks if the exporter configuration is valid +func (c *Config) Validate() error { + endpoint := c.sanitizedEndpoint() + if endpoint == "" { + return errors.New(`requires a non-empty "endpoint"`) + } + + // Validate that the port is in the address + _, port, err := net.SplitHostPort(endpoint) + if err != nil { + return err + } + if _, err := strconv.Atoi(port); err != nil { + return fmt.Errorf(`invalid port "%s"`, port) + } + + return nil +} + +// TODO: move this to configgrpc.ClientConfig to avoid this code duplication (copied from OTLP exporter). +func (c *Config) sanitizedEndpoint() string { + switch { + case strings.HasPrefix(c.Endpoint, "http://"): + return strings.TrimPrefix(c.Endpoint, "http://") + case strings.HasPrefix(c.Endpoint, "https://"): + return strings.TrimPrefix(c.Endpoint, "https://") + case strings.HasPrefix(c.Endpoint, "dns://"): + r := regexp.MustCompile("^dns://[/]?") + return r.ReplaceAllString(c.Endpoint, "") + default: + return c.Endpoint + } +} diff --git a/exporter/stefexporter/config_test.go b/exporter/stefexporter/config_test.go new file mode 100644 index 000000000000..308fad292ae2 --- /dev/null +++ b/exporter/stefexporter/config_test.go @@ -0,0 +1,18 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package stefexporter + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/confmap" +) + +func TestUnmarshalDefaultConfig(t *testing.T) { + factory := NewFactory() + cfg := factory.CreateDefaultConfig() + assert.NoError(t, confmap.New().Unmarshal(&cfg)) + assert.Equal(t, factory.CreateDefaultConfig(), cfg) +} diff --git a/exporter/stefexporter/doc.go b/exporter/stefexporter/doc.go new file mode 100644 index 000000000000..79582d0c006c --- /dev/null +++ b/exporter/stefexporter/doc.go @@ -0,0 +1,7 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +//go:generate mdatagen metadata.yaml + +// Package stefexporter implements an exporter that sends data Otel/STEF format. +package stefexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/stefexporter" diff --git a/exporter/stefexporter/exporter.go b/exporter/stefexporter/exporter.go new file mode 100644 index 000000000000..8c293ae06671 --- /dev/null +++ b/exporter/stefexporter/exporter.go @@ -0,0 +1,30 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package stefexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/stefexporter" + +import ( + "context" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/pdata/pmetric" + "go.uber.org/zap" +) + +type stefExporter struct{} + +func newStefExporter(_ *zap.Logger, _ *Config) *stefExporter { + return &stefExporter{} +} + +func (s *stefExporter) Start(_ context.Context, _ component.Host) error { + return nil +} + +func (s *stefExporter) Shutdown(_ context.Context) error { + return nil +} + +func (s *stefExporter) pushMetrics(_ context.Context, _ pmetric.Metrics) error { + return nil +} diff --git a/exporter/stefexporter/exporter_test.go b/exporter/stefexporter/exporter_test.go new file mode 100644 index 000000000000..536671c0a9ba --- /dev/null +++ b/exporter/stefexporter/exporter_test.go @@ -0,0 +1,4 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package stefexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/stefexporter" diff --git a/exporter/stefexporter/factory.go b/exporter/stefexporter/factory.go new file mode 100644 index 000000000000..c92174c94ccb --- /dev/null +++ b/exporter/stefexporter/factory.go @@ -0,0 +1,46 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package stefexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/stefexporter" + +import ( + "context" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/consumer" + "go.opentelemetry.io/collector/exporter" + "go.opentelemetry.io/collector/exporter/exporterhelper" + + "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/stefexporter/internal/metadata" +) + +// The value of "type" key in configuration. +var componentType = component.MustNewType("stef") + +// NewFactory creates a factory for Debug exporter +func NewFactory() exporter.Factory { + return exporter.NewFactory( + componentType, + createDefaultConfig, + exporter.WithMetrics(createMetricsExporter, metadata.MetricsStability), + ) +} + +func createDefaultConfig() component.Config { + return &Config{} +} + +func createMetricsExporter(ctx context.Context, set exporter.Settings, config component.Config) ( + exporter.Metrics, error, +) { + cfg := config.(*Config) + stefexporter := newStefExporter(set.TelemetrySettings.Logger, cfg) + return exporterhelper.NewMetrics( + ctx, set, config, + stefexporter.pushMetrics, + exporterhelper.WithStart(stefexporter.Start), + exporterhelper.WithShutdown(stefexporter.Shutdown), + exporterhelper.WithCapabilities(consumer.Capabilities{MutatesData: false}), + exporterhelper.WithTimeout(exporterhelper.TimeoutConfig{Timeout: 0}), + ) +} diff --git a/exporter/stefexporter/factory_test.go b/exporter/stefexporter/factory_test.go new file mode 100644 index 000000000000..fa2e10685565 --- /dev/null +++ b/exporter/stefexporter/factory_test.go @@ -0,0 +1,29 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package stefexporter + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/exporter/exportertest" +) + +func TestCreateDefaultConfig(t *testing.T) { + factory := NewFactory() + cfg := factory.CreateDefaultConfig() + assert.NotNil(t, cfg, "failed to create default config") + assert.NoError(t, componenttest.CheckConfigStruct(cfg)) +} + +func TestCreateMetricsExporter(t *testing.T) { + factory := NewFactory() + cfg := factory.CreateDefaultConfig() + + me, err := factory.CreateMetrics(context.Background(), exportertest.NewNopSettings(), cfg) + assert.NoError(t, err) + assert.NotNil(t, me) +} diff --git a/exporter/stefexporter/generated_component_test.go b/exporter/stefexporter/generated_component_test.go new file mode 100644 index 000000000000..64da76f8b782 --- /dev/null +++ b/exporter/stefexporter/generated_component_test.go @@ -0,0 +1,134 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package stefexporter + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/confmap/confmaptest" + "go.opentelemetry.io/collector/exporter" + "go.opentelemetry.io/collector/exporter/exportertest" + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/plog" + "go.opentelemetry.io/collector/pdata/pmetric" + "go.opentelemetry.io/collector/pdata/ptrace" +) + +func TestComponentFactoryType(t *testing.T) { + require.Equal(t, "stef", NewFactory().Type().String()) +} + +func TestComponentConfigStruct(t *testing.T) { + require.NoError(t, componenttest.CheckConfigStruct(NewFactory().CreateDefaultConfig())) +} + +func TestComponentLifecycle(t *testing.T) { + factory := NewFactory() + + tests := []struct { + createFn func(ctx context.Context, set exporter.Settings, cfg component.Config) (component.Component, error) + name string + }{ + + { + name: "metrics", + createFn: func(ctx context.Context, set exporter.Settings, cfg component.Config) (component.Component, error) { + return factory.CreateMetrics(ctx, set, cfg) + }, + }, + } + + cm, err := confmaptest.LoadConf("metadata.yaml") + require.NoError(t, err) + cfg := factory.CreateDefaultConfig() + sub, err := cm.Sub("tests::config") + require.NoError(t, err) + require.NoError(t, sub.Unmarshal(&cfg)) + + for _, tt := range tests { + t.Run(tt.name+"-shutdown", func(t *testing.T) { + c, err := tt.createFn(context.Background(), exportertest.NewNopSettings(), cfg) + require.NoError(t, err) + err = c.Shutdown(context.Background()) + require.NoError(t, err) + }) + t.Run(tt.name+"-lifecycle", func(t *testing.T) { + c, err := tt.createFn(context.Background(), exportertest.NewNopSettings(), cfg) + require.NoError(t, err) + host := componenttest.NewNopHost() + err = c.Start(context.Background(), host) + require.NoError(t, err) + require.NotPanics(t, func() { + switch tt.name { + case "logs": + e, ok := c.(exporter.Logs) + require.True(t, ok) + logs := generateLifecycleTestLogs() + if !e.Capabilities().MutatesData { + logs.MarkReadOnly() + } + err = e.ConsumeLogs(context.Background(), logs) + case "metrics": + e, ok := c.(exporter.Metrics) + require.True(t, ok) + metrics := generateLifecycleTestMetrics() + if !e.Capabilities().MutatesData { + metrics.MarkReadOnly() + } + err = e.ConsumeMetrics(context.Background(), metrics) + case "traces": + e, ok := c.(exporter.Traces) + require.True(t, ok) + traces := generateLifecycleTestTraces() + if !e.Capabilities().MutatesData { + traces.MarkReadOnly() + } + err = e.ConsumeTraces(context.Background(), traces) + } + }) + + err = c.Shutdown(context.Background()) + require.NoError(t, err) + }) + } +} + +func generateLifecycleTestLogs() plog.Logs { + logs := plog.NewLogs() + rl := logs.ResourceLogs().AppendEmpty() + rl.Resource().Attributes().PutStr("resource", "R1") + l := rl.ScopeLogs().AppendEmpty().LogRecords().AppendEmpty() + l.Body().SetStr("test log message") + l.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) + return logs +} + +func generateLifecycleTestMetrics() pmetric.Metrics { + metrics := pmetric.NewMetrics() + rm := metrics.ResourceMetrics().AppendEmpty() + rm.Resource().Attributes().PutStr("resource", "R1") + m := rm.ScopeMetrics().AppendEmpty().Metrics().AppendEmpty() + m.SetName("test_metric") + dp := m.SetEmptyGauge().DataPoints().AppendEmpty() + dp.Attributes().PutStr("test_attr", "value_1") + dp.SetIntValue(123) + dp.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) + return metrics +} + +func generateLifecycleTestTraces() ptrace.Traces { + traces := ptrace.NewTraces() + rs := traces.ResourceSpans().AppendEmpty() + rs.Resource().Attributes().PutStr("resource", "R1") + span := rs.ScopeSpans().AppendEmpty().Spans().AppendEmpty() + span.Attributes().PutStr("test_attr", "value_1") + span.SetName("test_span") + span.SetStartTimestamp(pcommon.NewTimestampFromTime(time.Now().Add(-1 * time.Second))) + span.SetEndTimestamp(pcommon.NewTimestampFromTime(time.Now())) + return traces +} diff --git a/exporter/stefexporter/generated_package_test.go b/exporter/stefexporter/generated_package_test.go new file mode 100644 index 000000000000..d6c7b549b6d3 --- /dev/null +++ b/exporter/stefexporter/generated_package_test.go @@ -0,0 +1,13 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package stefexporter + +import ( + "testing" + + "go.uber.org/goleak" +) + +func TestMain(m *testing.M) { + goleak.VerifyTestMain(m) +} diff --git a/exporter/stefexporter/go.mod b/exporter/stefexporter/go.mod new file mode 100644 index 000000000000..88e2ed268a9a --- /dev/null +++ b/exporter/stefexporter/go.mod @@ -0,0 +1,77 @@ +module github.com/open-telemetry/opentelemetry-collector-contrib/exporter/stefexporter + +go 1.22.0 + +require ( + github.com/stretchr/testify v1.10.0 + go.opentelemetry.io/collector/component v0.118.1-0.20250121185328-fbefb22cc2b3 + go.opentelemetry.io/collector/component/componenttest v0.118.1-0.20250121185328-fbefb22cc2b3 + go.opentelemetry.io/collector/config/configgrpc v0.118.1-0.20250121185328-fbefb22cc2b3 + go.opentelemetry.io/collector/confmap v1.24.1-0.20250121185328-fbefb22cc2b3 + go.opentelemetry.io/collector/consumer v1.24.1-0.20250121185328-fbefb22cc2b3 + go.opentelemetry.io/collector/exporter v0.118.1-0.20250121185328-fbefb22cc2b3 + go.opentelemetry.io/collector/exporter/exportertest v0.118.1-0.20250121185328-fbefb22cc2b3 + go.opentelemetry.io/collector/pdata v1.24.1-0.20250121185328-fbefb22cc2b3 + go.uber.org/goleak v1.3.0 + go.uber.org/zap v1.27.0 +) + +require ( + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fsnotify/fsnotify v1.8.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-viper/mapstructure/v2 v2.2.1 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/hashicorp/go-version v1.7.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/knadh/koanf/maps v0.1.1 // indirect + github.com/knadh/koanf/providers/confmap v0.1.0 // indirect + github.com/knadh/koanf/v2 v2.1.2 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/mostynb/go-grpc-compression v1.2.3 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/collector/client v1.24.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/config/configauth v0.118.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/config/configcompression v1.24.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/config/confignet v1.24.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/config/configopaque v1.24.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/config/configretry v1.24.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/config/configtelemetry v0.118.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/config/configtls v1.24.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/consumer/consumererror v0.118.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/consumer/consumertest v0.118.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/consumer/xconsumer v0.118.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/exporter/xexporter v0.118.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/extension v0.118.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/extension/auth v0.118.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/extension/xextension v0.118.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/featuregate v1.24.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/pdata/pprofile v0.118.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/pipeline v0.118.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/receiver v0.118.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/receiver/receivertest v0.118.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/receiver/xreceiver v0.118.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.56.0 // 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/sys v0.29.0 // indirect + golang.org/x/text v0.21.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 // indirect + google.golang.org/grpc v1.69.4 // indirect + google.golang.org/protobuf v1.36.3 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/exporter/stefexporter/go.sum b/exporter/stefexporter/go.sum new file mode 100644 index 000000000000..e9e754e962be --- /dev/null +++ b/exporter/stefexporter/go.sum @@ -0,0 +1,190 @@ +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +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-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= +github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs= +github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= +github.com/knadh/koanf/providers/confmap v0.1.0 h1:gOkxhHkemwG4LezxxN8DMOFopOPghxRVp7JbIvdvqzU= +github.com/knadh/koanf/providers/confmap v0.1.0/go.mod h1:2uLhxQzJnyHKfxG927awZC7+fyHFdQkd697K4MdLnIU= +github.com/knadh/koanf/v2 v2.1.2 h1:I2rtLRqXRy1p01m/utEtpZSSA6dcJbgGVuE27kW2PzQ= +github.com/knadh/koanf/v2 v2.1.2/go.mod h1:Gphfaen0q1Fc1HTgJgSTC4oRX9R2R5ErYMZJy8fLJBo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mostynb/go-grpc-compression v1.2.3 h1:42/BKWMy0KEJGSdWvzqIyOZ95YcR9mLPqKctH7Uo//I= +github.com/mostynb/go-grpc-compression v1.2.3/go.mod h1:AghIxF3P57umzqM9yz795+y1Vjs47Km/Y2FE6ouQ7Lg= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/collector/client v1.24.1-0.20250121185328-fbefb22cc2b3 h1:MxzfNtItYodclGVQDLzdyBaKixbqEKC2sPGxTiY0uEE= +go.opentelemetry.io/collector/client v1.24.1-0.20250121185328-fbefb22cc2b3/go.mod h1:I5195HMWPseUSVEbNaEgMbz8rzx11T59I2YIkJQ2jrE= +go.opentelemetry.io/collector/component v0.118.1-0.20250121185328-fbefb22cc2b3 h1:ODfDW9siyGYEvEv1+oKf0abnpYbIsMwAlXuZMCUFPXw= +go.opentelemetry.io/collector/component v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:/fqrkzmOXsqm4boZaVtxi5YIz39/i8K8Wqd9oryz8Iw= +go.opentelemetry.io/collector/component/componenttest v0.118.1-0.20250121185328-fbefb22cc2b3 h1:ZnCUlmJ6ZqG+pL1fYrEXmg2FG+RxiSay5Fyxa0i79dY= +go.opentelemetry.io/collector/component/componenttest v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:eug78n4rxt5hdCSDWZ50wpYZXAl0ho/w6IsNtVZzQII= +go.opentelemetry.io/collector/config/configauth v0.118.1-0.20250121185328-fbefb22cc2b3 h1:FrH9pOMBYyhYnMCeINzeeWeT/RdcUHUnpGWooak4apM= +go.opentelemetry.io/collector/config/configauth v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:4w14UrrB+We1k+gt3/3+34SWKLKQdGDPQ/lpsL0tiHc= +go.opentelemetry.io/collector/config/configcompression v1.24.1-0.20250121185328-fbefb22cc2b3 h1:dJzzLwFqU/j3VHoaJetgUlPOzrZPtg9zUGhKVsM9WUo= +go.opentelemetry.io/collector/config/configcompression v1.24.1-0.20250121185328-fbefb22cc2b3/go.mod h1:LvYG00tbPTv0NOLoZN0wXq1F5thcxvukO8INq7xyfWU= +go.opentelemetry.io/collector/config/configgrpc v0.118.1-0.20250121185328-fbefb22cc2b3 h1:tptVdunGC+0y1KmEYvmgmLRR8Jam4y1KtfYRVoyLw5U= +go.opentelemetry.io/collector/config/configgrpc v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:R//tIJknJigDNZhuDmKiUpPrgCZ79HPKVdq0Jub3fkw= +go.opentelemetry.io/collector/config/confignet v1.24.1-0.20250121185328-fbefb22cc2b3 h1:z2wSQoQlbMfqEguwKl2NFqD3dhT9wIeRENZmadadvmg= +go.opentelemetry.io/collector/config/confignet v1.24.1-0.20250121185328-fbefb22cc2b3/go.mod h1:ZppUH1hgUJOubawEsxsQ9MzEYFytqo2GnVSS7d4CVxc= +go.opentelemetry.io/collector/config/configopaque v1.24.1-0.20250121185328-fbefb22cc2b3 h1:Oi9hXd7YIf3wa4F9SXeKwYyOkB+DRhfZgHjs44Z6jyQ= +go.opentelemetry.io/collector/config/configopaque v1.24.1-0.20250121185328-fbefb22cc2b3/go.mod h1:sW0t0iI/VfRL9VYX7Ik6XzVgPcR+Y5kejTLsYcMyDWs= +go.opentelemetry.io/collector/config/configretry v1.24.1-0.20250121185328-fbefb22cc2b3 h1:HpwrcWtvUjIIlWVseYvNemnmwtAGHLFTzfoTs2fQ2eY= +go.opentelemetry.io/collector/config/configretry v1.24.1-0.20250121185328-fbefb22cc2b3/go.mod h1:cleBc9I0DIWpTiiHfu9v83FUaCTqcPXmebpLxjEIqro= +go.opentelemetry.io/collector/config/configtelemetry v0.118.1-0.20250121185328-fbefb22cc2b3 h1:AOaJFxyz+7Zlh2AbZd7vu2gYA5a4rSItbwAS7GYAaO4= +go.opentelemetry.io/collector/config/configtelemetry v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:SlBEwQg0qly75rXZ6W1Ig8jN25KBVBkFIIAUI1GiAAE= +go.opentelemetry.io/collector/config/configtls v1.24.1-0.20250121185328-fbefb22cc2b3 h1:zeC8GoDbDxtUbEvp8sPCXONuMxqWQPowXEzUZySxSgA= +go.opentelemetry.io/collector/config/configtls v1.24.1-0.20250121185328-fbefb22cc2b3/go.mod h1:d0OdfkbuYEMYDBJLSbpH0wPI29lmSiFT3geqh/ygF2k= +go.opentelemetry.io/collector/confmap v1.24.1-0.20250121185328-fbefb22cc2b3 h1:bYJCjMGjEi0hFpVsdkg20ri5ZGhG7VfrlPjdW7FhclI= +go.opentelemetry.io/collector/confmap v1.24.1-0.20250121185328-fbefb22cc2b3/go.mod h1:Rrhs+MWoaP6AswZp+ReQ2VO9dfOfcUjdjiSHBsG+nec= +go.opentelemetry.io/collector/consumer v1.24.1-0.20250121185328-fbefb22cc2b3 h1:rMGS7YpPjLWbykAQNoBZhTZ8OONKSmnewCFggZXMPmg= +go.opentelemetry.io/collector/consumer v1.24.1-0.20250121185328-fbefb22cc2b3/go.mod h1:YyTWeyBUYlVi983ylJAY5qHnCajq67on3A59OpS6A/I= +go.opentelemetry.io/collector/consumer/consumererror v0.118.1-0.20250121185328-fbefb22cc2b3 h1:wVb72DufdN0fQoScGeK7ByM5GTf0BkdTA4ZtKOQg+RI= +go.opentelemetry.io/collector/consumer/consumererror v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:/fhqEIxH0hmnDa6zm38XzsdURr5GrlC9oKO70JVorHU= +go.opentelemetry.io/collector/consumer/consumertest v0.118.1-0.20250121185328-fbefb22cc2b3 h1:sQKFJz7EYn9e9KsgVNjnLsONuc4w3uUo2+YzM8C2jtE= +go.opentelemetry.io/collector/consumer/consumertest v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:fOVRcSFNghbaDpTJtTVHvFEQHeAAW8WEX0dYWbPpgBc= +go.opentelemetry.io/collector/consumer/xconsumer v0.118.1-0.20250121185328-fbefb22cc2b3 h1:HCyq06lz8dtWHhcKCd5BuhZBu6USgjBEuHyYhBuiw54= +go.opentelemetry.io/collector/consumer/xconsumer v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:Ij9o9d7hZb4be6ql6yqMR7xy5fcFR0SSD6RRIYWlu88= +go.opentelemetry.io/collector/exporter v0.118.1-0.20250121185328-fbefb22cc2b3 h1:E2mBzlnz7aRRCGCp5osAGDnGO+ZrCnHzkpuRvn5tSTk= +go.opentelemetry.io/collector/exporter v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:KlWSon7+gCvxsq4QWiguXq0FgUteHvH7rN4rHFQSJn4= +go.opentelemetry.io/collector/exporter/exportertest v0.118.1-0.20250121185328-fbefb22cc2b3 h1:/rnRrsOvxVsG79Oyk4dwfwTHmIs49Jnj2YvPmmbI57o= +go.opentelemetry.io/collector/exporter/exportertest v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:lNczSjG3ihPPHKTifLBoNy02XRAVKchRvGSS0QbNxZo= +go.opentelemetry.io/collector/exporter/xexporter v0.118.1-0.20250121185328-fbefb22cc2b3 h1:cHIgmy1TCOGh+Fv8C72kPYljTVC3tvUVi20PTla7yfo= +go.opentelemetry.io/collector/exporter/xexporter v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:ltZ3Qosr6DVRxe9j7KnlHQ9WTEJNnvoVhldUFVJiOWA= +go.opentelemetry.io/collector/extension v0.118.1-0.20250121185328-fbefb22cc2b3 h1:pigm8Nxub1OMInnkdu9U/Gqm0GuWmYgVUiRa0WuJmo0= +go.opentelemetry.io/collector/extension v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:7yUjnhGc/ota8nhFdLdP3trrYFx3jqtq7NAV+i04eJw= +go.opentelemetry.io/collector/extension/auth v0.118.1-0.20250121185328-fbefb22cc2b3 h1:ENw3837wlS/3iSu0BIyUNjDIQAstkdBiTaCixj6yzrA= +go.opentelemetry.io/collector/extension/auth v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:cs4Er00Asntjw7aPHRVQDvvtMzppKjRgMECa89b86AE= +go.opentelemetry.io/collector/extension/auth/authtest v0.118.0 h1:KIORXNc71vfpQrrZOntiZesRCZtQ8alrASWVT/zZkyo= +go.opentelemetry.io/collector/extension/auth/authtest v0.118.0/go.mod h1:0ZlSP9NPAfTRQd6Tx4mOH0IWrp6ufHaVN//L9Mb87gM= +go.opentelemetry.io/collector/extension/extensiontest v0.118.0 h1:rKBUaFS9elGfENG45wANmrwx7mHsmt1+YWCzxjftElg= +go.opentelemetry.io/collector/extension/extensiontest v0.118.0/go.mod h1:CqNXzkIOR32D8EUpptpOXhpFkibs3kFlRyNMEgIW8l4= +go.opentelemetry.io/collector/extension/xextension v0.118.1-0.20250121185328-fbefb22cc2b3 h1:Wd6nfGwTu6HMm+/4T37H9zkCG5XHMGIif2z/6qAamqQ= +go.opentelemetry.io/collector/extension/xextension v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:oNYxFX5QI2BUb01qZz23x4yxCletpiGwoZLB+JcHd2M= +go.opentelemetry.io/collector/featuregate v1.24.1-0.20250121185328-fbefb22cc2b3 h1:bTrqWcaRulXfpSQwnWrGlCsN4ZO5wzD931vH2E28Vc4= +go.opentelemetry.io/collector/featuregate v1.24.1-0.20250121185328-fbefb22cc2b3/go.mod h1:3GaXqflNDVwWndNGBJ1+XJFy3Fv/XrFgjMN60N3z7yg= +go.opentelemetry.io/collector/pdata v1.24.1-0.20250121185328-fbefb22cc2b3 h1:GXjNTD7hyz2Qwuu5uwLYeJTkWECWL6eL41w/JrQIJrU= +go.opentelemetry.io/collector/pdata v1.24.1-0.20250121185328-fbefb22cc2b3/go.mod h1:6lE9r5x41Z9GyvTSBetXSHRikhiZZK5ApmFtX35ZbXc= +go.opentelemetry.io/collector/pdata/pprofile v0.118.1-0.20250121185328-fbefb22cc2b3 h1:INViss+PcyyzYe/ZFHHFr/h+Mmo7n94nSzdmp68gBqI= +go.opentelemetry.io/collector/pdata/pprofile v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:iD66/nCk+xHh4q/1FBcYBQTEZKZuejggZBkm14/cobA= +go.opentelemetry.io/collector/pdata/testdata v0.118.0 h1:5N0w1SX9KIRkwvtkrpzQgXy9eGk3vfNG0ds6mhEPMIM= +go.opentelemetry.io/collector/pdata/testdata v0.118.0/go.mod h1:UY+GHV5bOC1BnFburOZ0wiHReJj1XbW12mi2Ogbc5Lw= +go.opentelemetry.io/collector/pipeline v0.118.1-0.20250121185328-fbefb22cc2b3 h1:uXvVXIkbxeEJa9L+xM7b5+2Y/LjfGKX65fQdRfW5+PQ= +go.opentelemetry.io/collector/pipeline v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:qE3DmoB05AW0C3lmPvdxZqd/H4po84NPzd5MrqgtL74= +go.opentelemetry.io/collector/receiver v0.118.1-0.20250121185328-fbefb22cc2b3 h1:uP/22oV69zYMWFdeCQHlSpVC22UZWmZsHgcdFDW89eo= +go.opentelemetry.io/collector/receiver v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:ycM9v5g4GvMspTtQbwLvmLOv4djo/bVw4RefJreGGaY= +go.opentelemetry.io/collector/receiver/receivertest v0.118.1-0.20250121185328-fbefb22cc2b3 h1:i9gXuyWdAXD+NVaGJbPnY4q+u5RwkOb/NSBnv1+IAMw= +go.opentelemetry.io/collector/receiver/receivertest v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:x9N91YI3onF0+enjYegcHYOb50Of2xO05c8EyE/baJ0= +go.opentelemetry.io/collector/receiver/xreceiver v0.118.1-0.20250121185328-fbefb22cc2b3 h1:lSOxA/PFNKwCCf0bYwOkTtvYn4Ch4QADFVJU/kuye08= +go.opentelemetry.io/collector/receiver/xreceiver v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:WLPXXIuodY7quBgqCz3OIsPNdBMLDej5nUIbiyyfoUc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.56.0 h1:yMkBS9yViCc7U7yeLzJPM2XizlfdVvBRSmsQDWu6qc0= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.56.0/go.mod h1:n8MR6/liuGB5EmTETUBeU5ZgqMOlqKRxUaqPQBOANZ8= +go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= +go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= +go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= +go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= +go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= +go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= +go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= +go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= +go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= +go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +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/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= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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-20241104194629-dd2ea8efbc28 h1:XVhgTWWV3kGQlwJHR3upFWZeTsei6Oks1apkZSeonIE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= +google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A= +google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= +google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= +google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/exporter/stefexporter/internal/metadata/generated_status.go b/exporter/stefexporter/internal/metadata/generated_status.go new file mode 100644 index 000000000000..831f424d2aa7 --- /dev/null +++ b/exporter/stefexporter/internal/metadata/generated_status.go @@ -0,0 +1,16 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package metadata + +import ( + "go.opentelemetry.io/collector/component" +) + +var ( + Type = component.MustNewType("stef") + ScopeName = "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/stefexporter" +) + +const ( + MetricsStability = component.StabilityLevelDevelopment +) diff --git a/exporter/stefexporter/metadata.yaml b/exporter/stefexporter/metadata.yaml new file mode 100644 index 000000000000..525e593c9262 --- /dev/null +++ b/exporter/stefexporter/metadata.yaml @@ -0,0 +1,13 @@ +type: stef + +status: + class: exporter + stability: + development: [metrics] + distributions: [] + codeowners: + active: [tigrannajaryan, dmitryax] +tests: + config: + endpoint: "http://localhost:0" + expect_consumer_error: true diff --git a/processor/deltatocumulativeprocessor/internal/data/add.go b/processor/deltatocumulativeprocessor/internal/data/add.go index 13b9a8151106..c1a1ee6ad8f7 100644 --- a/processor/deltatocumulativeprocessor/internal/data/add.go +++ b/processor/deltatocumulativeprocessor/internal/data/add.go @@ -80,7 +80,7 @@ func (dp ExpHistogram) Add(in ExpHistogram) ExpHistogram { // Downscale if an expected number of buckets after the merge is too large. from := expo.Scale(dp.Scale()) - to := max( + to := min( expo.Limit(maxBuckets, from, dp.Positive(), in.Positive()), expo.Limit(maxBuckets, from, dp.Negative(), in.Negative()), ) diff --git a/processor/deltatocumulativeprocessor/internal/data/expo_test.go b/processor/deltatocumulativeprocessor/internal/data/expo_test.go index 970eda2b67c7..768f1f39b1cf 100644 --- a/processor/deltatocumulativeprocessor/internal/data/expo_test.go +++ b/processor/deltatocumulativeprocessor/internal/data/expo_test.go @@ -27,10 +27,11 @@ func TestExpoAdd(t *testing.T) { defer func() { maxBuckets = prevMaxBuckets }() cases := []struct { - name string - dp, in expdp - want expdp - flip bool + name string + dp, in expdp + want expdp + flip bool + alsoTryEachSign bool }{{ name: "noop", dp: expdp{PosNeg: bins{0, 0, 0, 0, 0, 0, 0, 0}.Into(), Count: 0}, @@ -108,6 +109,7 @@ func TestExpoAdd(t *testing.T) { PosNeg: bins{3, 3, 3, 3, 3, 3, 3, 3}.Into(), Count: 24, }, + alsoTryEachSign: true, }, { name: "scale/downscale_once_exceeds_limit", dp: expdp{ @@ -125,6 +127,7 @@ func TestExpoAdd(t *testing.T) { PosNeg: rawbs([]uint64{2, 2, 2, 6, 4, 4, 4}, 0), Count: 24, }, + alsoTryEachSign: true, }, { name: "scale/downscale_multiple_times_until_within_limit", dp: expdp{ @@ -142,6 +145,7 @@ func TestExpoAdd(t *testing.T) { PosNeg: rawbs([]uint64{2, 4, 2, 4, 8, 4}, -2), Count: 24, }, + alsoTryEachSign: true, }, { name: "scale/ignore_leading_trailing_zeros_in_bucket_count", dp: expdp{ @@ -159,6 +163,7 @@ func TestExpoAdd(t *testing.T) { PosNeg: rawbs([]uint64{1, 7, 7, 4, 3, 2, 2}, 0), Count: 26, }, + alsoTryEachSign: true, }, { name: "scale/downscale_with_leading_trailing_zeros", dp: expdp{ @@ -176,17 +181,18 @@ func TestExpoAdd(t *testing.T) { PosNeg: rawbs([]uint64{11, 11, 0, 0, 12, 12}, -1), Count: 46, }, + alsoTryEachSign: true, }} for _, cs := range cases { - run := func(dp, in expdp) func(t *testing.T) { + run := func(dp, in, want expdp) func(t *testing.T) { return func(t *testing.T) { is := datatest.New(t) var ( dp = ExpHistogram{dp.Into()} in = ExpHistogram{in.Into()} - want = ExpHistogram{cs.want.Into()} + want = ExpHistogram{want.Into()} ) dp.SetTimestamp(0) @@ -199,14 +205,32 @@ func TestExpoAdd(t *testing.T) { } if cs.flip { - t.Run(cs.name+"-dp", run(cs.dp, cs.in)) - t.Run(cs.name+"-in", run(cs.in, cs.dp)) + t.Run(cs.name+"-dp", run(cs.dp, cs.in, cs.want)) + t.Run(cs.name+"-in", run(cs.in, cs.dp, cs.want)) continue } - t.Run(cs.name, run(cs.dp, cs.in)) + if cs.alsoTryEachSign { + t.Run(cs.name+"-pos", run(clonePosExpdp(cs.dp), clonePosExpdp(cs.in), clonePosExpdp(cs.want))) + t.Run(cs.name+"-neg", run(cloneNegExpdp(cs.dp), cloneNegExpdp(cs.in), cloneNegExpdp(cs.want))) + } + t.Run(cs.name, run(cs.dp, cs.in, cs.want)) } } +func cloneNegExpdp(dp expotest.Histogram) expotest.Histogram { + dp.Neg = pmetric.NewExponentialHistogramDataPointBuckets() + dp.PosNeg.CopyTo(dp.Neg) + dp.PosNeg = expo.Buckets{} + return dp +} + +func clonePosExpdp(dp expotest.Histogram) expotest.Histogram { + dp.Pos = pmetric.NewExponentialHistogramDataPointBuckets() + dp.PosNeg.CopyTo(dp.Pos) + dp.PosNeg = expo.Buckets{} + return dp +} + func rawbs(data []uint64, offset int32) expo.Buckets { bs := pmetric.NewExponentialHistogramDataPointBuckets() bs.BucketCounts().FromRaw(data) diff --git a/receiver/envoyalsreceiver/Makefile b/receiver/envoyalsreceiver/Makefile new file mode 100644 index 000000000000..ded7a36092dc --- /dev/null +++ b/receiver/envoyalsreceiver/Makefile @@ -0,0 +1 @@ +include ../../Makefile.Common diff --git a/receiver/envoyalsreceiver/README.md b/receiver/envoyalsreceiver/README.md new file mode 100644 index 000000000000..1ef1fb384c17 --- /dev/null +++ b/receiver/envoyalsreceiver/README.md @@ -0,0 +1,44 @@ +# Envoy ALS(access log service) receiver + + +| Status | | +| ------------- |-----------| +| Stability | [development]: logs | +| Distributions | [] | +| Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aopen%20label%3Areceiver%2Fenvoyals%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Areceiver%2Fenvoyals) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aclosed%20label%3Areceiver%2Fenvoyals%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aclosed+is%3Aissue+label%3Areceiver%2Fenvoyals) | +| [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@evan-bradley](https://www.github.com/evan-bradley) | + +[development]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#development + + +This is a receiver for the [Envoy gRPC ALS](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/access_loggers/grpc/v3/als.proto#envoy-v3-api-msg-extensions-access-loggers-grpc-v3-httpgrpcaccesslogconfig) sink. + +Envoy ALS (Access Log Service) is a feature of Envoy Proxy that allows for the +centralized collection and management of access logs. + +Instead of writing access logs to local files, Envoy can be configured to send these logs to a remote gRPC service. + +This is particularly useful in distributed systems where centralized logging is required for monitoring, auditing, and debugging purposes. + +[Istio](https://istio.io) and [Envoy Gateway](https://gateway.envoyproxy.io) support OTLP and gRPC ALS with first class API. + +## Getting Started + +The settings are: + +- `endpoint` (required, default = localhost:19001 gRPC protocol): host:port to which the receiver is going to receive data. See our [security best practices doc](https://opentelemetry.io/docs/security/config-best-practices/#protect-against-denial-of-service-attacks) to understand how to set the endpoint in different environments. + +Example: +```yaml +receivers: + envoyals: + endpoint: 0.0.0.0:3500 +``` + +## Advanced Configuration + +Other options can be configured to support more advanced use cases: + +- [gRPC settings](https://github.com/open-telemetry/opentelemetry-collector/blob/main/config/configgrpc/README.md) including CORS +- [TLS and mTLS settings](https://github.com/open-telemetry/opentelemetry-collector/blob/main/config/configtls/README.md) + diff --git a/receiver/envoyalsreceiver/als.go b/receiver/envoyalsreceiver/als.go new file mode 100644 index 000000000000..f9a32e87a3ca --- /dev/null +++ b/receiver/envoyalsreceiver/als.go @@ -0,0 +1,90 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package envoyalsreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/envoyalsreceiver" + +import ( + "context" + "errors" + "fmt" + + alsv3 "github.com/envoyproxy/go-control-plane/envoy/service/accesslog/v3" + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componentstatus" + "go.opentelemetry.io/collector/consumer" + "go.opentelemetry.io/collector/receiver" + "go.opentelemetry.io/collector/receiver/receiverhelper" + "go.uber.org/zap" + "google.golang.org/grpc" + + "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/envoyalsreceiver/internal/als" +) + +type alsReceiver struct { + conf *Config + nextConsumer consumer.Logs + settings receiver.Settings + serverGRPC *grpc.Server + + obsrepGRPC *receiverhelper.ObsReport +} + +func (r *alsReceiver) Start(ctx context.Context, host component.Host) error { + var err error + r.serverGRPC, err = r.conf.ToServer(ctx, host, r.settings.TelemetrySettings) + if err != nil { + return fmt.Errorf("failed create grpc server error: %w", err) + } + + alsv3.RegisterAccessLogServiceServer(r.serverGRPC, als.New(r.nextConsumer, r.obsrepGRPC)) + + err = r.startGRPCServer(ctx, host) + if err != nil { + return fmt.Errorf("failed to start grpc server error: %w", err) + } + + return err +} + +func (r *alsReceiver) startGRPCServer(ctx context.Context, host component.Host) error { + r.settings.Logger.Info("Starting GRPC server", zap.String("endpoint", r.conf.NetAddr.Endpoint)) + listener, err := r.conf.NetAddr.Listen(ctx) + if err != nil { + return err + } + + go func() { + if errGRPC := r.serverGRPC.Serve(listener); !errors.Is(errGRPC, grpc.ErrServerStopped) && errGRPC != nil { + componentstatus.ReportStatus(host, componentstatus.NewFatalErrorEvent(errGRPC)) + } + }() + return nil +} + +func (r *alsReceiver) Shutdown(_ context.Context) error { + if r.serverGRPC != nil { + r.serverGRPC.GracefulStop() + } + + return nil +} + +func newALSReceiver(cfg *Config, nextConsumer consumer.Logs, settings receiver.Settings) (*alsReceiver, error) { + r := &alsReceiver{ + conf: cfg, + nextConsumer: nextConsumer, + settings: settings, + } + + var err error + r.obsrepGRPC, err = receiverhelper.NewObsReport(receiverhelper.ObsReportSettings{ + ReceiverID: settings.ID, + Transport: "grpc", + ReceiverCreateSettings: settings, + }) + if err != nil { + return nil, err + } + + return r, nil +} diff --git a/receiver/envoyalsreceiver/als_test.go b/receiver/envoyalsreceiver/als_test.go new file mode 100644 index 000000000000..ef11a6e2233c --- /dev/null +++ b/receiver/envoyalsreceiver/als_test.go @@ -0,0 +1,188 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package envoyalsreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/envoyalsreceiver" + +import ( + "context" + "testing" + "time" + + corev3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" + alsdata "github.com/envoyproxy/go-control-plane/envoy/data/accesslog/v3" + alsv3 "github.com/envoyproxy/go-control-plane/envoy/service/accesslog/v3" + "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/config/configgrpc" + "go.opentelemetry.io/collector/config/confignet" + "go.opentelemetry.io/collector/consumer/consumertest" + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/plog" + "go.opentelemetry.io/collector/receiver/receivertest" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/protobuf/types/known/timestamppb" + "google.golang.org/protobuf/types/known/wrapperspb" + + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/common/testutil" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest/plogtest" +) + +func startGRPCServer(t *testing.T) (*grpc.ClientConn, *consumertest.LogsSink) { + config := &Config{ + ServerConfig: configgrpc.ServerConfig{ + NetAddr: confignet.AddrConfig{ + Endpoint: testutil.GetAvailableLocalAddress(t), + Transport: confignet.TransportTypeTCP, + }, + }, + } + sink := new(consumertest.LogsSink) + + set := receivertest.NewNopSettings() + lr, err := newALSReceiver(config, sink, set) + require.NoError(t, err) + + require.NoError(t, lr.Start(context.Background(), componenttest.NewNopHost())) + t.Cleanup(func() { require.NoError(t, lr.Shutdown(context.Background())) }) + + conn, err := grpc.NewClient(config.NetAddr.Endpoint, grpc.WithTransportCredentials(insecure.NewCredentials())) + require.NoError(t, err) + return conn, sink +} + +func TestLogs(t *testing.T) { + // Start grpc server + conn, sink := startGRPCServer(t) + defer func() { + _ = conn.Close() + }() + + client, err := alsv3.NewAccessLogServiceClient(conn).StreamAccessLogs(context.Background()) + require.NoError(t, err) + + tm, err := time.Parse(time.RFC3339Nano, "2020-07-30T01:01:01.123456789Z") + require.NoError(t, err) + ts := int64(pcommon.NewTimestampFromTime(tm)) + + identifier := &alsv3.StreamAccessLogsMessage_Identifier{ + Node: &corev3.Node{ + Id: "test-id", + Cluster: "test-cluster", + }, + LogName: "test-log-name", + } + + httpLog := &alsdata.HTTPAccessLogEntry{ + CommonProperties: &alsdata.AccessLogCommon{ + StartTime: timestamppb.New(tm), + }, + Request: &alsdata.HTTPRequestProperties{ + Path: "/test", + Authority: "example.com", + }, + Response: &alsdata.HTTPResponseProperties{ + ResponseCode: wrapperspb.UInt32(200), + }, + } + + tcpLog := &alsdata.TCPAccessLogEntry{ + CommonProperties: &alsdata.AccessLogCommon{ + StartTime: timestamppb.New(tm), + }, + ConnectionProperties: &alsdata.ConnectionProperties{ + ReceivedBytes: 10, + SentBytes: 20, + }, + } + + tests := []struct { + name string + message *alsv3.StreamAccessLogsMessage + expected plog.Logs + }{ + { + name: "http", + message: &alsv3.StreamAccessLogsMessage{ + Identifier: identifier, + LogEntries: &alsv3.StreamAccessLogsMessage_HttpLogs{ + HttpLogs: &alsv3.StreamAccessLogsMessage_HTTPAccessLogEntries{ + LogEntry: []*alsdata.HTTPAccessLogEntry{ + httpLog, + }, + }, + }, + }, + expected: generateLogs([]Log{ + { + Timestamp: ts, + Attributes: map[string]any{ + "api_version": "v3", + "log_type": "http", + }, + Body: pcommon.NewValueStr(httpLog.String()), + }, + }), + }, + { + name: "tcp", + message: &alsv3.StreamAccessLogsMessage{ + Identifier: identifier, + LogEntries: &alsv3.StreamAccessLogsMessage_TcpLogs{ + TcpLogs: &alsv3.StreamAccessLogsMessage_TCPAccessLogEntries{ + LogEntry: []*alsdata.TCPAccessLogEntry{ + tcpLog, + }, + }, + }, + }, + expected: generateLogs([]Log{ + { + Timestamp: ts, + Attributes: map[string]any{ + "api_version": "v3", + "log_type": "tcp", + }, + Body: pcommon.NewValueStr(tcpLog.String()), + }, + }), + }, + } + + for i, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err = client.Send(tt.message) + require.NoError(t, err, "should not have failed to post logs") + + require.Eventually(t, func() bool { + gotLogs := sink.AllLogs() + + err := plogtest.CompareLogs(tt.expected, gotLogs[i], plogtest.IgnoreObservedTimestamp()) + if err == nil { + return true + } + t.Logf("Logs not received yet: %v", err) + return false + }, 5*time.Second, 100*time.Millisecond) + }) + } +} + +type Log struct { + Timestamp int64 + Body pcommon.Value + Attributes map[string]any +} + +func generateLogs(logs []Log) plog.Logs { + ld := plog.NewLogs() + logSlice := ld.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords() + + for _, log := range logs { + lr := logSlice.AppendEmpty() + _ = lr.Attributes().FromRaw(log.Attributes) + lr.SetTimestamp(pcommon.Timestamp(log.Timestamp)) + lr.Body().SetStr(log.Body.AsString()) + } + return ld +} diff --git a/receiver/envoyalsreceiver/config.go b/receiver/envoyalsreceiver/config.go new file mode 100644 index 000000000000..57a183022723 --- /dev/null +++ b/receiver/envoyalsreceiver/config.go @@ -0,0 +1,15 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package envoyalsreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/envoyalsreceiver" + +import ( + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/config/configgrpc" +) + +type Config struct { + configgrpc.ServerConfig `mapstructure:",squash"` +} + +var _ component.Config = (*Config)(nil) diff --git a/receiver/envoyalsreceiver/config_test.go b/receiver/envoyalsreceiver/config_test.go new file mode 100644 index 000000000000..c14d9d145d7e --- /dev/null +++ b/receiver/envoyalsreceiver/config_test.go @@ -0,0 +1,67 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package envoyalsreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/envoyalsreceiver" + +import ( + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/config/configgrpc" + "go.opentelemetry.io/collector/config/confignet" + "go.opentelemetry.io/collector/confmap/confmaptest" + + "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/envoyalsreceiver/internal/metadata" +) + +func TestLoadConfig(t *testing.T) { + t.Parallel() + + cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) + require.NoError(t, err) + + tests := []struct { + id component.ID + expected component.Config + }{ + { + id: component.NewIDWithName(metadata.Type, "defaults"), + expected: &Config{ + ServerConfig: configgrpc.ServerConfig{ + NetAddr: confignet.AddrConfig{ + Endpoint: "localhost:19001", + Transport: confignet.TransportTypeTCP, + }, + }, + }, + }, + { + id: component.NewIDWithName(metadata.Type, "custom"), + expected: &Config{ + ServerConfig: configgrpc.ServerConfig{ + NetAddr: confignet.AddrConfig{ + Endpoint: "localhost:4600", + Transport: confignet.TransportTypeTCP, + }, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.id.String(), func(t *testing.T) { + factory := NewFactory() + cfg := factory.CreateDefaultConfig() + + sub, err := cm.Sub(tt.id.String()) + require.NoError(t, err) + require.NoError(t, sub.Unmarshal(cfg)) + + assert.NoError(t, component.ValidateConfig(cfg)) + assert.Equal(t, tt.expected, cfg) + }) + } +} diff --git a/receiver/envoyalsreceiver/doc.go b/receiver/envoyalsreceiver/doc.go new file mode 100644 index 000000000000..0b647b53c155 --- /dev/null +++ b/receiver/envoyalsreceiver/doc.go @@ -0,0 +1,6 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +//go:generate mdatagen metadata.yaml + +package envoyalsreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/envoyalsreceiver" diff --git a/receiver/envoyalsreceiver/factory.go b/receiver/envoyalsreceiver/factory.go new file mode 100644 index 000000000000..bfbb2cee4a1f --- /dev/null +++ b/receiver/envoyalsreceiver/factory.go @@ -0,0 +1,49 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package envoyalsreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/envoyalsreceiver" + +import ( + "context" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/config/configgrpc" + "go.opentelemetry.io/collector/config/confignet" + "go.opentelemetry.io/collector/consumer" + "go.opentelemetry.io/collector/receiver" + + "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/envoyalsreceiver/internal/metadata" +) + +const ( + defaultGRPCEndpoint = "localhost:19001" +) + +// NewFactory creates a new ALS receiver factory. +func NewFactory() receiver.Factory { + return receiver.NewFactory( + metadata.Type, + createDefaultConfig, + receiver.WithLogs(newReceiver, metadata.LogsStability)) +} + +func createDefaultConfig() component.Config { + return &Config{ + ServerConfig: configgrpc.ServerConfig{ + NetAddr: confignet.AddrConfig{ + Endpoint: defaultGRPCEndpoint, + Transport: confignet.TransportTypeTCP, + }, + }, + } +} + +func newReceiver( + _ context.Context, + st receiver.Settings, + cfg component.Config, + consumer consumer.Logs, +) (receiver.Logs, error) { + alsCfg := cfg.(*Config) + return newALSReceiver(alsCfg, consumer, st) +} diff --git a/receiver/envoyalsreceiver/factory_test.go b/receiver/envoyalsreceiver/factory_test.go new file mode 100644 index 000000000000..7ba5941f65b8 --- /dev/null +++ b/receiver/envoyalsreceiver/factory_test.go @@ -0,0 +1,38 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package envoyalsreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/envoyalsreceiver" + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/config/configgrpc" + "go.opentelemetry.io/collector/config/confignet" + "go.opentelemetry.io/collector/consumer/consumertest" + "go.opentelemetry.io/collector/receiver/receivertest" +) + +func TestCreateDefaultConfig(t *testing.T) { + factory := NewFactory() + cfg := factory.CreateDefaultConfig() + require.NotNil(t, cfg, "failed to create default config") + require.NoError(t, componenttest.CheckConfigStruct(cfg)) +} + +func TestCreateReceiver(t *testing.T) { + factory := NewFactory() + cfg := factory.CreateDefaultConfig() + cfg.(*Config).ServerConfig = configgrpc.ServerConfig{ + NetAddr: confignet.AddrConfig{ + Endpoint: defaultGRPCEndpoint, + Transport: confignet.TransportTypeTCP, + }, + } + set := receivertest.NewNopSettings() + receiver, err := factory.CreateLogs(context.Background(), set, cfg, consumertest.NewNop()) + require.NoError(t, err, "receiver creation failed") + require.NotNil(t, receiver, "receiver creation failed") +} diff --git a/receiver/envoyalsreceiver/generated_component_test.go b/receiver/envoyalsreceiver/generated_component_test.go new file mode 100644 index 000000000000..35150d9f1ce0 --- /dev/null +++ b/receiver/envoyalsreceiver/generated_component_test.go @@ -0,0 +1,69 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package envoyalsreceiver + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/confmap/confmaptest" + "go.opentelemetry.io/collector/consumer/consumertest" + "go.opentelemetry.io/collector/receiver" + "go.opentelemetry.io/collector/receiver/receivertest" +) + +func TestComponentFactoryType(t *testing.T) { + require.Equal(t, "envoyals", NewFactory().Type().String()) +} + +func TestComponentConfigStruct(t *testing.T) { + require.NoError(t, componenttest.CheckConfigStruct(NewFactory().CreateDefaultConfig())) +} + +func TestComponentLifecycle(t *testing.T) { + factory := NewFactory() + + tests := []struct { + name string + createFn func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) + }{ + + { + name: "logs", + createFn: func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) { + return factory.CreateLogs(ctx, set, cfg, consumertest.NewNop()) + }, + }, + } + + cm, err := confmaptest.LoadConf("metadata.yaml") + require.NoError(t, err) + cfg := factory.CreateDefaultConfig() + sub, err := cm.Sub("tests::config") + require.NoError(t, err) + require.NoError(t, sub.Unmarshal(&cfg)) + + for _, tt := range tests { + t.Run(tt.name+"-shutdown", func(t *testing.T) { + c, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + require.NoError(t, err) + err = c.Shutdown(context.Background()) + require.NoError(t, err) + }) + t.Run(tt.name+"-lifecycle", func(t *testing.T) { + firstRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + require.NoError(t, err) + host := componenttest.NewNopHost() + require.NoError(t, err) + require.NoError(t, firstRcvr.Start(context.Background(), host)) + require.NoError(t, firstRcvr.Shutdown(context.Background())) + secondRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + require.NoError(t, err) + require.NoError(t, secondRcvr.Start(context.Background(), host)) + require.NoError(t, secondRcvr.Shutdown(context.Background())) + }) + } +} diff --git a/receiver/envoyalsreceiver/generated_package_test.go b/receiver/envoyalsreceiver/generated_package_test.go new file mode 100644 index 000000000000..2e965ab81961 --- /dev/null +++ b/receiver/envoyalsreceiver/generated_package_test.go @@ -0,0 +1,13 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package envoyalsreceiver + +import ( + "testing" + + "go.uber.org/goleak" +) + +func TestMain(m *testing.M) { + goleak.VerifyTestMain(m) +} diff --git a/receiver/envoyalsreceiver/go.mod b/receiver/envoyalsreceiver/go.mod new file mode 100644 index 000000000000..6030ed07c479 --- /dev/null +++ b/receiver/envoyalsreceiver/go.mod @@ -0,0 +1,88 @@ +module github.com/open-telemetry/opentelemetry-collector-contrib/receiver/envoyalsreceiver + +go 1.22.0 + +require ( + github.com/envoyproxy/go-control-plane v0.13.1 + github.com/open-telemetry/opentelemetry-collector-contrib/internal/common v0.117.0 + github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.117.0 + github.com/stretchr/testify v1.10.0 + go.opentelemetry.io/collector/component v0.118.1-0.20250121185328-fbefb22cc2b3 + go.opentelemetry.io/collector/component/componentstatus v0.118.1-0.20250121185328-fbefb22cc2b3 + go.opentelemetry.io/collector/component/componenttest v0.118.1-0.20250121185328-fbefb22cc2b3 + go.opentelemetry.io/collector/config/configgrpc v0.118.1-0.20250121185328-fbefb22cc2b3 + go.opentelemetry.io/collector/config/confignet v1.24.1-0.20250121185328-fbefb22cc2b3 + go.opentelemetry.io/collector/confmap v1.24.1-0.20250121185328-fbefb22cc2b3 + go.opentelemetry.io/collector/consumer v1.24.1-0.20250121185328-fbefb22cc2b3 + go.opentelemetry.io/collector/consumer/consumertest v0.118.1-0.20250121185328-fbefb22cc2b3 + go.opentelemetry.io/collector/pdata v1.24.1-0.20250121185328-fbefb22cc2b3 + go.opentelemetry.io/collector/receiver v0.118.1-0.20250121185328-fbefb22cc2b3 + go.opentelemetry.io/collector/receiver/receivertest v0.118.1-0.20250121185328-fbefb22cc2b3 + go.uber.org/goleak v1.3.0 + go.uber.org/zap v1.27.0 + google.golang.org/grpc v1.69.4 + google.golang.org/protobuf v1.36.3 +) + +require ( + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect + github.com/fsnotify/fsnotify v1.8.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-viper/mapstructure/v2 v2.2.1 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/hashicorp/go-version v1.7.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.17.11 // indirect + github.com/knadh/koanf/maps v0.1.1 // indirect + github.com/knadh/koanf/providers/confmap v0.1.0 // indirect + github.com/knadh/koanf/v2 v2.1.2 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/mostynb/go-grpc-compression v1.2.3 // indirect + github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.118.0 // indirect + github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/collector/client v1.24.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/config/configauth v0.118.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/config/configcompression v1.24.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/config/configopaque v1.24.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/config/configtelemetry v0.118.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/config/configtls v1.24.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/consumer/consumererror v0.118.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/consumer/xconsumer v0.118.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/extension v0.118.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/extension/auth v0.118.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/featuregate v1.24.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/pdata/pprofile v0.118.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/pipeline v0.118.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/collector/receiver/xreceiver v0.118.1-0.20250121185328-fbefb22cc2b3 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.56.0 // 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.34.0 // indirect + golang.org/x/sys v0.29.0 // indirect + golang.org/x/text v0.21.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) + +replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest => ../../pkg/pdatatest + +replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden => ../../pkg/golden + +replace github.com/open-telemetry/opentelemetry-collector-contrib/internal/common => ../../internal/common + +replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil => ../../pkg/pdatautil diff --git a/receiver/envoyalsreceiver/go.sum b/receiver/envoyalsreceiver/go.sum new file mode 100644 index 000000000000..b889a68270a8 --- /dev/null +++ b/receiver/envoyalsreceiver/go.sum @@ -0,0 +1,188 @@ +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 h1:QVw89YDxXxEe+l8gU8ETbOasdwEV+avkR75ZzsVV9WI= +github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.13.1 h1:vPfJZCkob6yTMEgS+0TwfTUfbHjfy/6vOJ8hUWX/uXE= +github.com/envoyproxy/go-control-plane v0.13.1/go.mod h1:X45hY0mufo6Fd0KW3rqsGvQMw58jvjymeCzBU3mWyHw= +github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM= +github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= +github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +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-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= +github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs= +github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= +github.com/knadh/koanf/providers/confmap v0.1.0 h1:gOkxhHkemwG4LezxxN8DMOFopOPghxRVp7JbIvdvqzU= +github.com/knadh/koanf/providers/confmap v0.1.0/go.mod h1:2uLhxQzJnyHKfxG927awZC7+fyHFdQkd697K4MdLnIU= +github.com/knadh/koanf/v2 v2.1.2 h1:I2rtLRqXRy1p01m/utEtpZSSA6dcJbgGVuE27kW2PzQ= +github.com/knadh/koanf/v2 v2.1.2/go.mod h1:Gphfaen0q1Fc1HTgJgSTC4oRX9R2R5ErYMZJy8fLJBo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mostynb/go-grpc-compression v1.2.3 h1:42/BKWMy0KEJGSdWvzqIyOZ95YcR9mLPqKctH7Uo//I= +github.com/mostynb/go-grpc-compression v1.2.3/go.mod h1:AghIxF3P57umzqM9yz795+y1Vjs47Km/Y2FE6ouQ7Lg= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/collector/client v1.24.1-0.20250121185328-fbefb22cc2b3 h1:MxzfNtItYodclGVQDLzdyBaKixbqEKC2sPGxTiY0uEE= +go.opentelemetry.io/collector/client v1.24.1-0.20250121185328-fbefb22cc2b3/go.mod h1:I5195HMWPseUSVEbNaEgMbz8rzx11T59I2YIkJQ2jrE= +go.opentelemetry.io/collector/component v0.118.1-0.20250121185328-fbefb22cc2b3 h1:ODfDW9siyGYEvEv1+oKf0abnpYbIsMwAlXuZMCUFPXw= +go.opentelemetry.io/collector/component v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:/fqrkzmOXsqm4boZaVtxi5YIz39/i8K8Wqd9oryz8Iw= +go.opentelemetry.io/collector/component/componentstatus v0.118.1-0.20250121185328-fbefb22cc2b3 h1:anyK0wvAeTO3QpO2AvVGXaN7t9K/CWQXSHii+0Ygr8o= +go.opentelemetry.io/collector/component/componentstatus v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:V84x0j/NyHPJciFJ5R8DrJrTOgkYFkyXTh7TXQYvol4= +go.opentelemetry.io/collector/component/componenttest v0.118.1-0.20250121185328-fbefb22cc2b3 h1:ZnCUlmJ6ZqG+pL1fYrEXmg2FG+RxiSay5Fyxa0i79dY= +go.opentelemetry.io/collector/component/componenttest v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:eug78n4rxt5hdCSDWZ50wpYZXAl0ho/w6IsNtVZzQII= +go.opentelemetry.io/collector/config/configauth v0.118.1-0.20250121185328-fbefb22cc2b3 h1:FrH9pOMBYyhYnMCeINzeeWeT/RdcUHUnpGWooak4apM= +go.opentelemetry.io/collector/config/configauth v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:4w14UrrB+We1k+gt3/3+34SWKLKQdGDPQ/lpsL0tiHc= +go.opentelemetry.io/collector/config/configcompression v1.24.1-0.20250121185328-fbefb22cc2b3 h1:dJzzLwFqU/j3VHoaJetgUlPOzrZPtg9zUGhKVsM9WUo= +go.opentelemetry.io/collector/config/configcompression v1.24.1-0.20250121185328-fbefb22cc2b3/go.mod h1:LvYG00tbPTv0NOLoZN0wXq1F5thcxvukO8INq7xyfWU= +go.opentelemetry.io/collector/config/configgrpc v0.118.1-0.20250121185328-fbefb22cc2b3 h1:tptVdunGC+0y1KmEYvmgmLRR8Jam4y1KtfYRVoyLw5U= +go.opentelemetry.io/collector/config/configgrpc v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:R//tIJknJigDNZhuDmKiUpPrgCZ79HPKVdq0Jub3fkw= +go.opentelemetry.io/collector/config/confignet v1.24.1-0.20250121185328-fbefb22cc2b3 h1:z2wSQoQlbMfqEguwKl2NFqD3dhT9wIeRENZmadadvmg= +go.opentelemetry.io/collector/config/confignet v1.24.1-0.20250121185328-fbefb22cc2b3/go.mod h1:ZppUH1hgUJOubawEsxsQ9MzEYFytqo2GnVSS7d4CVxc= +go.opentelemetry.io/collector/config/configopaque v1.24.1-0.20250121185328-fbefb22cc2b3 h1:Oi9hXd7YIf3wa4F9SXeKwYyOkB+DRhfZgHjs44Z6jyQ= +go.opentelemetry.io/collector/config/configopaque v1.24.1-0.20250121185328-fbefb22cc2b3/go.mod h1:sW0t0iI/VfRL9VYX7Ik6XzVgPcR+Y5kejTLsYcMyDWs= +go.opentelemetry.io/collector/config/configtelemetry v0.118.1-0.20250121185328-fbefb22cc2b3 h1:AOaJFxyz+7Zlh2AbZd7vu2gYA5a4rSItbwAS7GYAaO4= +go.opentelemetry.io/collector/config/configtelemetry v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:SlBEwQg0qly75rXZ6W1Ig8jN25KBVBkFIIAUI1GiAAE= +go.opentelemetry.io/collector/config/configtls v1.24.1-0.20250121185328-fbefb22cc2b3 h1:zeC8GoDbDxtUbEvp8sPCXONuMxqWQPowXEzUZySxSgA= +go.opentelemetry.io/collector/config/configtls v1.24.1-0.20250121185328-fbefb22cc2b3/go.mod h1:d0OdfkbuYEMYDBJLSbpH0wPI29lmSiFT3geqh/ygF2k= +go.opentelemetry.io/collector/confmap v1.24.1-0.20250121185328-fbefb22cc2b3 h1:bYJCjMGjEi0hFpVsdkg20ri5ZGhG7VfrlPjdW7FhclI= +go.opentelemetry.io/collector/confmap v1.24.1-0.20250121185328-fbefb22cc2b3/go.mod h1:Rrhs+MWoaP6AswZp+ReQ2VO9dfOfcUjdjiSHBsG+nec= +go.opentelemetry.io/collector/consumer v1.24.1-0.20250121185328-fbefb22cc2b3 h1:rMGS7YpPjLWbykAQNoBZhTZ8OONKSmnewCFggZXMPmg= +go.opentelemetry.io/collector/consumer v1.24.1-0.20250121185328-fbefb22cc2b3/go.mod h1:YyTWeyBUYlVi983ylJAY5qHnCajq67on3A59OpS6A/I= +go.opentelemetry.io/collector/consumer/consumererror v0.118.1-0.20250121185328-fbefb22cc2b3 h1:wVb72DufdN0fQoScGeK7ByM5GTf0BkdTA4ZtKOQg+RI= +go.opentelemetry.io/collector/consumer/consumererror v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:/fhqEIxH0hmnDa6zm38XzsdURr5GrlC9oKO70JVorHU= +go.opentelemetry.io/collector/consumer/consumertest v0.118.1-0.20250121185328-fbefb22cc2b3 h1:sQKFJz7EYn9e9KsgVNjnLsONuc4w3uUo2+YzM8C2jtE= +go.opentelemetry.io/collector/consumer/consumertest v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:fOVRcSFNghbaDpTJtTVHvFEQHeAAW8WEX0dYWbPpgBc= +go.opentelemetry.io/collector/consumer/xconsumer v0.118.1-0.20250121185328-fbefb22cc2b3 h1:HCyq06lz8dtWHhcKCd5BuhZBu6USgjBEuHyYhBuiw54= +go.opentelemetry.io/collector/consumer/xconsumer v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:Ij9o9d7hZb4be6ql6yqMR7xy5fcFR0SSD6RRIYWlu88= +go.opentelemetry.io/collector/extension v0.118.1-0.20250121185328-fbefb22cc2b3 h1:pigm8Nxub1OMInnkdu9U/Gqm0GuWmYgVUiRa0WuJmo0= +go.opentelemetry.io/collector/extension v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:7yUjnhGc/ota8nhFdLdP3trrYFx3jqtq7NAV+i04eJw= +go.opentelemetry.io/collector/extension/auth v0.118.1-0.20250121185328-fbefb22cc2b3 h1:ENw3837wlS/3iSu0BIyUNjDIQAstkdBiTaCixj6yzrA= +go.opentelemetry.io/collector/extension/auth v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:cs4Er00Asntjw7aPHRVQDvvtMzppKjRgMECa89b86AE= +go.opentelemetry.io/collector/extension/auth/authtest v0.118.0 h1:KIORXNc71vfpQrrZOntiZesRCZtQ8alrASWVT/zZkyo= +go.opentelemetry.io/collector/extension/auth/authtest v0.118.0/go.mod h1:0ZlSP9NPAfTRQd6Tx4mOH0IWrp6ufHaVN//L9Mb87gM= +go.opentelemetry.io/collector/featuregate v1.24.1-0.20250121185328-fbefb22cc2b3 h1:bTrqWcaRulXfpSQwnWrGlCsN4ZO5wzD931vH2E28Vc4= +go.opentelemetry.io/collector/featuregate v1.24.1-0.20250121185328-fbefb22cc2b3/go.mod h1:3GaXqflNDVwWndNGBJ1+XJFy3Fv/XrFgjMN60N3z7yg= +go.opentelemetry.io/collector/pdata v1.24.1-0.20250121185328-fbefb22cc2b3 h1:GXjNTD7hyz2Qwuu5uwLYeJTkWECWL6eL41w/JrQIJrU= +go.opentelemetry.io/collector/pdata v1.24.1-0.20250121185328-fbefb22cc2b3/go.mod h1:6lE9r5x41Z9GyvTSBetXSHRikhiZZK5ApmFtX35ZbXc= +go.opentelemetry.io/collector/pdata/pprofile v0.118.1-0.20250121185328-fbefb22cc2b3 h1:INViss+PcyyzYe/ZFHHFr/h+Mmo7n94nSzdmp68gBqI= +go.opentelemetry.io/collector/pdata/pprofile v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:iD66/nCk+xHh4q/1FBcYBQTEZKZuejggZBkm14/cobA= +go.opentelemetry.io/collector/pdata/testdata v0.118.0 h1:5N0w1SX9KIRkwvtkrpzQgXy9eGk3vfNG0ds6mhEPMIM= +go.opentelemetry.io/collector/pdata/testdata v0.118.0/go.mod h1:UY+GHV5bOC1BnFburOZ0wiHReJj1XbW12mi2Ogbc5Lw= +go.opentelemetry.io/collector/pipeline v0.118.1-0.20250121185328-fbefb22cc2b3 h1:uXvVXIkbxeEJa9L+xM7b5+2Y/LjfGKX65fQdRfW5+PQ= +go.opentelemetry.io/collector/pipeline v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:qE3DmoB05AW0C3lmPvdxZqd/H4po84NPzd5MrqgtL74= +go.opentelemetry.io/collector/receiver v0.118.1-0.20250121185328-fbefb22cc2b3 h1:uP/22oV69zYMWFdeCQHlSpVC22UZWmZsHgcdFDW89eo= +go.opentelemetry.io/collector/receiver v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:ycM9v5g4GvMspTtQbwLvmLOv4djo/bVw4RefJreGGaY= +go.opentelemetry.io/collector/receiver/receivertest v0.118.1-0.20250121185328-fbefb22cc2b3 h1:i9gXuyWdAXD+NVaGJbPnY4q+u5RwkOb/NSBnv1+IAMw= +go.opentelemetry.io/collector/receiver/receivertest v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:x9N91YI3onF0+enjYegcHYOb50Of2xO05c8EyE/baJ0= +go.opentelemetry.io/collector/receiver/xreceiver v0.118.1-0.20250121185328-fbefb22cc2b3 h1:lSOxA/PFNKwCCf0bYwOkTtvYn4Ch4QADFVJU/kuye08= +go.opentelemetry.io/collector/receiver/xreceiver v0.118.1-0.20250121185328-fbefb22cc2b3/go.mod h1:WLPXXIuodY7quBgqCz3OIsPNdBMLDej5nUIbiyyfoUc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.56.0 h1:yMkBS9yViCc7U7yeLzJPM2XizlfdVvBRSmsQDWu6qc0= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.56.0/go.mod h1:n8MR6/liuGB5EmTETUBeU5ZgqMOlqKRxUaqPQBOANZ8= +go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= +go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= +go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= +go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= +go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= +go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= +go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= +go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= +go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= +go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +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.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +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= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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-20241104194629-dd2ea8efbc28 h1:XVhgTWWV3kGQlwJHR3upFWZeTsei6Oks1apkZSeonIE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= +google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A= +google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= +google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= +google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/receiver/envoyalsreceiver/internal/als/server.go b/receiver/envoyalsreceiver/internal/als/server.go new file mode 100644 index 000000000000..7928bd6bf5c7 --- /dev/null +++ b/receiver/envoyalsreceiver/internal/als/server.go @@ -0,0 +1,89 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package als // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/envoyalsreceiver/internal/als" + +import ( + "context" + "errors" + "io" + + alsv3 "github.com/envoyproxy/go-control-plane/envoy/service/accesslog/v3" + "go.opentelemetry.io/collector/consumer" + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/plog" + "go.opentelemetry.io/collector/receiver/receiverhelper" +) + +const ( + apiVersionAttr = "api_version" + apiVersionVal = "v3" + logTypeAttr = "log_type" + httpTypeVal = "http" + tcpTypeVal = "tcp" +) + +type Server struct { + nextConsumer consumer.Logs + obsrep *receiverhelper.ObsReport +} + +func New(nextConsumer consumer.Logs, obsrep *receiverhelper.ObsReport) *Server { + return &Server{ + nextConsumer: nextConsumer, + obsrep: obsrep, + } +} + +func (s *Server) StreamAccessLogs(logStream alsv3.AccessLogService_StreamAccessLogsServer) error { + for { + data, err := logStream.Recv() + if errors.Is(err, io.EOF) { + break + } + if err != nil { + return err + } + + ctx := s.obsrep.StartLogsOp(context.Background()) + logs := toLogs(data) + logRecordCount := logs.LogRecordCount() + err = s.nextConsumer.ConsumeLogs(ctx, logs) + s.obsrep.EndLogsOp(ctx, "protobuf", logRecordCount, err) + if err != nil { + return err + } + } + + return nil +} + +func toLogs(data *alsv3.StreamAccessLogsMessage) plog.Logs { + logs := plog.NewLogs() + + rls := logs.ResourceLogs().AppendEmpty() + logSlice := rls.ScopeLogs().AppendEmpty().LogRecords() + + httpLogs := data.GetHttpLogs() + if httpLogs != nil { + for _, httpLog := range httpLogs.LogEntry { + lr := logSlice.AppendEmpty() + lr.SetTimestamp(pcommon.NewTimestampFromTime(httpLog.CommonProperties.StartTime.AsTime())) + lr.Attributes().PutStr(apiVersionAttr, apiVersionVal) + lr.Attributes().PutStr(logTypeAttr, httpTypeVal) + lr.Body().SetStr(httpLog.String()) + } + } + + tcpLogs := data.GetTcpLogs() + if tcpLogs != nil { + for _, tcpLog := range tcpLogs.LogEntry { + lr := logSlice.AppendEmpty() + lr.SetTimestamp(pcommon.NewTimestampFromTime(tcpLog.CommonProperties.StartTime.AsTime())) + lr.Attributes().PutStr(apiVersionAttr, apiVersionVal) + lr.Attributes().PutStr(logTypeAttr, tcpTypeVal) + lr.Body().SetStr(tcpLog.String()) + } + } + return logs +} diff --git a/receiver/envoyalsreceiver/internal/metadata/generated_status.go b/receiver/envoyalsreceiver/internal/metadata/generated_status.go new file mode 100644 index 000000000000..68a29876bc76 --- /dev/null +++ b/receiver/envoyalsreceiver/internal/metadata/generated_status.go @@ -0,0 +1,16 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package metadata + +import ( + "go.opentelemetry.io/collector/component" +) + +var ( + Type = component.MustNewType("envoyals") + ScopeName = "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/envoyalsreceiver" +) + +const ( + LogsStability = component.StabilityLevelDevelopment +) diff --git a/receiver/envoyalsreceiver/metadata.yaml b/receiver/envoyalsreceiver/metadata.yaml new file mode 100644 index 000000000000..cb9d5cc1a140 --- /dev/null +++ b/receiver/envoyalsreceiver/metadata.yaml @@ -0,0 +1,9 @@ +type: envoyals + +status: + class: receiver + stability: + development: [logs] + distributions: [] + codeowners: + active: [evan-bradley] diff --git a/receiver/envoyalsreceiver/testdata/config.yaml b/receiver/envoyalsreceiver/testdata/config.yaml new file mode 100644 index 000000000000..4883c58986ae --- /dev/null +++ b/receiver/envoyalsreceiver/testdata/config.yaml @@ -0,0 +1,5 @@ +# The following demonstrates how to enable protocols with defaults. +envoyals/defaults: + +envoyals/custom: + endpoint: localhost:4600 diff --git a/versions.yaml b/versions.yaml index 5f1dc302091d..2f15b1d7eb99 100644 --- a/versions.yaml +++ b/versions.yaml @@ -70,6 +70,7 @@ module-sets: - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/sentryexporter - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/signalfxexporter - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/splunkhecexporter + - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/stefexporter - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/sumologicexporter - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/syslogexporter - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/tencentcloudlogserviceexporter @@ -216,6 +217,7 @@ module-sets: - github.com/open-telemetry/opentelemetry-collector-contrib/receiver/datadogreceiver - github.com/open-telemetry/opentelemetry-collector-contrib/receiver/dockerstatsreceiver - github.com/open-telemetry/opentelemetry-collector-contrib/receiver/elasticsearchreceiver + - github.com/open-telemetry/opentelemetry-collector-contrib/receiver/envoyalsreceiver - github.com/open-telemetry/opentelemetry-collector-contrib/receiver/expvarreceiver - github.com/open-telemetry/opentelemetry-collector-contrib/receiver/filelogreceiver - github.com/open-telemetry/opentelemetry-collector-contrib/receiver/filestatsreceiver