Skip to content

Commit 8535a6a

Browse files
authored
Optimize attribute mapping (#2795)
1 parent 3aa7d31 commit 8535a6a

File tree

7 files changed

+386
-276
lines changed

7 files changed

+386
-276
lines changed

agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/AiConfigCustomizer.java

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import com.microsoft.applicationinsights.agent.internal.configuration.Configuration;
99
import com.microsoft.applicationinsights.agent.internal.legacyheaders.DelegatingPropagatorProvider;
1010
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
11-
import java.util.ArrayList;
1211
import java.util.HashMap;
1312
import java.util.List;
1413
import java.util.Map;
@@ -95,16 +94,6 @@ public Map<String, String> apply(ConfigProperties otelConfig) {
9594
if (tracesExporter == null) {
9695
// this overrides the default "otlp" so the exporter can be configured later
9796
properties.put("otel.traces.exporter", "none");
98-
99-
// TODO (trask) this can go away once new indexer is rolled out to gov clouds
100-
List<String> httpClientResponseHeaders = new ArrayList<>();
101-
httpClientResponseHeaders.add("request-context");
102-
httpClientResponseHeaders.addAll(
103-
configuration.preview.captureHttpClientHeaders.responseHeaders);
104-
setHttpHeaderConfiguration(
105-
properties,
106-
"otel.instrumentation.http.capture-headers.client.response",
107-
httpClientResponseHeaders);
10897
}
10998

11099
String metricsExporter = otelConfig.getString("otel.metrics.exporter");

agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/AiSemanticAttributes.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import static io.opentelemetry.api.common.AttributeKey.stringKey;
99

1010
import io.opentelemetry.api.common.AttributeKey;
11-
import java.util.List;
1211

1312
public final class AiSemanticAttributes {
1413

@@ -79,10 +78,6 @@ public final class AiSemanticAttributes {
7978
public static final AttributeKey<Long> NET_SOCK_PEER_PORT =
8079
AttributeKey.longKey("net.sock.peer.port");
8180

82-
// TODO (trask) this can go away once new indexer is rolled out to gov clouds
83-
public static final AttributeKey<List<String>> REQUEST_CONTEXT =
84-
AttributeKey.stringArrayKey("http.response.header.request_context");
85-
8681
public static final AttributeKey<String> LEGACY_PARENT_ID =
8782
AttributeKey.stringKey("applicationinsights.internal.legacy_parent_id");
8883
public static final AttributeKey<String> LEGACY_ROOT_ID =

agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/LogDataMapper.java

Lines changed: 57 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
package com.azure.monitor.opentelemetry.exporter.implementation;
55

6+
import static io.opentelemetry.api.common.AttributeKey.stringKey;
7+
68
import com.azure.core.util.logging.ClientLogger;
79
import com.azure.monitor.opentelemetry.exporter.implementation.builders.AbstractTelemetryBuilder;
810
import com.azure.monitor.opentelemetry.exporter.implementation.builders.ExceptionTelemetryBuilder;
@@ -25,16 +27,59 @@ public class LogDataMapper {
2527

2628
private static final ClientLogger logger = new ClientLogger(LogDataMapper.class);
2729

30+
private static final String LOG4J_MDC_PREFIX = "log4j.mdc."; // log4j 1.2
31+
private static final String LOG4J_CONTEXT_DATA_PREFIX = "log4j.context_data."; // log4j 2.x
32+
private static final String LOGBACK_MDC_PREFIX = "logback.mdc.";
33+
private static final String JBOSS_LOGGING_MDC_PREFIX = "jboss-logmanager.mdc.";
34+
35+
private static final AttributeKey<String> LOG4J_MARKER = stringKey("log4j.marker");
36+
private static final AttributeKey<String> LOGBACK_MARKER = stringKey("logback.marker");
37+
38+
private static final Mappings MAPPINGS;
39+
40+
static {
41+
MappingsBuilder mappingsBuilder =
42+
new MappingsBuilder()
43+
.prefix(
44+
LOG4J_MDC_PREFIX,
45+
(telemetryBuilder, key, value) -> {
46+
telemetryBuilder.addProperty(
47+
key.substring(LOG4J_MDC_PREFIX.length()), String.valueOf(value));
48+
})
49+
.prefix(
50+
LOG4J_CONTEXT_DATA_PREFIX,
51+
(telemetryBuilder, key, value) -> {
52+
telemetryBuilder.addProperty(
53+
key.substring(LOG4J_CONTEXT_DATA_PREFIX.length()), String.valueOf(value));
54+
})
55+
.prefix(
56+
LOGBACK_MDC_PREFIX,
57+
(telemetryBuilder, key, value) -> {
58+
telemetryBuilder.addProperty(
59+
key.substring(LOGBACK_MDC_PREFIX.length()), String.valueOf(value));
60+
})
61+
.prefix(
62+
JBOSS_LOGGING_MDC_PREFIX,
63+
(telemetryBuilder, key, value) -> {
64+
telemetryBuilder.addProperty(
65+
key.substring(JBOSS_LOGGING_MDC_PREFIX.length()), String.valueOf(value));
66+
})
67+
.exactString(SemanticAttributes.CODE_FILEPATH, "FileName")
68+
.exactString(SemanticAttributes.CODE_NAMESPACE, "ClassName")
69+
.exactString(SemanticAttributes.CODE_FUNCTION, "MethodName")
70+
.exactLong(SemanticAttributes.CODE_LINENO, "LineNumber")
71+
.exactString(LOG4J_MARKER, "Marker")
72+
.exactString(LOGBACK_MARKER, "Marker");
73+
74+
SpanDataMapper.applyCommonTags(mappingsBuilder);
75+
76+
MAPPINGS = mappingsBuilder.build();
77+
}
78+
2879
private final boolean captureLoggingLevelAsCustomDimension;
2980
private final boolean captureAzureFunctionsAttributes;
3081
private final BiConsumer<AbstractTelemetryBuilder, Resource> telemetryInitializer;
3182

32-
private static final AttributeKey<String> OTEL_LOG4J_MARKER =
33-
AttributeKey.stringKey("log4j.marker");
34-
35-
private static final AttributeKey<String> OTEL_LOGBACK_MARKER =
36-
AttributeKey.stringKey("logback.marker");
37-
3883
public LogDataMapper(
3984
boolean captureLoggingLevelAsCustomDimension,
4085
boolean captureAzureFunctionsAttributes,
@@ -64,7 +109,10 @@ private TelemetryItem createMessageTelemetryItem(LogRecordData log, @Nullable Lo
64109

65110
// update tags
66111
Attributes attributes = log.getAttributes();
67-
setExtraAttributes(telemetryBuilder, attributes);
112+
if (captureAzureFunctionsAttributes) {
113+
setFunctionExtraTraceAttributes(telemetryBuilder, attributes);
114+
}
115+
MAPPINGS.map(attributes, telemetryBuilder);
68116

69117
telemetryBuilder.setSeverityLevel(toSeverityLevel(log.getSeverity()));
70118
telemetryBuilder.setMessage(log.getBody().asString());
@@ -91,7 +139,7 @@ private TelemetryItem createExceptionTelemetryItem(
91139

92140
// update tags
93141
Attributes attributes = log.getAttributes();
94-
setExtraAttributes(telemetryBuilder, attributes);
142+
MAPPINGS.map(attributes, telemetryBuilder);
95143

96144
telemetryBuilder.setExceptions(Exceptions.minimalParse(stack));
97145
telemetryBuilder.setSeverityLevel(toSeverityLevel(log.getSeverity()));
@@ -143,79 +191,7 @@ private static void setItemCount(
143191
}
144192
}
145193

146-
private static final String LOG4J1_2_MDC_PREFIX = "log4j.mdc.";
147-
private static final String LOG4J2_CONTEXT_DATA_PREFIX = "log4j.context_data.";
148-
private static final String LOGBACK_MDC_PREFIX = "logback.mdc.";
149-
private static final String JBOSS_LOGGING_MDC_PREFIX = "jboss-logmanager.mdc.";
150-
151-
private void setExtraAttributes(
152-
AbstractTelemetryBuilder telemetryBuilder, Attributes attributes) {
153-
if (captureAzureFunctionsAttributes) {
154-
setFunctionExtraAttributes(telemetryBuilder, attributes);
155-
}
156-
attributes.forEach(
157-
(attributeKey, value) -> {
158-
String key = attributeKey.getKey();
159-
if (key.startsWith(LOG4J2_CONTEXT_DATA_PREFIX)) {
160-
telemetryBuilder.addProperty(
161-
key.substring(LOG4J2_CONTEXT_DATA_PREFIX.length()), String.valueOf(value));
162-
return;
163-
}
164-
if (key.startsWith(LOGBACK_MDC_PREFIX)) {
165-
telemetryBuilder.addProperty(
166-
key.substring(LOGBACK_MDC_PREFIX.length()), String.valueOf(value));
167-
return;
168-
}
169-
if (SemanticAttributes.CODE_FILEPATH.getKey().equals(key)) {
170-
telemetryBuilder.addProperty("FileName", String.valueOf(value));
171-
return;
172-
}
173-
if (SemanticAttributes.CODE_NAMESPACE.getKey().equals(key)) {
174-
telemetryBuilder.addProperty("ClassName", String.valueOf(value));
175-
return;
176-
}
177-
if (SemanticAttributes.CODE_FUNCTION.getKey().equals(key)) {
178-
telemetryBuilder.addProperty("MethodName", String.valueOf(value));
179-
return;
180-
}
181-
if (SemanticAttributes.CODE_LINENO.getKey().equals(key)) {
182-
telemetryBuilder.addProperty("LineNumber", String.valueOf(value));
183-
return;
184-
}
185-
if (OTEL_LOG4J_MARKER.getKey().equals(key) || OTEL_LOGBACK_MARKER.getKey().equals(key)) {
186-
telemetryBuilder.addProperty("Marker", String.valueOf(value));
187-
return;
188-
}
189-
if (key.startsWith(JBOSS_LOGGING_MDC_PREFIX)) {
190-
telemetryBuilder.addProperty(
191-
key.substring(JBOSS_LOGGING_MDC_PREFIX.length()), String.valueOf(value));
192-
return;
193-
}
194-
if (key.startsWith(LOG4J1_2_MDC_PREFIX)) {
195-
telemetryBuilder.addProperty(
196-
key.substring(LOG4J1_2_MDC_PREFIX.length()), String.valueOf(value));
197-
return;
198-
}
199-
if (SpanDataMapper.applyCommonTags(telemetryBuilder, key, value)) {
200-
return;
201-
}
202-
if (key.startsWith("applicationinsights.internal.")) {
203-
return;
204-
}
205-
if (key.startsWith("thread.")) {
206-
return;
207-
}
208-
if (key.startsWith("exception.")) {
209-
return;
210-
}
211-
String val = SpanDataMapper.convertToString(value, attributeKey.getType());
212-
if (val != null) {
213-
telemetryBuilder.addProperty(attributeKey.getKey(), val);
214-
}
215-
});
216-
}
217-
218-
private static void setFunctionExtraAttributes(
194+
private static void setFunctionExtraTraceAttributes(
219195
AbstractTelemetryBuilder telemetryBuilder, Attributes attributes) {
220196
String invocationId = attributes.get(AiSemanticAttributes.AZ_FN_INVOCATION_ID);
221197
if (invocationId != null) {
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package com.azure.monitor.opentelemetry.exporter.implementation;
5+
6+
import com.azure.core.util.logging.ClientLogger;
7+
import com.azure.monitor.opentelemetry.exporter.implementation.builders.AbstractTelemetryBuilder;
8+
import com.azure.monitor.opentelemetry.exporter.implementation.utils.Trie;
9+
import io.opentelemetry.api.common.AttributeKey;
10+
import io.opentelemetry.api.common.AttributeType;
11+
import io.opentelemetry.api.common.Attributes;
12+
import java.util.List;
13+
import java.util.Map;
14+
import java.util.Set;
15+
import java.util.concurrent.ConcurrentHashMap;
16+
import reactor.util.annotation.Nullable;
17+
18+
class Mappings {
19+
20+
private static final ClientLogger logger = new ClientLogger(Mappings.class);
21+
private static final Set<AttributeType> unexpectedTypesLogged = ConcurrentHashMap.newKeySet();
22+
23+
private final Map<String, MappingsBuilder.ExactMapping> exactMappings;
24+
private final Trie<MappingsBuilder.PrefixMapping> prefixMappings;
25+
26+
Mappings(
27+
Map<String, MappingsBuilder.ExactMapping> exactMappings,
28+
Trie<MappingsBuilder.PrefixMapping> prefixMappings) {
29+
this.exactMappings = exactMappings;
30+
this.prefixMappings = prefixMappings;
31+
}
32+
33+
void map(Attributes attributes, AbstractTelemetryBuilder telemetryBuilder) {
34+
attributes.forEach(
35+
(attributeKey, value) -> {
36+
map(telemetryBuilder, attributeKey, value);
37+
});
38+
}
39+
40+
private void map(
41+
AbstractTelemetryBuilder telemetryBuilder, AttributeKey attributeKey, Object value) {
42+
String key = attributeKey.getKey();
43+
MappingsBuilder.ExactMapping exactMapping = exactMappings.get(key);
44+
if (exactMapping != null) {
45+
exactMapping.map(telemetryBuilder, value);
46+
return;
47+
}
48+
MappingsBuilder.PrefixMapping prefixMapping = prefixMappings.getOrNull(key);
49+
if (prefixMapping != null) {
50+
prefixMapping.map(telemetryBuilder, key, value);
51+
return;
52+
}
53+
String val = convertToString(value, attributeKey.getType());
54+
if (val != null) {
55+
telemetryBuilder.addProperty(attributeKey.getKey(), val);
56+
}
57+
}
58+
59+
@Nullable
60+
private static String convertToString(Object value, AttributeType type) {
61+
switch (type) {
62+
case STRING:
63+
case BOOLEAN:
64+
case LONG:
65+
case DOUBLE:
66+
return String.valueOf(value);
67+
case STRING_ARRAY:
68+
case BOOLEAN_ARRAY:
69+
case LONG_ARRAY:
70+
case DOUBLE_ARRAY:
71+
return join((List<?>) value);
72+
}
73+
if (unexpectedTypesLogged.add(type)) {
74+
logger.warning("unexpected attribute type: {}", type);
75+
}
76+
return null;
77+
}
78+
79+
static <T> String join(List<T> values) {
80+
StringBuilder sb = new StringBuilder();
81+
for (Object val : values) {
82+
if (sb.length() > 0) {
83+
sb.append(", ");
84+
}
85+
sb.append(val);
86+
}
87+
return sb.toString();
88+
}
89+
}

0 commit comments

Comments
 (0)