Skip to content

Commit 04e45ae

Browse files
[exporter/azuremonitor] Enrich azuremonitor tags (#40791)
<!--Ex. Fixing a bug - Describe the bug and how this fixes the issue. Ex. Adding a feature - Explain what this achieves.--> #### Description Adds additional mapping in Azure Monitor Exporter to the following Application Insights properties: | Application Insights property | OpenTelemetry attribute | ----------------------------- | ----------------------------------------------------- | application_Version | service.version | client_OS | os.name concatenated with os.version | client_Model | device.manufacturer | client_Type | device.model.identifier <!-- Issue number (e.g. #1234) or full URL to issue, if applicable. --> #### Link to tracking issue Fixes #40598 --------- Co-authored-by: Dmitry Anoshin <[email protected]>
1 parent b2e7cb0 commit 04e45ae

File tree

7 files changed

+122
-1
lines changed

7 files changed

+122
-1
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: exporter/azuremonitor
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Add additional mapping of standard OTel properties to builtin Application Insights properties
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [40598]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: [user]

exporter/azuremonitorexporter/contracts_utils.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,34 @@ func applyCloudTagsToEnvelope(envelope *contracts.Envelope, resourceAttributes p
4343
envelope.Tags[contracts.InternalSdkVersion] = getCollectorVersion()
4444
}
4545

46+
// Sets ai.application.* tags on the envelope
47+
func applyApplicationTagsToEnvelope(envelope *contracts.Envelope, resourceAttributes pcommon.Map) {
48+
if serviceVersion, serviceVersionExists := resourceAttributes.Get(string(conventions.ServiceVersionKey)); serviceVersionExists {
49+
envelope.Tags[contracts.ApplicationVersion] = serviceVersion.Str()
50+
}
51+
}
52+
53+
// Sets ai.device.* tags on the envelope
54+
func applyDeviceTagsToEnvelope(envelope *contracts.Envelope, resourceAttributes pcommon.Map) {
55+
if osName, osNameExists := resourceAttributes.Get(string(conventions.OSNameKey)); osNameExists {
56+
deviceOs := osName.Str()
57+
58+
if osVersion, osVersionExists := resourceAttributes.Get(string(conventions.OSVersionKey)); osVersionExists {
59+
deviceOs = deviceOs + " " + osVersion.Str()
60+
}
61+
62+
envelope.Tags[contracts.DeviceOSVersion] = deviceOs
63+
}
64+
65+
if manufacturer, manufacturerExists := resourceAttributes.Get(string(conventions.DeviceManufacturerKey)); manufacturerExists {
66+
envelope.Tags[contracts.DeviceModel] = manufacturer.Str()
67+
}
68+
69+
if deviceType, deviceTypeExists := resourceAttributes.Get(string(conventions.DeviceModelIdentifierKey)); deviceTypeExists {
70+
envelope.Tags[contracts.DeviceType] = deviceType.Str()
71+
}
72+
}
73+
4674
// Applies internal sdk version tag on the envelope
4775
func applyInternalSdkVersionTagToEnvelope(envelope *contracts.Envelope) {
4876
envelope.Tags[contracts.InternalSdkVersion] = getCollectorVersion()

exporter/azuremonitorexporter/log_to_envelope.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ func (packer *logPacker) handleMessageData(envelope *contracts.Envelope, data *c
6565
applyResourcesToDataProperties(messageData.Properties, resourceAttributes)
6666
applyInstrumentationScopeValueToDataProperties(messageData.Properties, instrumentationScope)
6767
applyCloudTagsToEnvelope(envelope, resourceAttributes)
68+
applyApplicationTagsToEnvelope(envelope, resourceAttributes)
69+
applyDeviceTagsToEnvelope(envelope, resourceAttributes)
6870
applyInternalSdkVersionTagToEnvelope(envelope)
6971

7072
setAttributesAsProperties(logRecord.Attributes(), messageData.Properties)
@@ -119,6 +121,8 @@ func (packer *logPacker) handleExceptionData(envelope *contracts.Envelope, data
119121
applyResourcesToDataProperties(exceptionData.Properties, resourceAttributes)
120122
applyInstrumentationScopeValueToDataProperties(exceptionData.Properties, instrumentationScope)
121123
applyCloudTagsToEnvelope(envelope, resourceAttributes)
124+
applyApplicationTagsToEnvelope(envelope, resourceAttributes)
125+
applyDeviceTagsToEnvelope(envelope, resourceAttributes)
122126
applyInternalSdkVersionTagToEnvelope(envelope)
123127

124128
setAttributesAsProperties(logAttributeMap, exceptionData.Properties)

exporter/azuremonitorexporter/logexporter_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,38 @@ func TestLogRecordToEnvelopeCloudTags(t *testing.T) {
183183
require.Equal(t, expectedCloudRoleInstance, envelope.Tags[aiCloudRoleInstanceConvention])
184184
}
185185

186+
func TestLogRecordToEnvelopeApplicationTags(t *testing.T) {
187+
const aiAppVersionConvention = "ai.application.ver"
188+
189+
resource, scope, logRecord := getTestLogRecord(1)
190+
logPacker := getLogPacker()
191+
192+
envelope := logPacker.LogRecordToEnvelope(logRecord, resource, scope)
193+
194+
resourceAttributes := resource.Attributes().AsRaw()
195+
expectedAppVer := resourceAttributes[string(conventions.ServiceVersionKey)].(string)
196+
require.Equal(t, expectedAppVer, envelope.Tags[aiAppVersionConvention])
197+
}
198+
199+
func TestLogRecordToEnvelopeDeviceTags(t *testing.T) {
200+
const aiDeviceModelConvention = "ai.device.model"
201+
const aiDeviceTypeConvention = "ai.device.type"
202+
const aiDeviceOSConvention = "ai.device.osVersion"
203+
204+
resource, scope, logRecord := getTestLogRecord(1)
205+
logPacker := getLogPacker()
206+
207+
envelope := logPacker.LogRecordToEnvelope(logRecord, resource, scope)
208+
209+
resourceAttributes := resource.Attributes().AsRaw()
210+
expectedDeviceModel := resourceAttributes[string(conventions.DeviceManufacturerKey)].(string)
211+
require.Equal(t, expectedDeviceModel, envelope.Tags[aiDeviceModelConvention])
212+
expectedDeviceType := resourceAttributes[string(conventions.DeviceModelIdentifierKey)].(string)
213+
require.Equal(t, expectedDeviceType, envelope.Tags[aiDeviceTypeConvention])
214+
expectedOSVersion := resourceAttributes[string(conventions.OSNameKey)].(string) + " " + resourceAttributes[string(conventions.OSVersionKey)].(string)
215+
require.Equal(t, expectedOSVersion, envelope.Tags[aiDeviceOSConvention])
216+
}
217+
186218
func getLogsExporter(config *Config, transportChannel appinsights.TelemetryChannel) *azureMonitorExporter {
187219
return &azureMonitorExporter{
188220
config,
@@ -206,6 +238,11 @@ func getTestLogs() plog.Logs {
206238
resource.Attributes().PutStr(string(conventions.ServiceNameKey), defaultServiceName)
207239
resource.Attributes().PutStr(string(conventions.ServiceNamespaceKey), defaultServiceNamespace)
208240
resource.Attributes().PutStr(string(conventions.ServiceInstanceIDKey), defaultServiceInstance)
241+
resource.Attributes().PutStr(string(conventions.ServiceVersionKey), defaultServiceVersion)
242+
resource.Attributes().PutStr(string(conventions.OSNameKey), defaultOSName)
243+
resource.Attributes().PutStr(string(conventions.OSVersionKey), defaultOSVersion)
244+
resource.Attributes().PutStr(string(conventions.DeviceManufacturerKey), defaultDeviceManufacturer)
245+
resource.Attributes().PutStr(string(conventions.DeviceModelIdentifierKey), defaultDeviceModelIdentifier)
209246

210247
// add the scope
211248
scopeLogs := resourceLogs.ScopeLogs().AppendEmpty()

exporter/azuremonitorexporter/metric_to_envelopes.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ func (packer *metricPacker) MetricToEnvelopes(metric pmetric.Metric, resource pc
5454
applyResourcesToDataProperties(metricData.Properties, resourceAttributes)
5555
applyInstrumentationScopeValueToDataProperties(metricData.Properties, instrumentationScope)
5656
applyCloudTagsToEnvelope(envelope, resourceAttributes)
57+
applyApplicationTagsToEnvelope(envelope, resourceAttributes)
58+
applyDeviceTagsToEnvelope(envelope, resourceAttributes)
5759
applyInternalSdkVersionTagToEnvelope(envelope)
5860

5961
setAttributesAsProperties(timedDataPoint.attributes, metricData.Properties)

exporter/azuremonitorexporter/trace_to_envelope.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ func spanToEnvelopes(
122122
applyResourcesToDataProperties(dataProperties, resourceAttributes)
123123
applyInstrumentationScopeValueToDataProperties(dataProperties, instrumentationScope)
124124
applyCloudTagsToEnvelope(envelope, resourceAttributes)
125+
applyApplicationTagsToEnvelope(envelope, resourceAttributes)
126+
applyDeviceTagsToEnvelope(envelope, resourceAttributes)
125127
applyInternalSdkVersionTagToEnvelope(envelope)
126128
applyLinksToDataProperties(dataProperties, span.Links(), logger)
127129

@@ -169,7 +171,9 @@ func spanToEnvelopes(
169171
applyResourcesToDataProperties(dataProperties, resourceAttributes)
170172
applyInstrumentationScopeValueToDataProperties(dataProperties, instrumentationScope)
171173
applyCloudTagsToEnvelope(spanEventEnvelope, resourceAttributes)
172-
applyInternalSdkVersionTagToEnvelope(envelope)
174+
applyApplicationTagsToEnvelope(spanEventEnvelope, resourceAttributes)
175+
applyDeviceTagsToEnvelope(spanEventEnvelope, resourceAttributes)
176+
applyInternalSdkVersionTagToEnvelope(spanEventEnvelope)
173177

174178
// Sanitize the base data, the envelope and envelope tags
175179
sanitize(dataSanitizeFunc, logger)

exporter/azuremonitorexporter/trace_to_envelope_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ const (
3131
defaultServiceName = "foo"
3232
defaultServiceNamespace = "ns1"
3333
defaultServiceInstance = "112345"
34+
defaultServiceVersion = "1.0"
35+
defaultOSName = "Linux"
36+
defaultOSVersion = "1.0"
37+
defaultDeviceManufacturer = "Initech"
38+
defaultDeviceModelIdentifier = "Machine"
3439
defaultScopeName = "myinstrumentationlib"
3540
defaultScopeVersion = "1.0"
3641
defaultHTTPMethod = http.MethodGet
@@ -536,6 +541,11 @@ func TestSpanWithEventsToEnvelopes(t *testing.T) {
536541
assert.Equal(t, defaultSpanIDAsHex, envelope.Tags[contracts.OperationParentId])
537542
assert.Equal(t, defaultServiceNamespace+"."+defaultServiceName, envelope.Tags[contracts.CloudRole])
538543
assert.Equal(t, defaultServiceInstance, envelope.Tags[contracts.CloudRoleInstance])
544+
assert.Equal(t, defaultServiceVersion, envelope.Tags[contracts.ApplicationVersion])
545+
assert.Equal(t, defaultDeviceManufacturer, envelope.Tags[contracts.DeviceModel])
546+
assert.Equal(t, defaultDeviceModelIdentifier, envelope.Tags[contracts.DeviceType])
547+
assert.Equal(t, defaultOSName+" "+defaultOSVersion, envelope.Tags[contracts.DeviceOSVersion])
548+
assert.Contains(t, envelope.Tags[contracts.InternalSdkVersion], "otelc-")
539549
assert.NotNil(t, envelope.Data)
540550
}
541551

@@ -636,6 +646,10 @@ func commonEnvelopeValidations(
636646
assert.Equal(t, defaultParentSpanIDAsHex, envelope.Tags[contracts.OperationParentId])
637647
assert.Equal(t, defaultServiceNamespace+"."+defaultServiceName, envelope.Tags[contracts.CloudRole])
638648
assert.Equal(t, defaultServiceInstance, envelope.Tags[contracts.CloudRoleInstance])
649+
assert.Equal(t, defaultServiceVersion, envelope.Tags[contracts.ApplicationVersion])
650+
assert.Equal(t, defaultDeviceManufacturer, envelope.Tags[contracts.DeviceModel])
651+
assert.Equal(t, defaultDeviceModelIdentifier, envelope.Tags[contracts.DeviceType])
652+
assert.Equal(t, defaultOSName+" "+defaultOSVersion, envelope.Tags[contracts.DeviceOSVersion])
639653
assert.Contains(t, envelope.Tags[contracts.InternalSdkVersion], "otelc-")
640654
assert.NotNil(t, envelope.Data)
641655

@@ -906,6 +920,11 @@ func getResource() pcommon.Resource {
906920
r.Attributes().PutStr(string(conventions.ServiceNameKey), defaultServiceName)
907921
r.Attributes().PutStr(string(conventions.ServiceNamespaceKey), defaultServiceNamespace)
908922
r.Attributes().PutStr(string(conventions.ServiceInstanceIDKey), defaultServiceInstance)
923+
r.Attributes().PutStr(string(conventions.ServiceVersionKey), defaultServiceVersion)
924+
r.Attributes().PutStr(string(conventions.DeviceManufacturerKey), defaultDeviceManufacturer)
925+
r.Attributes().PutStr(string(conventions.DeviceModelIdentifierKey), defaultDeviceModelIdentifier)
926+
r.Attributes().PutStr(string(conventions.OSNameKey), defaultOSName)
927+
r.Attributes().PutStr(string(conventions.OSVersionKey), defaultOSVersion)
909928
return r
910929
}
911930

0 commit comments

Comments
 (0)