From d5a9dc109e53c47beaa430dfe95ad83c9dcc0d43 Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Thu, 5 Jun 2025 14:58:03 -0500 Subject: [PATCH 1/3] OTLP exporter should tolerate instances of LogRecordData when incubator is present --- .../exporter/internal/otlp/IncubatingUtil.java | 17 +++++++++++++++++ .../internal/otlp/logs/LogMarshaler.java | 17 ++--------------- .../LogsRequestMarshalerIncubatingTest.java | 16 ++++++++++++++++ 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IncubatingUtil.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IncubatingUtil.java index fb1e350188a..90660fd5a85 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IncubatingUtil.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IncubatingUtil.java @@ -28,11 +28,28 @@ */ public class IncubatingUtil { + private static final boolean INCUBATOR_AVAILABLE; + + static { + boolean incubatorAvailable = false; + try { + Class.forName("io.opentelemetry.api.incubator.common.ExtendedAttributes"); + incubatorAvailable = true; + } catch (ClassNotFoundException e) { + // Not available + } + INCUBATOR_AVAILABLE = incubatorAvailable; + } + private static final byte[] EMPTY_BYTES = new byte[0]; private static final KeyValueMarshaler[] EMPTY_REPEATED = new KeyValueMarshaler[0]; private IncubatingUtil() {} + public static boolean isExtendedLogRecordData(LogRecordData logRecordData) { + return INCUBATOR_AVAILABLE && logRecordData instanceof ExtendedLogRecordData; + } + @SuppressWarnings("AvoidObjectArrays") public static KeyValueMarshaler[] createdExtendedAttributesMarhsalers( LogRecordData logRecordData) { diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/logs/LogMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/logs/LogMarshaler.java index 713fba7ded0..a53a523c642 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/logs/LogMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/logs/LogMarshaler.java @@ -24,19 +24,6 @@ import javax.annotation.Nullable; final class LogMarshaler extends MarshalerWithSize { - private static final boolean INCUBATOR_AVAILABLE; - - static { - boolean incubatorAvailable = false; - try { - Class.forName("io.opentelemetry.api.incubator.common.ExtendedAttributes"); - incubatorAvailable = true; - } catch (ClassNotFoundException e) { - // Not available - } - INCUBATOR_AVAILABLE = incubatorAvailable; - } - private static final String INVALID_TRACE_ID = TraceId.getInvalid(); private static final String INVALID_SPAN_ID = SpanId.getInvalid(); @@ -54,12 +41,12 @@ final class LogMarshaler extends MarshalerWithSize { static LogMarshaler create(LogRecordData logRecordData) { KeyValueMarshaler[] attributeMarshalers = - INCUBATOR_AVAILABLE + IncubatingUtil.isExtendedLogRecordData(logRecordData) ? IncubatingUtil.createdExtendedAttributesMarhsalers(logRecordData) : KeyValueMarshaler.createForAttributes(logRecordData.getAttributes()); int attributeSize = - INCUBATOR_AVAILABLE + IncubatingUtil.isExtendedLogRecordData(logRecordData) ? IncubatingUtil.extendedAttributesSize(logRecordData) : logRecordData.getAttributes().size(); diff --git a/exporters/otlp/common/src/testIncubating/java/io/opentelemetry/exporter/internal/otlp/logs/LogsRequestMarshalerIncubatingTest.java b/exporters/otlp/common/src/testIncubating/java/io/opentelemetry/exporter/internal/otlp/logs/LogsRequestMarshalerIncubatingTest.java index 8b4533e24ae..60d4c4fe799 100644 --- a/exporters/otlp/common/src/testIncubating/java/io/opentelemetry/exporter/internal/otlp/logs/LogsRequestMarshalerIncubatingTest.java +++ b/exporters/otlp/common/src/testIncubating/java/io/opentelemetry/exporter/internal/otlp/logs/LogsRequestMarshalerIncubatingTest.java @@ -6,6 +6,7 @@ package io.opentelemetry.exporter.internal.otlp.logs; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; @@ -34,6 +35,7 @@ import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.logs.data.LogRecordData; import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.testing.logs.TestLogRecordData; import io.opentelemetry.sdk.testing.logs.internal.TestExtendedLogRecordData; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -56,6 +58,20 @@ class LogsRequestMarshalerIncubatingTest { private static final String EVENT_NAME = "hello"; private static final String BODY = "Hello world from this log..."; + // Marshalers should not throw if the incubator is on the class path, but are called with + // LogRecordData instances which are not ExtendedLogRecordData. + // See: https://github.com/open-telemetry/opentelemetry-java/issues/7363 + @ParameterizedTest + @EnumSource(MarshalerSource.class) + void toProtoLogRecord_NotExtendedLogRecordData_DoesNotThrow(MarshalerSource marshalerSource) { + assertThatCode( + () -> + parse( + LogRecord.getDefaultInstance(), + marshalerSource.create(TestLogRecordData.builder().build()))) + .doesNotThrowAnyException(); + } + @ParameterizedTest @EnumSource(MarshalerSource.class) void toProtoLogRecord(MarshalerSource marshalerSource) { From f4335a71ca9246f203e9112b89f54083a6a79346 Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Thu, 5 Jun 2025 15:32:52 -0500 Subject: [PATCH 2/3] Apply change to LogStatelessMarshaler --- .../internal/otlp/logs/LogStatelessMarshaler.java | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/logs/LogStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/logs/LogStatelessMarshaler.java index e8b533e170a..7e5202f8893 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/logs/LogStatelessMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/logs/LogStatelessMarshaler.java @@ -27,18 +27,6 @@ final class LogStatelessMarshaler implements StatelessMarshaler { private static final String INVALID_TRACE_ID = TraceId.getInvalid(); private static final String INVALID_SPAN_ID = SpanId.getInvalid(); - private static final boolean INCUBATOR_AVAILABLE; - - static { - boolean incubatorAvailable = false; - try { - Class.forName("io.opentelemetry.api.incubator.common.ExtendedAttributes"); - incubatorAvailable = true; - } catch (ClassNotFoundException e) { - // Not available - } - INCUBATOR_AVAILABLE = incubatorAvailable; - } static final LogStatelessMarshaler INSTANCE = new LogStatelessMarshaler(); @@ -56,7 +44,7 @@ public void writeTo(Serializer output, LogRecordData log, MarshalerContext conte } int droppedAttributesCount; - if (INCUBATOR_AVAILABLE) { + if (IncubatingUtil.isExtendedLogRecordData(log)) { IncubatingUtil.serializeExtendedAttributes(output, log, context); droppedAttributesCount = log.getTotalAttributeCount() - IncubatingUtil.extendedAttributesSize(log); From 8d4fc807127727d50f38367484d211721a6728cf Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Thu, 5 Jun 2025 16:35:17 -0500 Subject: [PATCH 3/3] Fix build? --- .../exporter/internal/otlp/logs/LogStatelessMarshaler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/logs/LogStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/logs/LogStatelessMarshaler.java index 7e5202f8893..505c42cbc47 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/logs/LogStatelessMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/logs/LogStatelessMarshaler.java @@ -87,7 +87,7 @@ public int getBinarySerializedSize(LogRecordData log, MarshalerContext context) StatelessMarshalerUtil.sizeMessageWithContext( LogRecord.BODY, log.getBodyValue(), AnyValueStatelessMarshaler.INSTANCE, context); } - if (INCUBATOR_AVAILABLE) { + if (IncubatingUtil.isExtendedLogRecordData(log)) { size += IncubatingUtil.sizeExtendedAttributes(log, context); int droppedAttributesCount =