From ecaebb98f1ae7531d594d49d24867aecb533198e Mon Sep 17 00:00:00 2001 From: Mengyi Zhou Date: Tue, 22 Oct 2024 12:14:18 -0700 Subject: [PATCH] Enhance the unit conversion in emf exporter --- .chloggen/awsemfexporter-enhancements.yaml | 27 +++++++++++++++ exporter/awsemfexporter/grouped_metric.go | 32 ++++++++++++++---- .../awsemfexporter/grouped_metric_test.go | 33 +++++++++++++------ 3 files changed, 76 insertions(+), 16 deletions(-) create mode 100644 .chloggen/awsemfexporter-enhancements.yaml diff --git a/.chloggen/awsemfexporter-enhancements.yaml b/.chloggen/awsemfexporter-enhancements.yaml new file mode 100644 index 000000000000..06b631ee6be7 --- /dev/null +++ b/.chloggen/awsemfexporter-enhancements.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: "Improvement unit conversion during EMF log translation" + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [35937] + +# (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/exporter/awsemfexporter/grouped_metric.go b/exporter/awsemfexporter/grouped_metric.go index dd3426cdc2e9..7b2319bb2e2c 100644 --- a/exporter/awsemfexporter/grouped_metric.go +++ b/exporter/awsemfexporter/grouped_metric.go @@ -5,6 +5,8 @@ package awsemfexporter // import "github.com/open-telemetry/opentelemetry-collec import ( "encoding/json" + "errors" + "reflect" "strings" "go.opentelemetry.io/collector/pdata/pmetric" @@ -77,9 +79,13 @@ func addToGroupedMetric( } } + unit, val, err := translateUnit(pmd, descriptor, dp.value) + if err != nil { + config.logger.Warn("failed to translate unit", zap.Error(err)) + } metric := &metricInfo{ - value: dp.value, - unit: translateUnit(pmd, descriptor), + value: val, + unit: unit, } if dp.timestampMs > 0 { @@ -186,14 +192,28 @@ func mapGetHelper(labels map[string]string, key string) string { return "" } -func translateUnit(metric pmetric.Metric, descriptor map[string]MetricDescriptor) string { +func translateUnit(metric pmetric.Metric, descriptor map[string]MetricDescriptor, value any) (string, any, error) { unit := metric.Unit() if descriptor, exists := descriptor[metric.Name()]; exists { if unit == "" || descriptor.Overwrite { - return descriptor.Unit + return descriptor.Unit, value, nil } } switch unit { + case "1": + unit = "Count" + case "ns": + // CloudWatch doesn't support Nanoseconds + switch v := value.(type) { + case int: + return "Microseconds", v / 1000, nil + case int64: + return "Microseconds", v / 1000, nil + case float64: + return "Microseconds", v / 1000, nil + default: + return unit, value, errors.New("Failed to convert ns to us with type " + reflect.TypeOf(value).String()) + } case "ms": unit = "Milliseconds" case "s": @@ -202,8 +222,8 @@ func translateUnit(metric pmetric.Metric, descriptor map[string]MetricDescriptor unit = "Microseconds" case "By": unit = "Bytes" - case "Bi": + case "bit": unit = "Bits" } - return unit + return unit, value, nil } diff --git a/exporter/awsemfexporter/grouped_metric_test.go b/exporter/awsemfexporter/grouped_metric_test.go index d2b1a86610f0..b811b664d57f 100644 --- a/exporter/awsemfexporter/grouped_metric_test.go +++ b/exporter/awsemfexporter/grouped_metric_test.go @@ -487,25 +487,38 @@ func TestTranslateUnit(t *testing.T) { } translateUnitCases := map[string]string{ - "Count": "Count", - "ms": "Milliseconds", - "s": "Seconds", - "us": "Microseconds", - "By": "Bytes", - "Bi": "Bits", + "raw": "raw", + "1": "Count", + "ms": "Milliseconds", + "ns": "Microseconds", + "s": "Seconds", + "us": "Microseconds", + "By": "Bytes", + "bit": "Bits", } for input, output := range translateUnitCases { t.Run(input, func(_ *testing.T) { metric.SetUnit(input) - v := translateUnit(metric, translator.metricDescriptor) - assert.Equal(t, output, v) + convertedUnit, data, err := translateUnit(metric, translator.metricDescriptor, 1000) + assert.NoError(t, err) + assert.Equal(t, output, convertedUnit) + if input == "ns" { + assert.Equal(t, 1, data) + } }) } metric.SetName("forceOverwrite") - v := translateUnit(metric, translator.metricDescriptor) - assert.Equal(t, "Count", v) + convertedUnit, _, _ := translateUnit(metric, translator.metricDescriptor, 1) + assert.Equal(t, "Count", convertedUnit) + + metric.SetName("failedConversion") + metric.SetUnit("ns") + convertedUnit, data, err := translateUnit(metric, translator.metricDescriptor, "any") + assert.Error(t, err) + assert.Equal(t, "ns", convertedUnit) + assert.Equal(t, "any", data) } func generateTestMetricMetadata(namespace string, timestamp int64, logGroup, logStreamName, instrumentationScopeName string, metricType pmetric.MetricType) cWMetricMetadata {