diff --git a/.chloggen/feat_marker-exporter.yaml b/.chloggen/feat_marker-exporter.yaml new file mode 100755 index 0000000000000..3c0f0bcd3f85a --- /dev/null +++ b/.chloggen/feat_marker-exporter.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: 'honeycombmarkerexporter' + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: "This component will export markers to be consumed by the Honeycomb Markers API to highlight user events" + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [26653] + +# (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/ingestionretry.yaml b/.chloggen/ingestionretry.yaml new file mode 100644 index 0000000000000..499fdef2209fd --- /dev/null +++ b/.chloggen/ingestionretry.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: azuredataexplorerexporter + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Added exporter helper config support for Azure Data Explorer exporter + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [24329] + +# (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/k8sclusterreceiver-qos-class.yaml b/.chloggen/k8sclusterreceiver-qos-class.yaml new file mode 100755 index 0000000000000..a04469c916f8b --- /dev/null +++ b/.chloggen/k8sclusterreceiver-qos-class.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: k8sclusterreceiver + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: "add optional k8s.pod.qos_class resource attribute" + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [27483] + +# (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/.github/CODEOWNERS b/.github/CODEOWNERS index 25d6af3c4d567..8b858059e85cf 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -61,6 +61,7 @@ exporter/fileexporter/ @open-te exporter/googlecloudexporter/ @open-telemetry/collector-contrib-approvers @aabmass @dashpole @jsuereth @punya @damemi @psx95 exporter/googlecloudpubsubexporter/ @open-telemetry/collector-contrib-approvers @alexvanboxel exporter/googlemanagedprometheusexporter/ @open-telemetry/collector-contrib-approvers @aabmass @dashpole @jsuereth @punya @damemi @psx95 +exporter/honeycombmarkerexporter/ @open-telemetry/collector-contrib-approvers @fchikwekwe @TylerHelmuth exporter/influxdbexporter/ @open-telemetry/collector-contrib-approvers @jacobmarble exporter/instanaexporter/ @open-telemetry/collector-contrib-approvers @jpkrohling @hickeyma exporter/kafkaexporter/ @open-telemetry/collector-contrib-approvers @pavolloffay @MovieStoreGuy diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index b16a01b48e72c..6eaafc61824c1 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -54,6 +54,7 @@ body: - exporter/googlecloud - exporter/googlecloudpubsub - exporter/googlemanagedprometheus + - exporter/honeycombmarker - exporter/influxdb - exporter/instana - exporter/kafka diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml index 18b95999e5b60..814303a8cb55b 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yaml +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -48,6 +48,7 @@ body: - exporter/googlecloud - exporter/googlecloudpubsub - exporter/googlemanagedprometheus + - exporter/honeycombmarker - exporter/influxdb - exporter/instana - exporter/kafka diff --git a/.github/ISSUE_TEMPLATE/other.yaml b/.github/ISSUE_TEMPLATE/other.yaml index 87369f9738f29..f9d2390eb1c9f 100644 --- a/.github/ISSUE_TEMPLATE/other.yaml +++ b/.github/ISSUE_TEMPLATE/other.yaml @@ -48,6 +48,7 @@ body: - exporter/googlecloud - exporter/googlecloudpubsub - exporter/googlemanagedprometheus + - exporter/honeycombmarker - exporter/influxdb - exporter/instana - exporter/kafka diff --git a/.github/dependabot.yml b/.github/dependabot.yml index f22ae93678be7..615cb65c803b6 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -7,16 +7,6 @@ updates: schedule: interval: "weekly" day: "wednesday" - - package-ecosystem: "gomod" - directory: "/cmd/mdatagen" - schedule: - interval: "weekly" - day: "wednesday" - - package-ecosystem: "gomod" - directory: "/cmd/opampsupervisor" - schedule: - interval: "weekly" - day: "wednesday" - package-ecosystem: "gomod" directory: "/cmd/otelcontribcol" schedule: @@ -172,6 +162,11 @@ updates: schedule: interval: "weekly" day: "wednesday" + - package-ecosystem: "gomod" + directory: "/exporter/honeycombmarkerexporter" + schedule: + interval: "weekly" + day: "wednesday" - package-ecosystem: "gomod" directory: "/exporter/influxdbexporter" schedule: @@ -272,6 +267,11 @@ updates: schedule: interval: "weekly" day: "wednesday" + - package-ecosystem: "gomod" + directory: "/exporter/syslogexporter" + schedule: + interval: "weekly" + day: "wednesday" - package-ecosystem: "gomod" directory: "/exporter/tanzuobservabilityexporter" schedule: diff --git a/exporter/azuredataexplorerexporter/README.md b/exporter/azuredataexplorerexporter/README.md index 6831e803a85d4..b0024e90d34ae 100644 --- a/exporter/azuredataexplorerexporter/README.md +++ b/exporter/azuredataexplorerexporter/README.md @@ -16,6 +16,7 @@ This exporter sends metrics, logs and trace data to [Azure Data Explorer](https://docs.microsoft.com/en-us/azure/data-explorer), [Azure Synapse Data Explorer](https://docs.microsoft.com/en-us/azure/synapse-analytics/data-explorer/data-explorer-overview) and [Real time analytics in Fabric](https://learn.microsoft.com/en-us/fabric/real-time-analytics/overview) + ## Configuration The following settings are required: @@ -78,6 +79,17 @@ exporters: traces_table_json_mapping: "oteltraces_mapping" # Type of ingestion managed or queued ingestion_type : "managed" + #other available exporter helper options, see more here: https://github.com/open-telemetry/opentelemetry-collector/blob/main/exporter/exporterhelper/README.md + # timeout: 10s + # sending_queue: + # enabled: true + # num_consumers: 2 + # queue_size: 10 + # retry_on_failure: + # enabled: true + # initial_interval: 10s + # max_interval: 60s + # max_elapsed_time: 10m ``` ## Attribute mapping @@ -193,3 +205,24 @@ with ( docstring = "Histo sum count processing function", folder = "UpdatePolicy .alter table HistoData policy update @'[{ "IsEnabled": true, "Source": "RawMetricsData","Query": "ExtractHistoCountColumns()", "IsTransactional": false, "PropagateIngestionProperties": false}]' ``` + +### Opentelemetry Exporter Helper Configurations + +The ADX exporter now includes support for Opentelemetry exporter helper configurations. This feature allows you to leverage the exporter helper capabilities(retries, timeout etc.) provided natively by Otel. Read more [here](https://github.com/open-telemetry/opentelemetry-collector/blob/main/exporter/exporterhelper/README.md). + +Please note that this configuration is not enabled by default. To utilize the Opentelemetry exporter helper, you will need to add it manually to the configuration. + +#### Example Configuration + +```yaml +# Example Opentelemetry Exporter Configuration + timeout: 10s + sending_queue: + enabled: true + num_consumers: 2 + queue_size: 10 + retry_on_failure: + enabled: true + initial_interval: 10s + max_interval: 60s + max_elapsed_time: 10m diff --git a/exporter/azuredataexplorerexporter/adx_exporter_test.go b/exporter/azuredataexplorerexporter/adx_exporter_test.go index 06905aaf6c273..653c3626a8f85 100644 --- a/exporter/azuredataexplorerexporter/adx_exporter_test.go +++ b/exporter/azuredataexplorerexporter/adx_exporter_test.go @@ -207,7 +207,8 @@ func TestCreateKcsb(t *testing.T) { applicationID: "", }, } - for _, tt := range tests { + for i := range tests { + tt := tests[i] t.Run(tt.name, func(t *testing.T) { wantAppID := tt.applicationID gotKcsb := createKcsb(&tt.config, "1.0.0") diff --git a/exporter/azuredataexplorerexporter/config.go b/exporter/azuredataexplorerexporter/config.go index 4ffea154b4535..084566b8c76e6 100644 --- a/exporter/azuredataexplorerexporter/config.go +++ b/exporter/azuredataexplorerexporter/config.go @@ -10,23 +10,27 @@ import ( "github.com/google/uuid" "go.opentelemetry.io/collector/config/configopaque" + "go.opentelemetry.io/collector/exporter/exporterhelper" ) // Config defines configuration for Azure Data Explorer Exporter type Config struct { - ClusterURI string `mapstructure:"cluster_uri"` - ApplicationID string `mapstructure:"application_id"` - ApplicationKey configopaque.String `mapstructure:"application_key"` - TenantID string `mapstructure:"tenant_id"` - ManagedIdentityID string `mapstructure:"managed_identity_id"` - Database string `mapstructure:"db_name"` - MetricTable string `mapstructure:"metrics_table_name"` - LogTable string `mapstructure:"logs_table_name"` - TraceTable string `mapstructure:"traces_table_name"` - MetricTableMapping string `mapstructure:"metrics_table_json_mapping"` - LogTableMapping string `mapstructure:"logs_table_json_mapping"` - TraceTableMapping string `mapstructure:"traces_table_json_mapping"` - IngestionType string `mapstructure:"ingestion_type"` + exporterhelper.TimeoutSettings `mapstructure:",squash"` // squash ensures fields are correctly decoded in embedded struct. + exporterhelper.QueueSettings `mapstructure:"sending_queue"` + exporterhelper.RetrySettings `mapstructure:"retry_on_failure"` + ClusterURI string `mapstructure:"cluster_uri"` + ApplicationID string `mapstructure:"application_id"` + ApplicationKey configopaque.String `mapstructure:"application_key"` + TenantID string `mapstructure:"tenant_id"` + ManagedIdentityID string `mapstructure:"managed_identity_id"` + Database string `mapstructure:"db_name"` + MetricTable string `mapstructure:"metrics_table_name"` + LogTable string `mapstructure:"logs_table_name"` + TraceTable string `mapstructure:"traces_table_name"` + MetricTableMapping string `mapstructure:"metrics_table_json_mapping"` + LogTableMapping string `mapstructure:"logs_table_json_mapping"` + TraceTableMapping string `mapstructure:"traces_table_json_mapping"` + IngestionType string `mapstructure:"ingestion_type"` } // Validate checks if the exporter configuration is valid diff --git a/exporter/azuredataexplorerexporter/config_test.go b/exporter/azuredataexplorerexporter/config_test.go index 496ff9cca860e..9167568179ae0 100644 --- a/exporter/azuredataexplorerexporter/config_test.go +++ b/exporter/azuredataexplorerexporter/config_test.go @@ -6,11 +6,13 @@ package azuredataexplorerexporter // import "github.com/open-telemetry/opentelem import ( "path/filepath" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/confmap/confmaptest" + "go.opentelemetry.io/collector/exporter/exporterhelper" "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/azuredataexplorerexporter/internal/metadata" ) @@ -80,6 +82,34 @@ func TestLoadConfig(t *testing.T) { id: component.NewIDWithName(metadata.Type, "7"), errorMessage: `clusterURI config is mandatory`, }, + { + id: component.NewIDWithName(metadata.Type, "8"), + expected: &Config{ + ClusterURI: "https://CLUSTER.kusto.windows.net", + ApplicationID: "f80da32c-108c-415c-a19e-643f461a677a", + ApplicationKey: "xx-xx-xx-xx", + TenantID: "21ff9e36-fbaa-43c8-98ba-00431ea10bc3", + Database: "oteldb", + MetricTable: "OTELMetrics", + LogTable: "OTELLogs", + TraceTable: "OTELTraces", + IngestionType: managedIngestType, + TimeoutSettings: exporterhelper.TimeoutSettings{ + Timeout: 10 * time.Second, + }, + RetrySettings: exporterhelper.RetrySettings{ + Enabled: true, + InitialInterval: 10 * time.Second, + MaxInterval: 60 * time.Second, + MaxElapsedTime: 10 * time.Minute, + }, + QueueSettings: exporterhelper.QueueSettings{ + Enabled: true, + NumConsumers: 2, + QueueSize: 10, + }, + }, + }, } for _, tt := range tests { diff --git a/exporter/azuredataexplorerexporter/factory.go b/exporter/azuredataexplorerexporter/factory.go index 300ad7c06a652..ca77d82ea13e3 100644 --- a/exporter/azuredataexplorerexporter/factory.go +++ b/exporter/azuredataexplorerexporter/factory.go @@ -74,7 +74,9 @@ func createMetricsExporter( set, adxCfg, adp.metricsDataPusher, - exporterhelper.WithTimeout(exporterhelper.TimeoutSettings{Timeout: 0}), + exporterhelper.WithTimeout(adxCfg.TimeoutSettings), + exporterhelper.WithRetry(adxCfg.RetrySettings), + exporterhelper.WithQueue(adxCfg.QueueSettings), exporterhelper.WithShutdown(adp.Close)) if err != nil { @@ -104,7 +106,9 @@ func createTracesExporter( set, adxCfg, adp.tracesDataPusher, - exporterhelper.WithTimeout(exporterhelper.TimeoutSettings{Timeout: 0}), + exporterhelper.WithTimeout(adxCfg.TimeoutSettings), + exporterhelper.WithRetry(adxCfg.RetrySettings), + exporterhelper.WithQueue(adxCfg.QueueSettings), exporterhelper.WithShutdown(adp.Close)) if err != nil { @@ -134,7 +138,9 @@ func createLogsExporter( set, adxCfg, adp.logsDataPusher, - exporterhelper.WithTimeout(exporterhelper.TimeoutSettings{Timeout: 0}), + exporterhelper.WithTimeout(adxCfg.TimeoutSettings), + exporterhelper.WithRetry(adxCfg.RetrySettings), + exporterhelper.WithQueue(adxCfg.QueueSettings), exporterhelper.WithShutdown(adp.Close)) if err != nil { diff --git a/exporter/azuredataexplorerexporter/testdata/config.yaml b/exporter/azuredataexplorerexporter/testdata/config.yaml index 1acf2bb887ae9..0fdf9fbe0a138 100644 --- a/exporter/azuredataexplorerexporter/testdata/config.yaml +++ b/exporter/azuredataexplorerexporter/testdata/config.yaml @@ -115,4 +115,34 @@ azuredataexplorer/7: # raw traces table traces_table_name: "OTELTraces" # type of ingestion managed or queued - ingestion_type: "managed" \ No newline at end of file + ingestion_type: "managed" +azuredataexplorer/8: + # Kusto cluster uri + cluster_uri: "https://CLUSTER.kusto.windows.net" + # Client Id + application_id: "f80da32c-108c-415c-a19e-643f461a677a" + # The client secret for the client + application_key: "xx-xx-xx-xx" + # The tenant + tenant_id: "21ff9e36-fbaa-43c8-98ba-00431ea10bc3" + # database for the logs + db_name: "oteldb" + # raw metric table name + metrics_table_name: "OTELMetrics" + # raw log table name + logs_table_name: "OTELLogs" + # raw traces table + traces_table_name: "OTELTraces" + # type of ingestion managed or queued + ingestion_type: "managed" + #export helper options + timeout: 10s + sending_queue: + enabled: true + num_consumers: 2 + queue_size: 10 + retry_on_failure: + enabled: true + initial_interval: 10s + max_interval: 60s + max_elapsed_time: 10m \ No newline at end of file diff --git a/exporter/honeycombmarkerexporter/Makefile b/exporter/honeycombmarkerexporter/Makefile new file mode 100644 index 0000000000000..ded7a36092dc3 --- /dev/null +++ b/exporter/honeycombmarkerexporter/Makefile @@ -0,0 +1 @@ +include ../../Makefile.Common diff --git a/exporter/honeycombmarkerexporter/README.md b/exporter/honeycombmarkerexporter/README.md new file mode 100644 index 0000000000000..c118195798775 --- /dev/null +++ b/exporter/honeycombmarkerexporter/README.md @@ -0,0 +1,42 @@ +@@ -0,0 +1,18 @@ +# Honeycomb Marker Exporter + +This exporter allows creating markers, via the Honeycomb Markers API, based on the look of incoming telemetry. + +The following configuration options are supported: + +* `api_key` (Required): This is the API key (also called Write Key) for your Honeycomb account. +* `api_url` (Required): You can set the hostname to send marker data to. +* `markers` (Required): This specifies the exact configuration to create an event marker. + * `type`: Specifies the marker type. Markers with the same type will appear in the same color in Honeycomb. MarkerType or MarkerColor should be set. + * `color`: Specifies the marker color. Will only be used if MarkerType is not set. + * `messagefield`: This is the attribute that will be used as the message. If necessary the value will be converted to a string. + * `urlfield`: This is the attribute that will be used as the url. If necessary the value will be converted to a string. + * `rules`: This is a list of OTTL rules that determine when to create an event marker. + * `resourceconditions`: A list of ottlresource conditions that determine a match + * `logconditions`: A list of ottllog conditions that determine a match + Example: + +```yaml +exporters: + honeycomb: + api_key: "my-api-key" + api_url: "https://api.testhost.io" + markers: + - type: "fooType", + messagefield: "test message", + urlfield: "https://api.testhost.io", + rules: + - resourceconditions: + - IsMatch(attributes["test"], ".*") + - logconditions: + - body == "test" + - color: "green", + messagefield: "another test message", + urlfield: "https://api.testhost.io", + rules: + - resourceconditions: + - IsMatch(attributes["test"], ".*") + - logconditions: + - body == "test" +``` \ No newline at end of file diff --git a/exporter/honeycombmarkerexporter/config.go b/exporter/honeycombmarkerexporter/config.go new file mode 100644 index 0000000000000..bc9bf7d2987cf --- /dev/null +++ b/exporter/honeycombmarkerexporter/config.go @@ -0,0 +1,90 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package honeycombmarkerexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/honeycombmarkerexporter" + +import ( + "fmt" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/config/configopaque" + "go.uber.org/zap" + + "github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter/filterottl" + "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl" +) + +// Config defines configuration for the Honeycomb Marker exporter. +type Config struct { + // APIKey is the authentication token associated with the Honeycomb account. + APIKey configopaque.String `mapstructure:"api_key"` + + // API URL to use (defaults to https://api.honeycomb.io) + APIURL string `mapstructure:"api_url"` + + // Markers is the list of markers to create + Markers []Marker `mapstructure:"markers"` +} + +type Marker struct { + // Type defines the type of Marker. Markers with the same type appear in Honeycomb with the same color + Type string `mapstructure:"type"` + + // Color is the color of the Marker. Will only be used if the Type does not already exist. + Color string `mapstructure:"color"` + + // MessageField is the attribute that will be used as the message. + // If necessary the value will be converted to a string. + MessageField string `mapstructure:"message_field"` + + // URLField is the attribute that will be used as the url. + // If necessary the value will be converted to a string. + URLField string `mapstructure:"url_field"` + + // Rules are the OTTL rules that determine when a piece of telemetry should be turned into a Marker + Rules Rules `mapstructure:"rules"` +} + +type Rules struct { + // ResourceConditions is the list of ottlresource conditions that determine a match + ResourceConditions []string `mapstructure:"resource_conditions"` + + // LogConditions is the list of ottllog conditions that determine a match + LogConditions []string `mapstructure:"log_conditions"` +} + +var defaultCfg = createDefaultConfig().(*Config) + +func (cfg *Config) Validate() error { + if cfg == nil { + cfg = defaultCfg + } + + if cfg.APIKey == "" { + return fmt.Errorf("invalid API Key") + } + + if len(cfg.Markers) != 0 { + for _, m := range cfg.Markers { + if len(m.Rules.ResourceConditions) == 0 && len(m.Rules.LogConditions) == 0 { + return fmt.Errorf("no rules supplied for Marker %v", m) + } + + _, err := filterottl.NewBoolExprForResource(m.Rules.ResourceConditions, filterottl.StandardResourceFuncs(), ottl.PropagateError, component.TelemetrySettings{Logger: zap.NewNop()}) + if err != nil { + return err + } + + _, err = filterottl.NewBoolExprForLog(m.Rules.LogConditions, filterottl.StandardLogFuncs(), ottl.PropagateError, component.TelemetrySettings{Logger: zap.NewNop()}) + if err != nil { + return err + } + } + } else { + return fmt.Errorf("no markers supplied") + } + + return nil +} + +var _ component.Config = (*Config)(nil) diff --git a/exporter/honeycombmarkerexporter/config_test.go b/exporter/honeycombmarkerexporter/config_test.go new file mode 100644 index 0000000000000..9fbdc724db560 --- /dev/null +++ b/exporter/honeycombmarkerexporter/config_test.go @@ -0,0 +1,113 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package honeycombmarkerexporter + +import ( + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/confmap/confmaptest" + + "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/honeycombmarkerexporter/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("honeycomb", ""), + expected: &Config{ + APIKey: "test-apikey", + APIURL: "https://api.testhost.io", + Markers: []Marker{ + { + Type: "fooType", + MessageField: "test message", + URLField: "https://api.testhost.io", + Rules: Rules{ + ResourceConditions: []string{ + `IsMatch(attributes["test"], ".*")`, + }, + LogConditions: []string{ + `body == "test"`, + }, + }, + }, + }, + }, + }, + { + id: component.NewIDWithName("honeycomb", "color_no_type"), + expected: &Config{ + APIKey: "test-apikey", + APIURL: "https://api.testhost.io", + Markers: []Marker{ + { + Color: "green", + MessageField: "test message", + URLField: "https://api.testhost.io", + Rules: Rules{ + ResourceConditions: []string{ + `IsMatch(attributes["test"], ".*")`, + }, + LogConditions: []string{ + `body == "test"`, + }, + }, + }, + }, + }, + }, + { + id: component.NewIDWithName(metadata.Type, "bad_syntax_log"), + }, + { + id: component.NewIDWithName(metadata.Type, "no_conditions"), + }, + { + id: component.NewIDWithName(metadata.Type, "no_api_key"), + }, + { + id: component.NewIDWithName(metadata.Type, "no_markers_supplied"), + }, + } + + 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, component.UnmarshalConfig(sub, cfg)) + + if tt.expected == nil { + err = component.ValidateConfig(cfg) + assert.Error(t, err) + return + } + + assert.NoError(t, component.ValidateConfig(cfg)) + assert.Equal(t, tt.expected, cfg) + }) + } +} + +func withDefaultConfig(fns ...func(*Config)) *Config { + cfg := createDefaultConfig().(*Config) + for _, fn := range fns { + fn(cfg) + } + return cfg +} diff --git a/exporter/honeycombmarkerexporter/doc.go b/exporter/honeycombmarkerexporter/doc.go new file mode 100644 index 0000000000000..e01e77000d7f6 --- /dev/null +++ b/exporter/honeycombmarkerexporter/doc.go @@ -0,0 +1,7 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +//go:generate mdatagen metadata.yaml + +// Package honeycombmarkerexporter exports Marker data to Honeycomb. +package honeycombmarkerexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/honeycombmarkerexporter" diff --git a/exporter/honeycombmarkerexporter/factory.go b/exporter/honeycombmarkerexporter/factory.go new file mode 100644 index 0000000000000..36e26f4d7e7f6 --- /dev/null +++ b/exporter/honeycombmarkerexporter/factory.go @@ -0,0 +1,47 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package honeycombmarkerexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/honeycombmarkerexporter" + +import ( + "context" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/exporter" + "go.opentelemetry.io/collector/exporter/exporterhelper" + + "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/honeycombmarkerexporter/internal/metadata" +) + +func NewFactory() exporter.Factory { + return exporter.NewFactory( + metadata.Type, + createDefaultConfig, + exporter.WithLogs(createLogsExporter, metadata.LogsStability), + ) +} + +func createDefaultConfig() component.Config { + return &Config{ + APIKey: "", + APIURL: "api.honeycomb.io:443", + Markers: []Marker{}, + } +} + +func createLogsExporter( + ctx context.Context, + set exporter.CreateSettings, + cfg component.Config, +) (exporter.Logs, error) { + cf := cfg.(*Config) + + exporter := newLogsExporter(set.Logger, cf) + + return exporterhelper.NewLogsExporter( + ctx, + set, + cfg, + exporter.exportLogs, + ) +} diff --git a/exporter/honeycombmarkerexporter/factory_test.go b/exporter/honeycombmarkerexporter/factory_test.go new file mode 100644 index 0000000000000..8b3fce63d577b --- /dev/null +++ b/exporter/honeycombmarkerexporter/factory_test.go @@ -0,0 +1,36 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package honeycombmarkerexporter + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/exporter/exportertest" +) + +const defaultURL = `https://api.example.com/v1` + +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 TestFactory_CreateLogsExporter(t *testing.T) { + factory := NewFactory() + cfg := withDefaultConfig(func(cfg *Config) { + cfg.APIURL = defaultURL + }) + params := exportertest.NewNopCreateSettings() + exporter, err := factory.CreateLogsExporter(context.Background(), params, cfg) + require.NoError(t, err) + require.NotNil(t, exporter) + + require.NoError(t, exporter.Shutdown(context.TODO())) +} diff --git a/exporter/honeycombmarkerexporter/go.mod b/exporter/honeycombmarkerexporter/go.mod new file mode 100644 index 0000000000000..c55af3226bede --- /dev/null +++ b/exporter/honeycombmarkerexporter/go.mod @@ -0,0 +1,66 @@ +module github.com/open-telemetry/opentelemetry-collector-contrib/exporter/honeycombmarkerexporter + +go 1.20 + +require ( + github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter v0.86.0 + github.com/open-telemetry/opentelemetry-collector-contrib/pkg/ottl v0.87.0 + github.com/stretchr/testify v1.8.4 + go.opentelemetry.io/collector/component v0.87.0 + go.opentelemetry.io/collector/config/configopaque v0.87.0 + go.opentelemetry.io/collector/confmap v0.87.0 + go.opentelemetry.io/collector/exporter v0.87.0 + go.opentelemetry.io/collector/pdata v1.0.0-rcv0016 + go.uber.org/zap v1.26.0 +) + +require ( + github.com/alecthomas/participle/v2 v2.1.0 // indirect + github.com/cenkalti/backoff/v4 v4.2.1 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/gobwas/glob v0.2.3 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/uuid v1.3.1 // indirect + github.com/iancoleman/strcase v0.3.0 // indirect + github.com/json-iterator/go v1.1.12 // 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.0.1 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 // 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/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal v0.87.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/collector v0.87.0 // indirect + go.opentelemetry.io/collector/config/configtelemetry v0.87.0 // indirect + go.opentelemetry.io/collector/consumer v0.87.0 // indirect + go.opentelemetry.io/collector/extension v0.87.0 // indirect + go.opentelemetry.io/collector/featuregate v1.0.0-rcv0016 // indirect + go.opentelemetry.io/otel v1.19.0 // indirect + go.opentelemetry.io/otel/metric v1.19.0 // indirect + go.opentelemetry.io/otel/trace v1.19.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + golang.org/x/exp v0.0.0-20230711023510-fffb14384f22 // indirect + golang.org/x/net v0.17.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect + google.golang.org/grpc v1.58.2 // indirect + google.golang.org/protobuf v1.31.0 // 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/ottl => ../../pkg/ottl + +replace github.com/open-telemetry/opentelemetry-collector-contrib/internal/filter => ../../internal/filter + +replace github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal => ../../internal/coreinternal + +replace github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil => ../../pkg/pdatautil diff --git a/exporter/honeycombmarkerexporter/go.sum b/exporter/honeycombmarkerexporter/go.sum new file mode 100644 index 0000000000000..949175148023a --- /dev/null +++ b/exporter/honeycombmarkerexporter/go.sum @@ -0,0 +1,226 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +contrib.go.opencensus.io/exporter/prometheus v0.4.2 h1:sqfsYl5GIY/L570iT+l93ehxaWJs2/OwXtiWwew3oAg= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/alecthomas/assert/v2 v2.3.0 h1:mAsH2wmvjsuvyBvAmCtm7zFsBlb8mIHx5ySLVdDZXL0= +github.com/alecthomas/participle/v2 v2.1.0 h1:z7dElHRrOEEq45F2TG5cbQihMtNTv8vwldytDj7Wrz4= +github.com/alecthomas/participle/v2 v2.1.0/go.mod h1:Y1+hAs8DHPmc3YUFzqllV+eSQ9ljPTk0ZkPMtEdAx2c= +github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +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.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= +github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= +github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +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/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.0.1 h1:1dYGITt1I23x8cfx8ZnldtezdyaZtfAuRtIFOiRzK7g= +github.com/knadh/koanf/v2 v2.0.1/go.mod h1:ZeiIlIDXTE7w1lMT6UVcNiRAS2/rCeLn/GdLNvY1Dus= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +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/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 h1:BpfhmLKZf+SjVanKKhCgf3bg+511DmU9eDQTen7LLbY= +github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= +github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= +github.com/prometheus/statsd_exporter v0.22.7 h1:7Pji/i2GuhK6Lu7DHrtTkFmNBCudCPT1pX2CziuyQR0= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/collector v0.87.0 h1:160HewHp+/wzr62BzWjQgIvdTtzpaYTlCnGVb8DYnM0= +go.opentelemetry.io/collector v0.87.0/go.mod h1:VsAXXIK0D1na+Ysoy1/GIx0GgkH8vQqA6zwosddFz7A= +go.opentelemetry.io/collector/component v0.87.0 h1:Q+lwM5WAa2x4a5lgyaF6SjFBpIij5gyjsoiv9KFG36A= +go.opentelemetry.io/collector/component v0.87.0/go.mod h1:LsfDQRkwJRHOSHNnM1/pdi/6EQNj41WpIxpZRqSdI0E= +go.opentelemetry.io/collector/config/configopaque v0.87.0 h1:+qqJG1oEzX4+/YNbgeaXW9YM0BPWSj5XCi5y2zZLhDY= +go.opentelemetry.io/collector/config/configopaque v0.87.0/go.mod h1:TPCHaU+QXiEV+JXbgyr6mSErTI9chwQyasDVMdJr3eY= +go.opentelemetry.io/collector/config/configtelemetry v0.87.0 h1:xUqayM9b41OvXkjU3p8RkUr8hUrCjfDUmO+oKhRNSwc= +go.opentelemetry.io/collector/config/configtelemetry v0.87.0/go.mod h1:+LAXM5WFMW/UbTlAuSs6L/W72WC+q8TBJt/6z39FPOU= +go.opentelemetry.io/collector/confmap v0.87.0 h1:LFnyDKIOMtlJm5EsdcFN2t0rcU/QLbS9QEs/awM2HOA= +go.opentelemetry.io/collector/confmap v0.87.0/go.mod h1:inqYRP70+bMrUwGGnuhcWyyufxyU3VQT6rl3/EX0f+g= +go.opentelemetry.io/collector/consumer v0.87.0 h1:oR5XKZoVF/hwz0FnrYPaHcbbQazHifMsxpENMR7ivvo= +go.opentelemetry.io/collector/consumer v0.87.0/go.mod h1:lui5rg1byAT7QPbCY733StCDc/TPxS3hVNXKoVQ3LsI= +go.opentelemetry.io/collector/exporter v0.87.0 h1:DZ0QT2yp1qACmHMxs6W2ho5RPqdevCx9R/LFCxnxi9w= +go.opentelemetry.io/collector/exporter v0.87.0/go.mod h1:SGobdCR0xwQElJT2Sbofo7BprMlV8XeXdsNP9fsNaKY= +go.opentelemetry.io/collector/extension v0.87.0 h1:EMIaEequ5rjWzoid6vNImjQGVMfzbME+8JSa5XACYKs= +go.opentelemetry.io/collector/extension v0.87.0/go.mod h1:D3srNZC99QVTAdLNUVuqfmmgJge4sQHDrnt5XWscvxI= +go.opentelemetry.io/collector/featuregate v1.0.0-rcv0016 h1:/6N9990tbjotvXgrXpV5AbaFiyxTdFEXDypGBHVDSQM= +go.opentelemetry.io/collector/featuregate v1.0.0-rcv0016/go.mod h1:fLmJMf1AoHttkF8p5oJAc4o5ZpHu8yO5XYJ7gbLCLzo= +go.opentelemetry.io/collector/pdata v1.0.0-rcv0016 h1:qCPXSQCoD3qeWFb1RuIks8fw9Atxpk78bmtVdi15KhE= +go.opentelemetry.io/collector/pdata v1.0.0-rcv0016/go.mod h1:OdN0alYOlYhHXu6BDlGehrZWgtBuiDsz/rlNeJeXiNg= +go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= +go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= +go.opentelemetry.io/otel/exporters/prometheus v0.42.0 h1:jwV9iQdvp38fxXi8ZC+lNpxjK16MRcZlpDYvbuO1FiA= +go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= +go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= +go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= +go.opentelemetry.io/otel/sdk/metric v1.19.0 h1:EJoTO5qysMsYCa+w4UghwFV/ptQgqSL/8Ni+hx+8i1k= +go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= +go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +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.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +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/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20230711023510-fffb14384f22 h1:FqrVOBQxQ8r/UwwXibI0KMolVhvFiGobSfdE33deHJM= +golang.org/x/exp v0.0.0-20230711023510-fffb14384f22/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +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-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +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.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +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-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +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.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +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.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +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/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I= +google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +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/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/exporter/honeycombmarkerexporter/internal/metadata/generated_status.go b/exporter/honeycombmarkerexporter/internal/metadata/generated_status.go new file mode 100644 index 0000000000000..e475b1c0f3b6a --- /dev/null +++ b/exporter/honeycombmarkerexporter/internal/metadata/generated_status.go @@ -0,0 +1,12 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package metadata + +import ( + "go.opentelemetry.io/collector/component" +) + +const ( + Type = "honeycombmarker" + LogsStability = component.StabilityLevelDevelopment +) diff --git a/exporter/honeycombmarkerexporter/logs_exporter.go b/exporter/honeycombmarkerexporter/logs_exporter.go new file mode 100644 index 0000000000000..3dfe36d5d9bc3 --- /dev/null +++ b/exporter/honeycombmarkerexporter/logs_exporter.go @@ -0,0 +1,28 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package honeycombmarkerexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/honeycombmarkerexporter" + +import ( + "context" + + "go.opentelemetry.io/collector/pdata/plog" + "go.uber.org/zap" +) + +type honeycombLogsExporter struct { + logger *zap.Logger + markers []Marker +} + +func newLogsExporter(logger *zap.Logger, config *Config) *honeycombLogsExporter { + logsExp := &honeycombLogsExporter{ + logger: logger, + markers: config.Markers, + } + return logsExp +} + +func (e *honeycombLogsExporter) exportLogs(_ context.Context, _ plog.Logs) error { + return nil +} diff --git a/exporter/honeycombmarkerexporter/metadata.yaml b/exporter/honeycombmarkerexporter/metadata.yaml new file mode 100644 index 0000000000000..51361e199f72a --- /dev/null +++ b/exporter/honeycombmarkerexporter/metadata.yaml @@ -0,0 +1,9 @@ +type: honeycombmarker + +status: + class: exporter + stability: + development: [logs] + distributions: [] + codeowners: + active: [TylerHelmuth, fchikwekwe] diff --git a/exporter/honeycombmarkerexporter/testdata/config.yaml b/exporter/honeycombmarkerexporter/testdata/config.yaml new file mode 100644 index 0000000000000..3ca6508c9ffb2 --- /dev/null +++ b/exporter/honeycombmarkerexporter/testdata/config.yaml @@ -0,0 +1,78 @@ +honeycomb: + api_key: "test-apikey" + api_url: "https://api.testhost.io" + markers: + - type: "fooType" + message_field: "test message" + url_field: "https://api.testhost.io" + rules: + resource_conditions: + - IsMatch(attributes["test"], ".*") + log_conditions: + - body == "test" + +honeycomb/color_no_type: + api_key: "test-apikey" + api_url: "https://api.testhost.io" + markers: + - color: "green" + message_field: "test message" + url_field: "https://api.testhost.io" + rules: + resource_conditions: + - IsMatch(attributes["test"], ".*") + log_conditions: + - body == "test" + +honeycomb/bad_syntax_log: + api_key: "test-apikey" + api_url: "https://api.testhost.io" + markers: + - type: "fooType" + message_field: "test message" + url_field: "https://api.testhost.io" + rules: + log_conditions: + - body == "test" + - set(attributes["body"], body) + +honeycomb/no_conditions: + api_key: "test-apikey" + api_url: "https://api.testhost.io" + markers: + - color: "green" + message_field: "test message" + url_field: "https://api.testhost.io" + rules: + +honeycomb/no_api_key: + api_key: "" + api_url: "https://api.testhost.io" + markers: + - type: "fooType" + message_field: "test message" + url_field: "https://api.testhost.io" + rules: + resource_conditions: + - IsMatch(attributes["test"], ".*") + log_conditions: + - body == "test" + +honeycomb/no_api_url: + api_key: "test-apikey" + api_url: "" + markers: + - type: "fooType" + message_field: "test message" + url_field: "https://api.testhost.io" + rules: + resource_conditions: + - IsMatch(attributes["test"], ".*") + log_conditions: + - body == "test" + +honeycomb/no_markers_supplied: + api_key: "test-apikey" + api_url: "https://api.testhost.io" + markers: + diff --git a/processor/transformprocessor/README.md b/processor/transformprocessor/README.md index b8973698f3693..624541a35b201 100644 --- a/processor/transformprocessor/README.md +++ b/processor/transformprocessor/README.md @@ -356,7 +356,7 @@ transform: - set(attributes["body"], body) ``` -### Comnbine two attributes +### Combine two attributes Set attribute `test` to the value of attributes `"foo"` and `"bar"` combined. ```yaml transform: diff --git a/receiver/k8sclusterreceiver/documentation.md b/receiver/k8sclusterreceiver/documentation.md index 15acf9331c1fa..326521bf889c3 100644 --- a/receiver/k8sclusterreceiver/documentation.md +++ b/receiver/k8sclusterreceiver/documentation.md @@ -429,6 +429,7 @@ Current status reason of the pod (1 - Evicted, 2 - NodeAffinity, 3 - NodeLost, 4 | k8s.node.name | The k8s node name. | Any Str | true | | k8s.node.uid | The k8s node uid. | Any Str | true | | k8s.pod.name | The k8s pod name. | Any Str | true | +| k8s.pod.qos_class | The k8s pod qos class name. One of Guaranteed, Burstable, BestEffort. | Any Str | false | | k8s.pod.uid | The k8s pod uid. | Any Str | true | | k8s.replicaset.name | The k8s replicaset name | Any Str | true | | k8s.replicaset.uid | The k8s replicaset uid | Any Str | true | diff --git a/receiver/k8sclusterreceiver/internal/metadata/generated_config.go b/receiver/k8sclusterreceiver/internal/metadata/generated_config.go index 91adaecbfd678..784d34de376b5 100644 --- a/receiver/k8sclusterreceiver/internal/metadata/generated_config.go +++ b/receiver/k8sclusterreceiver/internal/metadata/generated_config.go @@ -246,6 +246,7 @@ type ResourceAttributesConfig struct { K8sNodeName ResourceAttributeConfig `mapstructure:"k8s.node.name"` K8sNodeUID ResourceAttributeConfig `mapstructure:"k8s.node.uid"` K8sPodName ResourceAttributeConfig `mapstructure:"k8s.pod.name"` + K8sPodQosClass ResourceAttributeConfig `mapstructure:"k8s.pod.qos_class"` K8sPodUID ResourceAttributeConfig `mapstructure:"k8s.pod.uid"` K8sReplicasetName ResourceAttributeConfig `mapstructure:"k8s.replicaset.name"` K8sReplicasetUID ResourceAttributeConfig `mapstructure:"k8s.replicaset.uid"` @@ -324,6 +325,9 @@ func DefaultResourceAttributesConfig() ResourceAttributesConfig { K8sPodName: ResourceAttributeConfig{ Enabled: true, }, + K8sPodQosClass: ResourceAttributeConfig{ + Enabled: false, + }, K8sPodUID: ResourceAttributeConfig{ Enabled: true, }, diff --git a/receiver/k8sclusterreceiver/internal/metadata/generated_config_test.go b/receiver/k8sclusterreceiver/internal/metadata/generated_config_test.go index 82e839640f5fd..1bccc30933afa 100644 --- a/receiver/k8sclusterreceiver/internal/metadata/generated_config_test.go +++ b/receiver/k8sclusterreceiver/internal/metadata/generated_config_test.go @@ -92,6 +92,7 @@ func TestMetricsBuilderConfig(t *testing.T) { K8sNodeName: ResourceAttributeConfig{Enabled: true}, K8sNodeUID: ResourceAttributeConfig{Enabled: true}, K8sPodName: ResourceAttributeConfig{Enabled: true}, + K8sPodQosClass: ResourceAttributeConfig{Enabled: true}, K8sPodUID: ResourceAttributeConfig{Enabled: true}, K8sReplicasetName: ResourceAttributeConfig{Enabled: true}, K8sReplicasetUID: ResourceAttributeConfig{Enabled: true}, @@ -176,6 +177,7 @@ func TestMetricsBuilderConfig(t *testing.T) { K8sNodeName: ResourceAttributeConfig{Enabled: false}, K8sNodeUID: ResourceAttributeConfig{Enabled: false}, K8sPodName: ResourceAttributeConfig{Enabled: false}, + K8sPodQosClass: ResourceAttributeConfig{Enabled: false}, K8sPodUID: ResourceAttributeConfig{Enabled: false}, K8sReplicasetName: ResourceAttributeConfig{Enabled: false}, K8sReplicasetUID: ResourceAttributeConfig{Enabled: false}, @@ -244,6 +246,7 @@ func TestResourceAttributesConfig(t *testing.T) { K8sNodeName: ResourceAttributeConfig{Enabled: true}, K8sNodeUID: ResourceAttributeConfig{Enabled: true}, K8sPodName: ResourceAttributeConfig{Enabled: true}, + K8sPodQosClass: ResourceAttributeConfig{Enabled: true}, K8sPodUID: ResourceAttributeConfig{Enabled: true}, K8sReplicasetName: ResourceAttributeConfig{Enabled: true}, K8sReplicasetUID: ResourceAttributeConfig{Enabled: true}, @@ -281,6 +284,7 @@ func TestResourceAttributesConfig(t *testing.T) { K8sNodeName: ResourceAttributeConfig{Enabled: false}, K8sNodeUID: ResourceAttributeConfig{Enabled: false}, K8sPodName: ResourceAttributeConfig{Enabled: false}, + K8sPodQosClass: ResourceAttributeConfig{Enabled: false}, K8sPodUID: ResourceAttributeConfig{Enabled: false}, K8sReplicasetName: ResourceAttributeConfig{Enabled: false}, K8sReplicasetUID: ResourceAttributeConfig{Enabled: false}, diff --git a/receiver/k8sclusterreceiver/internal/metadata/generated_metrics_test.go b/receiver/k8sclusterreceiver/internal/metadata/generated_metrics_test.go index 2afd291beaa78..4df3641aa383c 100644 --- a/receiver/k8sclusterreceiver/internal/metadata/generated_metrics_test.go +++ b/receiver/k8sclusterreceiver/internal/metadata/generated_metrics_test.go @@ -248,6 +248,7 @@ func TestMetricsBuilder(t *testing.T) { rb.SetK8sNodeName("k8s.node.name-val") rb.SetK8sNodeUID("k8s.node.uid-val") rb.SetK8sPodName("k8s.pod.name-val") + rb.SetK8sPodQosClass("k8s.pod.qos_class-val") rb.SetK8sPodUID("k8s.pod.uid-val") rb.SetK8sReplicasetName("k8s.replicaset.name-val") rb.SetK8sReplicasetUID("k8s.replicaset.uid-val") diff --git a/receiver/k8sclusterreceiver/internal/metadata/generated_resource.go b/receiver/k8sclusterreceiver/internal/metadata/generated_resource.go index 59b13e98c30c6..ff2df65ff6e4b 100644 --- a/receiver/k8sclusterreceiver/internal/metadata/generated_resource.go +++ b/receiver/k8sclusterreceiver/internal/metadata/generated_resource.go @@ -168,6 +168,13 @@ func (rb *ResourceBuilder) SetK8sPodName(val string) { } } +// SetK8sPodQosClass sets provided value as "k8s.pod.qos_class" attribute. +func (rb *ResourceBuilder) SetK8sPodQosClass(val string) { + if rb.config.K8sPodQosClass.Enabled { + rb.res.Attributes().PutStr("k8s.pod.qos_class", val) + } +} + // SetK8sPodUID sets provided value as "k8s.pod.uid" attribute. func (rb *ResourceBuilder) SetK8sPodUID(val string) { if rb.config.K8sPodUID.Enabled { diff --git a/receiver/k8sclusterreceiver/internal/metadata/generated_resource_test.go b/receiver/k8sclusterreceiver/internal/metadata/generated_resource_test.go index a26162228b518..5eb06be190481 100644 --- a/receiver/k8sclusterreceiver/internal/metadata/generated_resource_test.go +++ b/receiver/k8sclusterreceiver/internal/metadata/generated_resource_test.go @@ -34,6 +34,7 @@ func TestResourceBuilder(t *testing.T) { rb.SetK8sNodeName("k8s.node.name-val") rb.SetK8sNodeUID("k8s.node.uid-val") rb.SetK8sPodName("k8s.pod.name-val") + rb.SetK8sPodQosClass("k8s.pod.qos_class-val") rb.SetK8sPodUID("k8s.pod.uid-val") rb.SetK8sReplicasetName("k8s.replicaset.name-val") rb.SetK8sReplicasetUID("k8s.replicaset.uid-val") @@ -53,7 +54,7 @@ func TestResourceBuilder(t *testing.T) { case "default": assert.Equal(t, 30, res.Attributes().Len()) case "all_set": - assert.Equal(t, 32, res.Attributes().Len()) + assert.Equal(t, 33, res.Attributes().Len()) case "none_set": assert.Equal(t, 0, res.Attributes().Len()) return @@ -166,6 +167,11 @@ func TestResourceBuilder(t *testing.T) { if ok { assert.EqualValues(t, "k8s.pod.name-val", val.Str()) } + val, ok = res.Attributes().Get("k8s.pod.qos_class") + assert.Equal(t, test == "all_set", ok) + if ok { + assert.EqualValues(t, "k8s.pod.qos_class-val", val.Str()) + } val, ok = res.Attributes().Get("k8s.pod.uid") assert.True(t, ok) if ok { diff --git a/receiver/k8sclusterreceiver/internal/metadata/testdata/config.yaml b/receiver/k8sclusterreceiver/internal/metadata/testdata/config.yaml index c78018044e863..69eb73f82c3f0 100644 --- a/receiver/k8sclusterreceiver/internal/metadata/testdata/config.yaml +++ b/receiver/k8sclusterreceiver/internal/metadata/testdata/config.yaml @@ -130,6 +130,8 @@ all_set: enabled: true k8s.pod.name: enabled: true + k8s.pod.qos_class: + enabled: true k8s.pod.uid: enabled: true k8s.replicaset.name: @@ -283,6 +285,8 @@ none_set: enabled: false k8s.pod.name: enabled: false + k8s.pod.qos_class: + enabled: false k8s.pod.uid: enabled: false k8s.replicaset.name: diff --git a/receiver/k8sclusterreceiver/internal/pod/pods.go b/receiver/k8sclusterreceiver/internal/pod/pods.go index ffcff3e2c6eae..5b3c504cda85c 100644 --- a/receiver/k8sclusterreceiver/internal/pod/pods.go +++ b/receiver/k8sclusterreceiver/internal/pod/pods.go @@ -41,7 +41,8 @@ func Transform(pod *corev1.Pod) *corev1.Pod { NodeName: pod.Spec.NodeName, }, Status: corev1.PodStatus{ - Phase: pod.Status.Phase, + Phase: pod.Status.Phase, + QOSClass: pod.Status.QOSClass, }, } for _, cs := range pod.Status.ContainerStatuses { @@ -76,6 +77,7 @@ func RecordMetrics(logger *zap.Logger, mb *metadata.MetricsBuilder, pod *corev1. rb.SetK8sNodeName(pod.Spec.NodeName) rb.SetK8sPodName(pod.Name) rb.SetK8sPodUID(string(pod.UID)) + rb.SetK8sPodQosClass(string(pod.Status.QOSClass)) mb.EmitForResource(metadata.WithResource(rb.Emit())) for _, c := range pod.Spec.Containers { diff --git a/receiver/k8sclusterreceiver/internal/pod/pods_test.go b/receiver/k8sclusterreceiver/internal/pod/pods_test.go index 7c5e40f8ed852..52e801fff117b 100644 --- a/receiver/k8sclusterreceiver/internal/pod/pods_test.go +++ b/receiver/k8sclusterreceiver/internal/pod/pods_test.go @@ -68,6 +68,7 @@ func TestPodStatusReasonAndContainerMetricsReportCPUMetrics(t *testing.T) { mbc := metadata.DefaultMetricsBuilderConfig() mbc.Metrics.K8sPodStatusReason.Enabled = true + mbc.ResourceAttributes.K8sPodQosClass.Enabled = true ts := pcommon.Timestamp(time.Now().UnixNano()) mb := metadata.NewMetricsBuilder(mbc, receivertest.NewNopCreateSettings()) RecordMetrics(zap.NewNop(), mb, pod, ts) diff --git a/receiver/k8sclusterreceiver/internal/pod/testdata/expected_evicted.yaml b/receiver/k8sclusterreceiver/internal/pod/testdata/expected_evicted.yaml index 2a77c97083d60..2da3f591fcd72 100644 --- a/receiver/k8sclusterreceiver/internal/pod/testdata/expected_evicted.yaml +++ b/receiver/k8sclusterreceiver/internal/pod/testdata/expected_evicted.yaml @@ -10,6 +10,9 @@ resourceMetrics: - key: k8s.pod.name value: stringValue: test-pod-1 + - key: k8s.pod.qos_class + value: + stringValue: BestEffort - key: k8s.pod.uid value: stringValue: test-pod-1-uid diff --git a/receiver/k8sclusterreceiver/internal/testutils/objects.go b/receiver/k8sclusterreceiver/internal/testutils/objects.go index b4edefa5eb45a..e331fda815dc1 100644 --- a/receiver/k8sclusterreceiver/internal/testutils/objects.go +++ b/receiver/k8sclusterreceiver/internal/testutils/objects.go @@ -264,8 +264,9 @@ func NewPodStatusWithContainer(containerName, containerID string) *corev1.PodSta func NewEvictedTerminatedPodStatusWithContainer(containerName, containerID string) *corev1.PodStatus { return &corev1.PodStatus{ - Phase: corev1.PodFailed, - Reason: "Evicted", + Phase: corev1.PodFailed, + QOSClass: corev1.PodQOSBestEffort, + Reason: "Evicted", ContainerStatuses: []corev1.ContainerStatus{ { Name: containerName, diff --git a/receiver/k8sclusterreceiver/metadata.yaml b/receiver/k8sclusterreceiver/metadata.yaml index fceeccb83c3e8..0c8e8ebebaaa8 100644 --- a/receiver/k8sclusterreceiver/metadata.yaml +++ b/receiver/k8sclusterreceiver/metadata.yaml @@ -62,6 +62,11 @@ resource_attributes: type: string enabled: true + k8s.pod.qos_class: + description: "The k8s pod qos class name. One of Guaranteed, Burstable, BestEffort." + type: string + enabled: false + k8s.replicaset.name: description: The k8s replicaset name type: string diff --git a/versions.yaml b/versions.yaml index 523df048f113a..18f66f8550dea 100644 --- a/versions.yaml +++ b/versions.yaml @@ -41,6 +41,7 @@ module-sets: - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/googlecloudexporter - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/googlemanagedprometheusexporter - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/googlecloudpubsubexporter + - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/honeycombmarkerexporter - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/influxdbexporter - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/instanaexporter - github.com/open-telemetry/opentelemetry-collector-contrib/exporter/kafkaexporter