diff --git a/exporter/awsemfexporter/README.md b/exporter/awsemfexporter/README.md index c71c51ea87a1..f80b4a580438 100644 --- a/exporter/awsemfexporter/README.md +++ b/exporter/awsemfexporter/README.md @@ -18,32 +18,32 @@ Convert OpenTelemetry ```Int64DataPoints```, ```DoubleDataPoints```, ```SummaryD The following exporter configuration parameters are supported. -| Name | Description | Default | -|:---------------------------------------------| :--------------------------------------------------------------------- | ------- | -| `log_group_name` | Customized log group name which supports `{ClusterName}` and `{TaskId}` placeholders. One valid example is `/aws/metrics/{ClusterName}`. It will search for `ClusterName` (or `aws.ecs.cluster.name`) resource attribute in the metrics data and replace with the actual cluster name. If none of them are found in the resource attribute map, `{ClusterName}` will be replaced by `undefined`. Similar way, for the `{TaskId}`, it searches for `TaskId` (or `aws.ecs.task.id`) key in the resource attribute map. For `{NodeName}`, it searches for `NodeName` (or `k8s.node.name`) |"/metrics/default"| -| `log_stream_name` | Customized log stream name which supports `{TaskId}`, `{ClusterName}`, `{NodeName}`, `{ContainerInstanceId}`, and `{TaskDefinitionFamily}` placeholders. One valid example is `{TaskId}`. It will search for `TaskId` (or `aws.ecs.task.id`) resource attribute in the metrics data and replace with the actual task id. If none of them are found in the resource attribute map, `{TaskId}` will be replaced by `undefined`. Similarly, for the `{TaskDefinitionFamily}`, it searches for `TaskDefinitionFamily` (or `aws.ecs.task.family`). For the `{ClusterName}`, it searches for `ClusterName` (or `aws.ecs.cluster.name`). For `{NodeName}`, it searches for `NodeName` (or `k8s.node.name`). For `{ContainerInstanceId}`, it searches for `ContainerInstanceId` (or `aws.ecs.container.instance.id`). (Note: ContainerInstanceId (or `aws.ecs.container.instance.id`) only works for AWS ECS EC2 launch type. |"otel-stream"| -| `namespace` | Customized CloudWatch metrics namespace | "default" | -| `endpoint` | Optionally override the default CloudWatch service endpoint. | | -| `no_verify_ssl` | Enable or disable TLS certificate verification. | false | -| `proxy_address` | Upload Structured Logs to AWS CloudWatch through a proxy. | | -| `region` | Send Structured Logs to AWS CloudWatch in a specific region. If this field is not present in config, environment variable "AWS_REGION" can then be used to set region.| determined by metadata | -| `role_arn` | IAM role to upload segments to a different account. | | -| `max_retries` | Maximum number of retries before abandoning an attempt to post data. | 1 | -| `dimension_rollup_option` | DimensionRollupOption is the option for metrics dimension rollup. Three options are available. |"ZeroAndSingleDimensionRollup" (Enable both zero dimension rollup and single dimension rollup)| -| `resource_to_telemetry_conversion` | "resource_to_telemetry_conversion" is the option for converting resource attributes to telemetry attributes. It has only one config onption- `enabled`. For metrics, if `enabled=true`, all the resource attributes will be converted to metric labels by default. See `Resource Attributes to Metric Labels` section below for examples. | `enabled=false` | -| `output_destination` | "output_destination" is an option to specify the EMFExporter output. Currently, two options are available. "cloudwatch" or "stdout" | `cloudwatch` | -| `parse_json_encoded_attr_values` | List of attribute keys whose corresponding values are JSON-encoded strings and will be converted to JSON structures in emf logs. For example, the attribute string value "{\\"x\\":5,\\"y\\":6}" will be converted to a json object: ```{"x": 5, "y": 6}```| [ ] | -| [`metric_declarations`](#metric_declaration) | List of rules for filtering exported metrics and their dimensions. | [ ] | -| [`metric_descriptors`](#metric_descriptor) | List of rules for inserting or updating metric descriptors.| [ ]| +| Name | Description | Default | +|:---------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ------- | +| `log_group_name` | Customized log group name which supports `{ClusterName}` and `{TaskId}` placeholders. One valid example is `/aws/metrics/{ClusterName}`. It will search for `ClusterName` (or `aws.ecs.cluster.name`) resource attribute in the metrics data and replace with the actual cluster name. If none of them are found in the resource attribute map, `{ClusterName}` will be replaced by `undefined`. Similar way, for the `{TaskId}`, it searches for `TaskId` (or `aws.ecs.task.id`) key in the resource attribute map. For `{NodeName}`, it searches for `NodeName` (or `k8s.node.name`) |"/metrics/default"| +| `log_stream_name` | Customized log stream name which supports `{TaskId}`, `{ClusterName}`, `{NodeName}`, `{ContainerInstanceId}`, and `{TaskDefinitionFamily}` placeholders. One valid example is `{TaskId}`. It will search for `TaskId` (or `aws.ecs.task.id`) resource attribute in the metrics data and replace with the actual task id. If none of them are found in the resource attribute map, `{TaskId}` will be replaced by `undefined`. Similarly, for the `{TaskDefinitionFamily}`, it searches for `TaskDefinitionFamily` (or `aws.ecs.task.family`). For the `{ClusterName}`, it searches for `ClusterName` (or `aws.ecs.cluster.name`). For `{NodeName}`, it searches for `NodeName` (or `k8s.node.name`). For `{ContainerInstanceId}`, it searches for `ContainerInstanceId` (or `aws.ecs.container.instance.id`). (Note: ContainerInstanceId (or `aws.ecs.container.instance.id`) only works for AWS ECS EC2 launch type. |"otel-stream"| +| `namespace` | Customized CloudWatch metrics namespace | "default" | +| `endpoint` | Optionally override the default CloudWatch service endpoint. | | +| `no_verify_ssl` | Enable or disable TLS certificate verification. | false | +| `proxy_address` | Upload Structured Logs to AWS CloudWatch through a proxy. | | +| `region` | Send Structured Logs to AWS CloudWatch in a specific region. If this field is not present in config, environment variable "AWS_REGION" can then be used to set region. | determined by metadata | +| `role_arn` | IAM role to upload segments to a different account. | | +| `max_retries` | Maximum number of retries before abandoning an attempt to post data. | 1 | +| `dimension_rollup_option` | DimensionRollupOption is the option for metrics dimension rollup. Three options are available: `NoDimensionRollup`, `SingleDimensionRollupOnly` and `ZeroAndSingleDimensionRollup` |"ZeroAndSingleDimensionRollup" (Enable both zero dimension rollup and single dimension rollup)| +| `resource_to_telemetry_conversion` | "resource_to_telemetry_conversion" is the option for converting resource attributes to telemetry attributes. It has only one config onption- `enabled`. For metrics, if `enabled=true`, all the resource attributes will be converted to metric labels by default. See `Resource Attributes to Metric Labels` section below for examples. | `enabled=false` | +| `output_destination` | "output_destination" is an option to specify the EMFExporter output. Currently, two options are available. "cloudwatch" or "stdout" | `cloudwatch` | +| `parse_json_encoded_attr_values` | List of attribute keys whose corresponding values are JSON-encoded strings and will be converted to JSON structures in emf logs. For example, the attribute string value "{\\"x\\":5,\\"y\\":6}" will be converted to a json object: ```{"x": 5, "y": 6}``` | [ ] | +| [`metric_declarations`](#metric_declaration) | List of rules for filtering exported metrics and their dimensions. | [ ] | +| [`metric_descriptors`](#metric_descriptor) | List of rules for inserting or updating metric descriptors. | [ ]| ### metric_declaration A metric_declaration section characterizes a rule to be used to set dimensions for exported metrics, filtered by the incoming metrics' labels and metric names. -| Name | Description | Default | -| :---------------- | :--------------------------------------------------------------------- | ------- | -| `dimensions` | List of dimension sets to be exported. | [[ ]] | -| `metric_name_selectors` | List of regex strings to filter metric names by. | | -| [`label_matchers`](#label_matcher) | (Optional) list of label matching rules to filter metrics by their labels. This rule is applied to any metric that matches any of the label matchers. | [ ] | +| Name | Description | Default | +| :---------------- |:------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ------- | +| `dimensions` | List of dimension sets to be exported. Dimension sets that include dimensions that are not labels are ignored. Use empty dimension set `[]` for metrics without labels. | [[ ]] | +| `metric_name_selectors` | List of regex strings to filter metric names by. | | +| [`label_matchers`](#label_matcher) | (Optional) list of label matching rules to filter metrics by their labels. This rule is applied to any metric that matches any of the label matchers. | [ ] | #### label_matcher A label_matcher section defines a matching rule against the labels of the incoming metric. Only metrics that match the rules will be used by the surrounding `metric_declaration`. @@ -87,5 +87,25 @@ exporters: enabled: true ``` +### Metric Declaration + +The following is an example of how to use `metric_declaration` to select what metrics should be exported. + +```yaml +exporters: + awsemf: + region: 'us-west-2' + output_destination: stdout + dimension_rollup_option: "NoDimensionRollup" + metric_declarations: + - dimensions: [[]] + metric_name_selectors: + # Metric without label + - "^node_load15$" + - dimensions: [[device, fstype], []] + metric_name_selectors: + - "^node_filesystem_readonly$" +``` + [beta]:https://github.com/open-telemetry/opentelemetry-collector#beta -[contrib]:https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib \ No newline at end of file +[contrib]:https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib diff --git a/exporter/awsemfexporter/metric_declaration.go b/exporter/awsemfexporter/metric_declaration.go index 850668cddb3c..af3343e48173 100644 --- a/exporter/awsemfexporter/metric_declaration.go +++ b/exporter/awsemfexporter/metric_declaration.go @@ -160,9 +160,6 @@ func (m *MetricDeclaration) MatchesLabels(labels map[string]string) bool { // returns dimensions that only contains labels from in the given label set. func (m *MetricDeclaration) ExtractDimensions(labels map[string]string) (dimensions [][]string) { for _, dimensionSet := range m.Dimensions { - if len(dimensionSet) == 0 { - continue - } includeSet := true for _, dim := range dimensionSet { if _, ok := labels[dim]; !ok { diff --git a/exporter/awsemfexporter/metric_declaration_test.go b/exporter/awsemfexporter/metric_declaration_test.go index 71d7be3aa6c8..4cea0480ed9c 100644 --- a/exporter/awsemfexporter/metric_declaration_test.go +++ b/exporter/awsemfexporter/metric_declaration_test.go @@ -579,7 +579,7 @@ func TestExtractDimensions(t *testing.T) { map[string]string{ "a": "foo", }, - nil, + [][]string{{}}, }, } logger := zap.NewNop() diff --git a/exporter/awsemfexporter/metric_translator_test.go b/exporter/awsemfexporter/metric_translator_test.go index bf5616370e93..ba7eca725093 100644 --- a/exporter/awsemfexporter/metric_translator_test.go +++ b/exporter/awsemfexporter/metric_translator_test.go @@ -1437,6 +1437,30 @@ func TestGroupedMetricToCWMeasurementsWithFilters(t *testing.T) { }, nil, }, + { + "empty dimension set matches", + []*MetricDeclaration{ + { + Dimensions: [][]string{{}}, + MetricNameSelectors: []string{"metric(1|3)"}, + }, + }, []cWMeasurement{ + { + Namespace: namespace, + Dimensions: [][]string{{}}, + Metrics: []map[string]string{ + { + "Name": "metric1", + "Unit": "Count", + }, + { + "Name": "metric3", + "Unit": "Seconds", + }, + }, + }, + }, + }, { "label matchers", []*MetricDeclaration{ @@ -1997,6 +2021,18 @@ func TestGroupedMetricToCWMeasurementsWithFilters(t *testing.T) { zeroAndSingleDimensionRollup, nil, }, + { + "no labels with empty dimension", + map[string]string{}, + []*MetricDeclaration{ + { + Dimensions: [][]string{{}, {"a"}}, + MetricNameSelectors: []string{metricName}, + }, + }, + zeroAndSingleDimensionRollup, + [][]string{{}}, + }, } for _, tc := range rollupTestCases { diff --git a/unreleased/awsemfexporter-fix-4739.yaml b/unreleased/awsemfexporter-fix-4739.yaml new file mode 100644 index 000000000000..92b68878c437 --- /dev/null +++ b/unreleased/awsemfexporter-fix-4739.yaml @@ -0,0 +1,4 @@ +change_type: bug_fix +component: awsemfexporter +note: "Properly handle empty dimension set in metric_declarations" +issues: [13766]