From 050be09bfffbe9e1931382f10fbf5a53ea3dc127 Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Wed, 14 Aug 2024 13:19:52 -0700 Subject: [PATCH] Better populate exception type name and message from span events (#41397) --- .../implementation/LogDataMapper.java | 12 +-- .../implementation/SpanDataMapper.java | 19 +++- .../implementation/builders/Exceptions.java | 45 --------- .../implementation/utils/ExceptionsTest.java | 96 ------------------- 4 files changed, 18 insertions(+), 154 deletions(-) delete mode 100644 sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/Exceptions.java delete mode 100644 sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/ExceptionsTest.java diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/LogDataMapper.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/LogDataMapper.java index 2b19159c68eca..7166b6d1943ad 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/LogDataMapper.java +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/LogDataMapper.java @@ -127,17 +127,7 @@ private TelemetryItem createExceptionTelemetryItem(LogRecordData log, String sta Attributes attributes = log.getAttributes(); MAPPINGS.map(attributes, telemetryBuilder); - List builders = Exceptions.minimalParse(stack); - ExceptionDetailBuilder exceptionDetailBuilder = builders.get(0); - String type = log.getAttributes().get(SemanticAttributes.EXCEPTION_TYPE); - if (type != null && !type.isEmpty()) { - exceptionDetailBuilder.setTypeName(type); - } - String message = log.getAttributes().get(SemanticAttributes.EXCEPTION_MESSAGE); - if (message != null && !message.isEmpty()) { - exceptionDetailBuilder.setMessage(message); - } - telemetryBuilder.setExceptions(builders); + SpanDataMapper.setExceptions(stack, log.getAttributes(), telemetryBuilder); telemetryBuilder.setSeverityLevel(toSeverityLevel(log.getSeverity())); // set exception-specific properties diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/SpanDataMapper.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/SpanDataMapper.java index f133de713396f..85902adc46aa5 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/SpanDataMapper.java +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/SpanDataMapper.java @@ -4,8 +4,8 @@ package com.azure.monitor.opentelemetry.exporter.implementation; import com.azure.monitor.opentelemetry.exporter.implementation.builders.AbstractTelemetryBuilder; +import com.azure.monitor.opentelemetry.exporter.implementation.builders.ExceptionDetailBuilder; import com.azure.monitor.opentelemetry.exporter.implementation.builders.ExceptionTelemetryBuilder; -import com.azure.monitor.opentelemetry.exporter.implementation.builders.Exceptions; import com.azure.monitor.opentelemetry.exporter.implementation.builders.MessageTelemetryBuilder; import com.azure.monitor.opentelemetry.exporter.implementation.builders.RemoteDependencyTelemetryBuilder; import com.azure.monitor.opentelemetry.exporter.implementation.builders.RequestTelemetryBuilder; @@ -36,6 +36,7 @@ import static com.azure.monitor.opentelemetry.exporter.implementation.MappingsBuilder.MappingType.SPAN; import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; import static java.util.concurrent.TimeUnit.NANOSECONDS; import static java.util.concurrent.TimeUnit.SECONDS; @@ -820,11 +821,25 @@ private TelemetryItem createExceptionTelemetryItem(String errorStack, SpanData s MAPPINGS.map(span.getAttributes(), telemetryBuilder); // set exception-specific properties - telemetryBuilder.setExceptions(Exceptions.minimalParse(errorStack)); + setExceptions(errorStack, span.getAttributes(), telemetryBuilder); return telemetryBuilder.build(); } + static void setExceptions(String stack, Attributes attributes, ExceptionTelemetryBuilder telemetryBuilder) { + ExceptionDetailBuilder builder = new ExceptionDetailBuilder(); + String type = attributes.get(SemanticAttributes.EXCEPTION_TYPE); + if (type != null && !type.isEmpty()) { + builder.setTypeName(type); + } + String message = attributes.get(SemanticAttributes.EXCEPTION_MESSAGE); + if (message != null && !message.isEmpty()) { + builder.setMessage(message); + } + builder.setStack(stack); + telemetryBuilder.setExceptions(singletonList(builder)); + } + public static T getStableOrOldAttribute(Attributes attributes, AttributeKey stable, AttributeKey old) { T value = attributes.get(stable); if (value != null) { diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/Exceptions.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/Exceptions.java deleted file mode 100644 index 3e2d4ab9eea07..0000000000000 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/Exceptions.java +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.monitor.opentelemetry.exporter.implementation.builders; - -import java.util.List; - -import static java.util.Collections.singletonList; - -public final class Exceptions { - - public static List minimalParse(String str) { - ExceptionDetailBuilder builder = new ExceptionDetailBuilder(); - int separator = -1; - int length = str.length(); - int current; - for (current = 0; current < length; current++) { - char c = str.charAt(current); - if (c == ':' && separator == -1) { - separator = current; - } else if (c == '\r' || c == '\n') { - break; - } - } - // at the end of the loop, current will be end of the first line - if (separator != -1) { - String typeName = str.substring(0, separator); - String message = str.substring(separator + 1, current).trim(); - if (message.isEmpty()) { - message = typeName; - } - builder.setTypeName(typeName); - builder.setMessage(message); - } else { - String typeName = str.substring(0, current); - builder.setTypeName(typeName); - builder.setMessage(typeName); - } - builder.setStack(str); - return singletonList(builder); - } - - private Exceptions() { - } -} diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/ExceptionsTest.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/ExceptionsTest.java deleted file mode 100644 index 5c253bf7892f8..0000000000000 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/ExceptionsTest.java +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.monitor.opentelemetry.exporter.implementation.utils; - -import com.azure.monitor.opentelemetry.exporter.implementation.builders.ExceptionDetailBuilder; -import com.azure.monitor.opentelemetry.exporter.implementation.builders.Exceptions; -import com.azure.monitor.opentelemetry.exporter.implementation.models.TelemetryExceptionDetails; -import org.junit.jupiter.api.Test; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -public class ExceptionsTest { - - @Test - public void testMinimalParse() { - // given - String str = toString(new IllegalStateException("test")); - - // when - List list = Exceptions.minimalParse(str); - - // then - assertThat(list.size()).isEqualTo(1); - - TelemetryExceptionDetails details = list.get(0).build(); - assertThat(details.getTypeName()).isEqualTo(IllegalStateException.class.getName()); - assertThat(details.getMessage()).isEqualTo("test"); - } - - @Test - public void testMinimalParseWithColonInMessage() { - // given - String str = toString(new IllegalStateException("hello: world")); - - // when - List list = Exceptions.minimalParse(str); - - // then - assertThat(list.size()).isEqualTo(1); - - TelemetryExceptionDetails details = list.get(0).build(); - assertThat(details.getTypeName()).isEqualTo(IllegalStateException.class.getName()); - assertThat(details.getMessage()).isEqualTo("hello: world"); - } - - @Test - public void testMinimalParseWithNoMessage() { - // given - String str = toString(new IllegalStateException()); - - // when - List list = Exceptions.minimalParse(str); - - // then - assertThat(list.size()).isEqualTo(1); - - TelemetryExceptionDetails details = list.get(0).build(); - assertThat(details.getTypeName()).isEqualTo(IllegalStateException.class.getName()); - assertThat(details.getMessage()).isEqualTo(IllegalStateException.class.getName()); - } - - @Test - public void testMinimalParseWithProblematicMessage() { - // given - String str = toString(new ProblematicException()); - - // when - List list = Exceptions.minimalParse(str); - - // then - assertThat(list.size()).isEqualTo(1); - - TelemetryExceptionDetails details = list.get(0).build(); - assertThat(details.getTypeName()).isEqualTo(ProblematicException.class.getName()); - assertThat(details.getMessage()).isEqualTo(ProblematicException.class.getName()); - } - - private static String toString(Throwable t) { - StringWriter out = new StringWriter(); - t.printStackTrace(new PrintWriter(out)); - return out.toString(); - } - - @SuppressWarnings("OverrideThrowableToString") - private static class ProblematicException extends Exception { - @Override - public String toString() { - return ProblematicException.class.getName() + ":"; - } - } -}