Skip to content

Commit

Permalink
Optimize attribute mapping (#2795)
Browse files Browse the repository at this point in the history
  • Loading branch information
trask authored Dec 13, 2022
1 parent 3aa7d31 commit 8535a6a
Show file tree
Hide file tree
Showing 7 changed files with 386 additions and 276 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import com.microsoft.applicationinsights.agent.internal.configuration.Configuration;
import com.microsoft.applicationinsights.agent.internal.legacyheaders.DelegatingPropagatorProvider;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -95,16 +94,6 @@ public Map<String, String> apply(ConfigProperties otelConfig) {
if (tracesExporter == null) {
// this overrides the default "otlp" so the exporter can be configured later
properties.put("otel.traces.exporter", "none");

// TODO (trask) this can go away once new indexer is rolled out to gov clouds
List<String> httpClientResponseHeaders = new ArrayList<>();
httpClientResponseHeaders.add("request-context");
httpClientResponseHeaders.addAll(
configuration.preview.captureHttpClientHeaders.responseHeaders);
setHttpHeaderConfiguration(
properties,
"otel.instrumentation.http.capture-headers.client.response",
httpClientResponseHeaders);
}

String metricsExporter = otelConfig.getString("otel.metrics.exporter");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import static io.opentelemetry.api.common.AttributeKey.stringKey;

import io.opentelemetry.api.common.AttributeKey;
import java.util.List;

public final class AiSemanticAttributes {

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

// TODO (trask) this can go away once new indexer is rolled out to gov clouds
public static final AttributeKey<List<String>> REQUEST_CONTEXT =
AttributeKey.stringArrayKey("http.response.header.request_context");

public static final AttributeKey<String> LEGACY_PARENT_ID =
AttributeKey.stringKey("applicationinsights.internal.legacy_parent_id");
public static final AttributeKey<String> LEGACY_ROOT_ID =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

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

import static io.opentelemetry.api.common.AttributeKey.stringKey;

import com.azure.core.util.logging.ClientLogger;
import com.azure.monitor.opentelemetry.exporter.implementation.builders.AbstractTelemetryBuilder;
import com.azure.monitor.opentelemetry.exporter.implementation.builders.ExceptionTelemetryBuilder;
Expand All @@ -25,16 +27,59 @@ public class LogDataMapper {

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

private static final String LOG4J_MDC_PREFIX = "log4j.mdc."; // log4j 1.2
private static final String LOG4J_CONTEXT_DATA_PREFIX = "log4j.context_data."; // log4j 2.x
private static final String LOGBACK_MDC_PREFIX = "logback.mdc.";
private static final String JBOSS_LOGGING_MDC_PREFIX = "jboss-logmanager.mdc.";

private static final AttributeKey<String> LOG4J_MARKER = stringKey("log4j.marker");
private static final AttributeKey<String> LOGBACK_MARKER = stringKey("logback.marker");

private static final Mappings MAPPINGS;

static {
MappingsBuilder mappingsBuilder =
new MappingsBuilder()
.prefix(
LOG4J_MDC_PREFIX,
(telemetryBuilder, key, value) -> {
telemetryBuilder.addProperty(
key.substring(LOG4J_MDC_PREFIX.length()), String.valueOf(value));
})
.prefix(
LOG4J_CONTEXT_DATA_PREFIX,
(telemetryBuilder, key, value) -> {
telemetryBuilder.addProperty(
key.substring(LOG4J_CONTEXT_DATA_PREFIX.length()), String.valueOf(value));
})
.prefix(
LOGBACK_MDC_PREFIX,
(telemetryBuilder, key, value) -> {
telemetryBuilder.addProperty(
key.substring(LOGBACK_MDC_PREFIX.length()), String.valueOf(value));
})
.prefix(
JBOSS_LOGGING_MDC_PREFIX,
(telemetryBuilder, key, value) -> {
telemetryBuilder.addProperty(
key.substring(JBOSS_LOGGING_MDC_PREFIX.length()), String.valueOf(value));
})
.exactString(SemanticAttributes.CODE_FILEPATH, "FileName")
.exactString(SemanticAttributes.CODE_NAMESPACE, "ClassName")
.exactString(SemanticAttributes.CODE_FUNCTION, "MethodName")
.exactLong(SemanticAttributes.CODE_LINENO, "LineNumber")
.exactString(LOG4J_MARKER, "Marker")
.exactString(LOGBACK_MARKER, "Marker");

SpanDataMapper.applyCommonTags(mappingsBuilder);

MAPPINGS = mappingsBuilder.build();
}

private final boolean captureLoggingLevelAsCustomDimension;
private final boolean captureAzureFunctionsAttributes;
private final BiConsumer<AbstractTelemetryBuilder, Resource> telemetryInitializer;

private static final AttributeKey<String> OTEL_LOG4J_MARKER =
AttributeKey.stringKey("log4j.marker");

private static final AttributeKey<String> OTEL_LOGBACK_MARKER =
AttributeKey.stringKey("logback.marker");

public LogDataMapper(
boolean captureLoggingLevelAsCustomDimension,
boolean captureAzureFunctionsAttributes,
Expand Down Expand Up @@ -64,7 +109,10 @@ private TelemetryItem createMessageTelemetryItem(LogRecordData log, @Nullable Lo

// update tags
Attributes attributes = log.getAttributes();
setExtraAttributes(telemetryBuilder, attributes);
if (captureAzureFunctionsAttributes) {
setFunctionExtraTraceAttributes(telemetryBuilder, attributes);
}
MAPPINGS.map(attributes, telemetryBuilder);

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

// update tags
Attributes attributes = log.getAttributes();
setExtraAttributes(telemetryBuilder, attributes);
MAPPINGS.map(attributes, telemetryBuilder);

telemetryBuilder.setExceptions(Exceptions.minimalParse(stack));
telemetryBuilder.setSeverityLevel(toSeverityLevel(log.getSeverity()));
Expand Down Expand Up @@ -143,79 +191,7 @@ private static void setItemCount(
}
}

private static final String LOG4J1_2_MDC_PREFIX = "log4j.mdc.";
private static final String LOG4J2_CONTEXT_DATA_PREFIX = "log4j.context_data.";
private static final String LOGBACK_MDC_PREFIX = "logback.mdc.";
private static final String JBOSS_LOGGING_MDC_PREFIX = "jboss-logmanager.mdc.";

private void setExtraAttributes(
AbstractTelemetryBuilder telemetryBuilder, Attributes attributes) {
if (captureAzureFunctionsAttributes) {
setFunctionExtraAttributes(telemetryBuilder, attributes);
}
attributes.forEach(
(attributeKey, value) -> {
String key = attributeKey.getKey();
if (key.startsWith(LOG4J2_CONTEXT_DATA_PREFIX)) {
telemetryBuilder.addProperty(
key.substring(LOG4J2_CONTEXT_DATA_PREFIX.length()), String.valueOf(value));
return;
}
if (key.startsWith(LOGBACK_MDC_PREFIX)) {
telemetryBuilder.addProperty(
key.substring(LOGBACK_MDC_PREFIX.length()), String.valueOf(value));
return;
}
if (SemanticAttributes.CODE_FILEPATH.getKey().equals(key)) {
telemetryBuilder.addProperty("FileName", String.valueOf(value));
return;
}
if (SemanticAttributes.CODE_NAMESPACE.getKey().equals(key)) {
telemetryBuilder.addProperty("ClassName", String.valueOf(value));
return;
}
if (SemanticAttributes.CODE_FUNCTION.getKey().equals(key)) {
telemetryBuilder.addProperty("MethodName", String.valueOf(value));
return;
}
if (SemanticAttributes.CODE_LINENO.getKey().equals(key)) {
telemetryBuilder.addProperty("LineNumber", String.valueOf(value));
return;
}
if (OTEL_LOG4J_MARKER.getKey().equals(key) || OTEL_LOGBACK_MARKER.getKey().equals(key)) {
telemetryBuilder.addProperty("Marker", String.valueOf(value));
return;
}
if (key.startsWith(JBOSS_LOGGING_MDC_PREFIX)) {
telemetryBuilder.addProperty(
key.substring(JBOSS_LOGGING_MDC_PREFIX.length()), String.valueOf(value));
return;
}
if (key.startsWith(LOG4J1_2_MDC_PREFIX)) {
telemetryBuilder.addProperty(
key.substring(LOG4J1_2_MDC_PREFIX.length()), String.valueOf(value));
return;
}
if (SpanDataMapper.applyCommonTags(telemetryBuilder, key, value)) {
return;
}
if (key.startsWith("applicationinsights.internal.")) {
return;
}
if (key.startsWith("thread.")) {
return;
}
if (key.startsWith("exception.")) {
return;
}
String val = SpanDataMapper.convertToString(value, attributeKey.getType());
if (val != null) {
telemetryBuilder.addProperty(attributeKey.getKey(), val);
}
});
}

private static void setFunctionExtraAttributes(
private static void setFunctionExtraTraceAttributes(
AbstractTelemetryBuilder telemetryBuilder, Attributes attributes) {
String invocationId = attributes.get(AiSemanticAttributes.AZ_FN_INVOCATION_ID);
if (invocationId != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

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

import com.azure.core.util.logging.ClientLogger;
import com.azure.monitor.opentelemetry.exporter.implementation.builders.AbstractTelemetryBuilder;
import com.azure.monitor.opentelemetry.exporter.implementation.utils.Trie;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.AttributeType;
import io.opentelemetry.api.common.Attributes;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import reactor.util.annotation.Nullable;

class Mappings {

private static final ClientLogger logger = new ClientLogger(Mappings.class);
private static final Set<AttributeType> unexpectedTypesLogged = ConcurrentHashMap.newKeySet();

private final Map<String, MappingsBuilder.ExactMapping> exactMappings;
private final Trie<MappingsBuilder.PrefixMapping> prefixMappings;

Mappings(
Map<String, MappingsBuilder.ExactMapping> exactMappings,
Trie<MappingsBuilder.PrefixMapping> prefixMappings) {
this.exactMappings = exactMappings;
this.prefixMappings = prefixMappings;
}

void map(Attributes attributes, AbstractTelemetryBuilder telemetryBuilder) {
attributes.forEach(
(attributeKey, value) -> {
map(telemetryBuilder, attributeKey, value);
});
}

private void map(
AbstractTelemetryBuilder telemetryBuilder, AttributeKey attributeKey, Object value) {
String key = attributeKey.getKey();
MappingsBuilder.ExactMapping exactMapping = exactMappings.get(key);
if (exactMapping != null) {
exactMapping.map(telemetryBuilder, value);
return;
}
MappingsBuilder.PrefixMapping prefixMapping = prefixMappings.getOrNull(key);
if (prefixMapping != null) {
prefixMapping.map(telemetryBuilder, key, value);
return;
}
String val = convertToString(value, attributeKey.getType());
if (val != null) {
telemetryBuilder.addProperty(attributeKey.getKey(), val);
}
}

@Nullable
private static String convertToString(Object value, AttributeType type) {
switch (type) {
case STRING:
case BOOLEAN:
case LONG:
case DOUBLE:
return String.valueOf(value);
case STRING_ARRAY:
case BOOLEAN_ARRAY:
case LONG_ARRAY:
case DOUBLE_ARRAY:
return join((List<?>) value);
}
if (unexpectedTypesLogged.add(type)) {
logger.warning("unexpected attribute type: {}", type);
}
return null;
}

static <T> String join(List<T> values) {
StringBuilder sb = new StringBuilder();
for (Object val : values) {
if (sb.length() > 0) {
sb.append(", ");
}
sb.append(val);
}
return sb.toString();
}
}
Loading

0 comments on commit 8535a6a

Please sign in to comment.