diff --git a/.chloggen/awsemf_storageresolution.yaml b/.chloggen/awsemf_storageresolution.yaml new file mode 100644 index 000000000000..bdd7dbad2304 --- /dev/null +++ b/.chloggen/awsemf_storageresolution.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: awsemfexporter + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Add support for 1 second metric resolution in CloudWatch Embedded Metrics Format based on metric attributes + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [29506] + +# (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/exporter/awsemfexporter/README.md b/exporter/awsemfexporter/README.md index 8e79a58c41cf..6eb5d1dd4ebf 100644 --- a/exporter/awsemfexporter/README.md +++ b/exporter/awsemfexporter/README.md @@ -85,6 +85,14 @@ This exporter follows default credential resolution for the Follow the [guidelines](https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html) for the credential configuration. +## Metric Attributes +By setting attributes on your metrics you can change how individual metrics are sent to CloudWatch. Attributes can be set in code or using components like the [Attribute Processor](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/processor/attributesprocessor). + +The AWS EMF Exporter will interpret the following metric attributes to change how it publishes metrics to CloudWatch: + +| Attribute Name | Description | Default | +| :---------------- | :--------------------------------------------------------------------- | ------- | +| `aws.emf.storage_resolution` | This attribute should be set to an integer value of `1` or `60`. When sending the metric value to CloudWatch use the specified storage resolution value. CloudWatch currently supports a storage resolution of `1` or `60` to indicate 1 second or 60 second resolution. | `aws.emf.storage_resolution = 60` | ## Configuration Examples diff --git a/exporter/awsemfexporter/metric_translator.go b/exporter/awsemfexporter/metric_translator.go index bb16a5ea3346..b5d9330503ce 100644 --- a/exporter/awsemfexporter/metric_translator.go +++ b/exporter/awsemfexporter/metric_translator.go @@ -7,6 +7,7 @@ import ( "encoding/json" "fmt" "reflect" + "strconv" "time" "go.opentelemetry.io/collector/pdata/pmetric" @@ -29,6 +30,9 @@ const ( prometheusReceiver = "prometheus" attributeReceiver = "receiver" fieldPrometheusMetricType = "prom_metric_type" + + // metric attributes for AWS EMF, not to be treated as metric labels + emfStorageResolutionAttribute = "aws.emf.storage_resolution" ) var fieldPrometheusTypes = map[pmetric.MetricType]string{ @@ -45,10 +49,16 @@ type cWMetrics struct { fields map[string]any } +type cWMetricInfo struct { + Name string + Unit string + StorageResolution int +} + type cWMeasurement struct { Namespace string Dimensions [][]string - Metrics []map[string]string + Metrics []cWMetricInfo } type cWMetricStats struct { @@ -156,7 +166,7 @@ func (mt metricTranslator) translateOTelToGroupedMetric(rm pmetric.ResourceMetri // translateGroupedMetricToCWMetric converts Grouped Metric format to CloudWatch Metric format. func translateGroupedMetricToCWMetric(groupedMetric *groupedMetric, config *Config) *cWMetrics { - labels := groupedMetric.labels + labels := filterAWSEMFAttributes(groupedMetric.labels) fieldsLength := len(labels) + len(groupedMetric.metrics) isPrometheusMetric := groupedMetric.metadata.receiver == prometheusReceiver @@ -198,7 +208,7 @@ func translateGroupedMetricToCWMetric(groupedMetric *groupedMetric, config *Conf // groupedMetricToCWMeasurement creates a single CW Measurement from a grouped metric. func groupedMetricToCWMeasurement(groupedMetric *groupedMetric, config *Config) cWMeasurement { - labels := groupedMetric.labels + labels := filterAWSEMFAttributes(groupedMetric.labels) dimensionRollupOption := config.DimensionRollupOption // Create a dimension set containing list of label names @@ -208,6 +218,7 @@ func groupedMetricToCWMeasurement(groupedMetric *groupedMetric, config *Config) dimSet[idx] = labelName idx++ } + dimensions := [][]string{dimSet} // Apply single/zero dimension rollup to labels @@ -228,14 +239,20 @@ func groupedMetricToCWMeasurement(groupedMetric *groupedMetric, config *Config) // Add on rolled-up dimensions dimensions = append(dimensions, rollupDimensionArray...) - metrics := make([]map[string]string, len(groupedMetric.metrics)) + metrics := make([]cWMetricInfo, len(groupedMetric.metrics)) idx = 0 for metricName, metricInfo := range groupedMetric.metrics { - metrics[idx] = map[string]string{ - "Name": metricName, + metrics[idx] = cWMetricInfo{ + Name: metricName, + StorageResolution: 60, } if metricInfo.unit != "" { - metrics[idx]["Unit"] = metricInfo.unit + metrics[idx].Unit = metricInfo.unit + } + if storRes, ok := groupedMetric.labels[emfStorageResolutionAttribute]; ok { + if storResInt, err := strconv.Atoi(storRes); err == nil { + metrics[idx].StorageResolution = storResInt + } } idx++ } @@ -250,7 +267,7 @@ func groupedMetricToCWMeasurement(groupedMetric *groupedMetric, config *Config) // groupedMetricToCWMeasurementsWithFilters filters the grouped metric using the given list of metric // declarations and returns the corresponding list of CW Measurements. func groupedMetricToCWMeasurementsWithFilters(groupedMetric *groupedMetric, config *Config) (cWMeasurements []cWMeasurement) { - labels := groupedMetric.labels + labels := filterAWSEMFAttributes(groupedMetric.labels) // Filter metric declarations by labels metricDeclarations := make([]*MetricDeclaration, 0, len(config.MetricDeclarations)) @@ -278,7 +295,7 @@ func groupedMetricToCWMeasurementsWithFilters(groupedMetric *groupedMetric, conf // Group metrics by matched metric declarations type metricDeclarationGroup struct { metricDeclIdxList []int - metrics []map[string]string + metrics []cWMetricInfo } metricDeclGroups := make(map[string]*metricDeclarationGroup) @@ -299,11 +316,17 @@ func groupedMetricToCWMeasurementsWithFilters(groupedMetric *groupedMetric, conf continue } - metric := map[string]string{ - "Name": metricName, + metric := cWMetricInfo{ + Name: metricName, + StorageResolution: 60, } if metricInfo.unit != "" { - metric["Unit"] = metricInfo.unit + metric.Unit = metricInfo.unit + } + if storRes, ok := groupedMetric.labels[emfStorageResolutionAttribute]; ok { + if storResInt, err := strconv.Atoi(storRes); err == nil { + metric.StorageResolution = storResInt + } } metricDeclKey := fmt.Sprint(metricDeclIdx) if group, ok := metricDeclGroups[metricDeclKey]; ok { @@ -311,7 +334,7 @@ func groupedMetricToCWMeasurementsWithFilters(groupedMetric *groupedMetric, conf } else { metricDeclGroups[metricDeclKey] = &metricDeclarationGroup{ metricDeclIdxList: metricDeclIdx, - metrics: []map[string]string{metric}, + metrics: []cWMetricInfo{metric}, } } } @@ -465,3 +488,14 @@ func translateGroupedMetricToEmf(groupedMetric *groupedMetric, config *Config, d return event, nil } + +func filterAWSEMFAttributes(labels map[string]string) map[string]string { + // remove any labels that are attributes specific to AWS EMF Exporter + filteredLabels := make(map[string]string) + for labelName := range labels { + if labelName != emfStorageResolutionAttribute { + filteredLabels[labelName] = labels[labelName] + } + } + return filteredLabels +} diff --git a/exporter/awsemfexporter/metric_translator_test.go b/exporter/awsemfexporter/metric_translator_test.go index 15c74767d7d8..3a8f9268624c 100644 --- a/exporter/awsemfexporter/metric_translator_test.go +++ b/exporter/awsemfexporter/metric_translator_test.go @@ -163,11 +163,11 @@ func normalizeDimensionality(dims [][]string) [][]string { } // hashMetricSlice hashes a metrics slice for equality checking. -func hashMetricSlice(metricSlice []map[string]string) []string { +func hashMetricSlice(metricSlice []cWMetricInfo) []string { // Convert to string for easier sorting stringified := make([]string, len(metricSlice)) for i, v := range metricSlice { - stringified[i] = v["Name"] + "," + v["Unit"] + stringified[i] = fmt.Sprint(v.Name) + "," + fmt.Sprint(v.Unit) + "," + fmt.Sprint(v.StorageResolution) } // Sort across metrics for equality checking sort.Strings(stringified) @@ -397,24 +397,26 @@ func TestTranslateCWMetricToEMF(t *testing.T) { measurements: []cWMeasurement{{ Namespace: "test-emf", Dimensions: [][]string{{oTellibDimensionKey}, {oTellibDimensionKey, "spanName"}}, - Metrics: []map[string]string{{ - "Name": "spanCounter", - "Unit": "Count", + Metrics: []cWMetricInfo{{ + Name: "spanCounter", + Unit: "Count", + StorageResolution: 1, }}, }}, - expectedEMFLogEvent: "{\"OTelLib\":\"cloudwatch-otel\",\"Sources\":[\"cadvisor\",\"pod\",\"calculated\"],\"Version\":\"1\",\"_aws\":{\"CloudWatchMetrics\":[{\"Namespace\":\"test-emf\",\"Dimensions\":[[\"OTelLib\"],[\"OTelLib\",\"spanName\"]],\"Metrics\":[{\"Name\":\"spanCounter\",\"Unit\":\"Count\"}]}],\"Timestamp\":1596151098037},\"kubernetes\":{\"container_name\":\"cloudwatch-agent\",\"docker\":{\"container_id\":\"fc1b0a4c3faaa1808e187486a3a90cbea883dccaf2e2c46d4069d663b032a1ca\"},\"host\":\"ip-192-168-58-245.ec2.internal\",\"labels\":{\"controller-revision-hash\":\"5bdbf497dc\",\"name\":\"cloudwatch-agent\",\"pod-template-generation\":\"1\"},\"namespace_name\":\"amazon-cloudwatch\",\"pod_id\":\"e23f3413-af2e-4a98-89e0-5df2251e7f05\",\"pod_name\":\"cloudwatch-agent-26bl6\",\"pod_owners\":[{\"owner_kind\":\"DaemonSet\",\"owner_name\":\"cloudwatch-agent\"}]},\"spanCounter\":0,\"spanName\":\"test\"}", + expectedEMFLogEvent: "{\"OTelLib\":\"cloudwatch-otel\",\"Sources\":[\"cadvisor\",\"pod\",\"calculated\"],\"Version\":\"1\",\"_aws\":{\"CloudWatchMetrics\":[{\"Namespace\":\"test-emf\",\"Dimensions\":[[\"OTelLib\"],[\"OTelLib\",\"spanName\"]],\"Metrics\":[{\"Name\":\"spanCounter\",\"Unit\":\"Count\",\"StorageResolution\":1}]}],\"Timestamp\":1596151098037},\"kubernetes\":{\"container_name\":\"cloudwatch-agent\",\"docker\":{\"container_id\":\"fc1b0a4c3faaa1808e187486a3a90cbea883dccaf2e2c46d4069d663b032a1ca\"},\"host\":\"ip-192-168-58-245.ec2.internal\",\"labels\":{\"controller-revision-hash\":\"5bdbf497dc\",\"name\":\"cloudwatch-agent\",\"pod-template-generation\":\"1\"},\"namespace_name\":\"amazon-cloudwatch\",\"pod_id\":\"e23f3413-af2e-4a98-89e0-5df2251e7f05\",\"pod_name\":\"cloudwatch-agent-26bl6\",\"pod_owners\":[{\"owner_kind\":\"DaemonSet\",\"owner_name\":\"cloudwatch-agent\"}]},\"spanCounter\":0,\"spanName\":\"test\"}", }, "WithMeasurementAndEMFV0": { emfVersion: "0", measurements: []cWMeasurement{{ Namespace: "test-emf", Dimensions: [][]string{{oTellibDimensionKey}, {oTellibDimensionKey, "spanName"}}, - Metrics: []map[string]string{{ - "Name": "spanCounter", - "Unit": "Count", + Metrics: []cWMetricInfo{{ + Name: "spanCounter", + Unit: "Count", + StorageResolution: 60, }}, }}, - expectedEMFLogEvent: "{\"CloudWatchMetrics\":[{\"Namespace\":\"test-emf\",\"Dimensions\":[[\"OTelLib\"],[\"OTelLib\",\"spanName\"]],\"Metrics\":[{\"Name\":\"spanCounter\",\"Unit\":\"Count\"}]}],\"OTelLib\":\"cloudwatch-otel\",\"Sources\":[\"cadvisor\",\"pod\",\"calculated\"],\"Timestamp\":\"1596151098037\",\"Version\":\"0\",\"kubernetes\":{\"container_name\":\"cloudwatch-agent\",\"docker\":{\"container_id\":\"fc1b0a4c3faaa1808e187486a3a90cbea883dccaf2e2c46d4069d663b032a1ca\"},\"host\":\"ip-192-168-58-245.ec2.internal\",\"labels\":{\"controller-revision-hash\":\"5bdbf497dc\",\"name\":\"cloudwatch-agent\",\"pod-template-generation\":\"1\"},\"namespace_name\":\"amazon-cloudwatch\",\"pod_id\":\"e23f3413-af2e-4a98-89e0-5df2251e7f05\",\"pod_name\":\"cloudwatch-agent-26bl6\",\"pod_owners\":[{\"owner_kind\":\"DaemonSet\",\"owner_name\":\"cloudwatch-agent\"}]},\"spanCounter\":0,\"spanName\":\"test\"}", + expectedEMFLogEvent: "{\"CloudWatchMetrics\":[{\"Namespace\":\"test-emf\",\"Dimensions\":[[\"OTelLib\"],[\"OTelLib\",\"spanName\"]],\"Metrics\":[{\"Name\":\"spanCounter\",\"Unit\":\"Count\",\"StorageResolution\":60}]}],\"OTelLib\":\"cloudwatch-otel\",\"Sources\":[\"cadvisor\",\"pod\",\"calculated\"],\"Timestamp\":\"1596151098037\",\"Version\":\"0\",\"kubernetes\":{\"container_name\":\"cloudwatch-agent\",\"docker\":{\"container_id\":\"fc1b0a4c3faaa1808e187486a3a90cbea883dccaf2e2c46d4069d663b032a1ca\"},\"host\":\"ip-192-168-58-245.ec2.internal\",\"labels\":{\"controller-revision-hash\":\"5bdbf497dc\",\"name\":\"cloudwatch-agent\",\"pod-template-generation\":\"1\"},\"namespace_name\":\"amazon-cloudwatch\",\"pod_id\":\"e23f3413-af2e-4a98-89e0-5df2251e7f05\",\"pod_name\":\"cloudwatch-agent-26bl6\",\"pod_owners\":[{\"owner_kind\":\"DaemonSet\",\"owner_name\":\"cloudwatch-agent\"}]},\"spanCounter\":0,\"spanName\":\"test\"}", }, "WithNoMeasurementAndEMFV1": { emfVersion: "1", @@ -493,10 +495,11 @@ func TestTranslateGroupedMetricToCWMetric(t *testing.T) { { Namespace: namespace, Dimensions: [][]string{{"label1"}}, - Metrics: []map[string]string{ + Metrics: []cWMetricInfo{ { - "Name": "metric1", - "Unit": "Count", + Name: "metric1", + Unit: "Count", + StorageResolution: 60, }, }, }, @@ -538,10 +541,11 @@ func TestTranslateGroupedMetricToCWMetric(t *testing.T) { { Namespace: namespace, Dimensions: [][]string{{"label1"}}, - Metrics: []map[string]string{ + Metrics: []cWMetricInfo{ { - "Name": "metric1", - "Unit": "Count", + Name: "metric1", + Unit: "Count", + StorageResolution: 60, }, }, }, @@ -587,18 +591,21 @@ func TestTranslateGroupedMetricToCWMetric(t *testing.T) { { Namespace: namespace, Dimensions: [][]string{{"label1", "label2"}}, - Metrics: []map[string]string{ + Metrics: []cWMetricInfo{ { - "Name": "metric1", - "Unit": "Count", + Name: "metric1", + Unit: "Count", + StorageResolution: 60, }, { - "Name": "metric2", - "Unit": "Count", + Name: "metric2", + Unit: "Count", + StorageResolution: 60, }, { - "Name": "metric3", - "Unit": "Seconds", + Name: "metric3", + Unit: "Seconds", + StorageResolution: 60, }, }, }, @@ -662,20 +669,22 @@ func TestTranslateGroupedMetricToCWMetric(t *testing.T) { { Namespace: namespace, Dimensions: [][]string{{"label1"}}, - Metrics: []map[string]string{ + Metrics: []cWMetricInfo{ { - "Name": "metric1", - "Unit": "Count", + Name: "metric1", + Unit: "Count", + StorageResolution: 60, }, }, }, { Namespace: namespace, Dimensions: [][]string{{"label1", "label2"}}, - Metrics: []map[string]string{ + Metrics: []cWMetricInfo{ { - "Name": "metric2", - "Unit": "Count", + Name: "metric2", + Unit: "Count", + StorageResolution: 60, }, }, }, @@ -746,10 +755,11 @@ func TestTranslateGroupedMetricToCWMetric(t *testing.T) { { Namespace: namespace, Dimensions: [][]string{{"label1"}}, - Metrics: []map[string]string{ + Metrics: []cWMetricInfo{ { - "Name": "metric1", - "Unit": "Count", + Name: "metric1", + Unit: "Count", + StorageResolution: 60, }, }, }, @@ -816,10 +826,11 @@ func TestGroupedMetricToCWMeasurement(t *testing.T) { cWMeasurement{ Namespace: namespace, Dimensions: [][]string{{"label1"}}, - Metrics: []map[string]string{ + Metrics: []cWMetricInfo{ { - "Name": "metric1", - "Unit": "Count", + Name: "metric1", + Unit: "Count", + StorageResolution: 60, }, }, }, @@ -856,18 +867,21 @@ func TestGroupedMetricToCWMeasurement(t *testing.T) { cWMeasurement{ Namespace: namespace, Dimensions: [][]string{{"label1", "label2"}}, - Metrics: []map[string]string{ + Metrics: []cWMetricInfo{ { - "Name": "metric1", - "Unit": "Count", + Name: "metric1", + Unit: "Count", + StorageResolution: 60, }, { - "Name": "metric2", - "Unit": "Count", + Name: "metric2", + Unit: "Count", + StorageResolution: 60, }, { - "Name": "metric3", - "Unit": "Seconds", + Name: "metric3", + Unit: "Seconds", + StorageResolution: 60, }, }, }, @@ -895,10 +909,11 @@ func TestGroupedMetricToCWMeasurement(t *testing.T) { cWMeasurement{ Namespace: namespace, Dimensions: [][]string{{"label1"}}, - Metrics: []map[string]string{ + Metrics: []cWMetricInfo{ { - "Name": "metric1", - "Unit": "Count", + Name: "metric1", + Unit: "Count", + StorageResolution: 60, }, }, }, @@ -940,18 +955,21 @@ func TestGroupedMetricToCWMeasurement(t *testing.T) { {"label2"}, {}, }, - Metrics: []map[string]string{ + Metrics: []cWMetricInfo{ { - "Name": "metric1", - "Unit": "Count", + Name: "metric1", + Unit: "Count", + StorageResolution: 60, }, { - "Name": "metric2", - "Unit": "Count", + Name: "metric2", + Unit: "Count", + StorageResolution: 60, }, { - "Name": "metric3", - "Unit": "Seconds", + Name: "metric3", + Unit: "Seconds", + StorageResolution: 60, }, }, }, @@ -1183,18 +1201,21 @@ func TestGroupedMetricToCWMeasurementsWithFilters(t *testing.T) { { Namespace: namespace, Dimensions: [][]string{{"a"}, {"a", "c"}}, - Metrics: []map[string]string{ + Metrics: []cWMetricInfo{ { - "Name": "metric1", - "Unit": "Count", + Name: "metric1", + Unit: "Count", + StorageResolution: 60, }, { - "Name": "metric2", - "Unit": "Count", + Name: "metric2", + Unit: "Count", + StorageResolution: 60, }, { - "Name": "metric3", - "Unit": "Seconds", + Name: "metric3", + Unit: "Seconds", + StorageResolution: 60, }, }, }, @@ -1220,30 +1241,33 @@ func TestGroupedMetricToCWMeasurementsWithFilters(t *testing.T) { { Namespace: namespace, Dimensions: [][]string{{"a"}, {"b"}, {"a", "c"}}, - Metrics: []map[string]string{ + Metrics: []cWMetricInfo{ { - "Name": "metric1", - "Unit": "Count", + Name: "metric1", + Unit: "Count", + StorageResolution: 60, }, }, }, { Namespace: namespace, Dimensions: [][]string{{"a"}, {"b"}}, - Metrics: []map[string]string{ + Metrics: []cWMetricInfo{ { - "Name": "metric2", - "Unit": "Count", + Name: "metric2", + Unit: "Count", + StorageResolution: 60, }, }, }, { Namespace: namespace, Dimensions: [][]string{{"a"}}, - Metrics: []map[string]string{ + Metrics: []cWMetricInfo{ { - "Name": "metric3", - "Unit": "Seconds", + Name: "metric3", + Unit: "Seconds", + StorageResolution: 60, }, }, }, @@ -1265,24 +1289,27 @@ func TestGroupedMetricToCWMeasurementsWithFilters(t *testing.T) { { Namespace: namespace, Dimensions: [][]string{{"a"}, {"b"}}, - Metrics: []map[string]string{ + Metrics: []cWMetricInfo{ { - "Name": "metric1", - "Unit": "Count", + Name: "metric1", + Unit: "Count", + StorageResolution: 60, }, { - "Name": "metric2", - "Unit": "Count", + Name: "metric2", + Unit: "Count", + StorageResolution: 60, }, }, }, { Namespace: namespace, Dimensions: [][]string{{"a"}}, - Metrics: []map[string]string{ + Metrics: []cWMetricInfo{ { - "Name": "metric3", - "Unit": "Seconds", + Name: "metric3", + Unit: "Seconds", + StorageResolution: 60, }, }, }, @@ -1304,14 +1331,16 @@ func TestGroupedMetricToCWMeasurementsWithFilters(t *testing.T) { { Namespace: namespace, Dimensions: [][]string{{"a"}, {"b"}}, - Metrics: []map[string]string{ + Metrics: []cWMetricInfo{ { - "Name": "metric1", - "Unit": "Count", + Name: "metric1", + Unit: "Count", + StorageResolution: 60, }, { - "Name": "metric2", - "Unit": "Count", + Name: "metric2", + Unit: "Count", + StorageResolution: 60, }, }, }, @@ -1339,14 +1368,16 @@ func TestGroupedMetricToCWMeasurementsWithFilters(t *testing.T) { { Namespace: namespace, Dimensions: [][]string{{}}, - Metrics: []map[string]string{ + Metrics: []cWMetricInfo{ { - "Name": "metric1", - "Unit": "Count", + Name: "metric1", + Unit: "Count", + StorageResolution: 60, }, { - "Name": "metric3", - "Unit": "Seconds", + Name: "metric3", + Unit: "Seconds", + StorageResolution: 60, }, }, }, @@ -1380,18 +1411,21 @@ func TestGroupedMetricToCWMeasurementsWithFilters(t *testing.T) { { Namespace: namespace, Dimensions: [][]string{{"b"}}, - Metrics: []map[string]string{ + Metrics: []cWMetricInfo{ { - "Name": "metric1", - "Unit": "Count", + Name: "metric1", + Unit: "Count", + StorageResolution: 60, }, { - "Name": "metric2", - "Unit": "Count", + Name: "metric2", + Unit: "Count", + StorageResolution: 60, }, { - "Name": "metric3", - "Unit": "Seconds", + Name: "metric3", + Unit: "Seconds", + StorageResolution: 60, }, }, }, @@ -2154,9 +2188,9 @@ func BenchmarkTranslateCWMetricToEMF(b *testing.B) { cwMeasurement := cWMeasurement{ Namespace: "test-emf", Dimensions: [][]string{{oTellibDimensionKey}, {oTellibDimensionKey, "spanName"}}, - Metrics: []map[string]string{{ - "Name": "spanCounter", - "Unit": "Count", + Metrics: []cWMetricInfo{{ + Name: "spanCounter", + Unit: "Count", }}, } timestamp := int64(1596151098037)