diff --git a/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/logs/OtlpStdoutLogRecordExporter.java b/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/logs/OtlpStdoutLogRecordExporter.java index 96331e56d23..11798e938f0 100644 --- a/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/logs/OtlpStdoutLogRecordExporter.java +++ b/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/logs/OtlpStdoutLogRecordExporter.java @@ -5,15 +5,17 @@ package io.opentelemetry.exporter.logging.otlp.internal.logs; -import io.opentelemetry.exporter.internal.otlp.logs.LogsRequestMarshaler; +import io.opentelemetry.exporter.internal.otlp.logs.LogReusableDataMarshaler; import io.opentelemetry.exporter.internal.otlp.logs.ResourceLogsMarshaler; import io.opentelemetry.exporter.logging.otlp.internal.writer.JsonWriter; import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.common.export.MemoryMode; import io.opentelemetry.sdk.logs.data.LogRecordData; import io.opentelemetry.sdk.logs.export.LogRecordExporter; import java.util.Collection; import java.util.StringJoiner; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function; import java.util.logging.Level; import java.util.logging.Logger; @@ -33,11 +35,16 @@ public final class OtlpStdoutLogRecordExporter implements LogRecordExporter { private final Logger logger; private final JsonWriter jsonWriter; private final boolean wrapperJsonObject; + private final MemoryMode memoryMode; + private final Function, CompletableResultCode> marshaler; - OtlpStdoutLogRecordExporter(Logger logger, JsonWriter jsonWriter, boolean wrapperJsonObject) { + OtlpStdoutLogRecordExporter( + Logger logger, JsonWriter jsonWriter, boolean wrapperJsonObject, MemoryMode memoryMode) { this.logger = logger; this.jsonWriter = jsonWriter; this.wrapperJsonObject = wrapperJsonObject; + this.memoryMode = memoryMode; + marshaler = createMarshaler(jsonWriter, memoryMode, wrapperJsonObject); } /** Returns a new {@link OtlpStdoutLogRecordExporterBuilder}. */ @@ -46,25 +53,35 @@ public static OtlpStdoutLogRecordExporterBuilder builder() { return new OtlpStdoutLogRecordExporterBuilder(LOGGER).setOutput(System.out); } + private static Function, CompletableResultCode> createMarshaler( + JsonWriter jsonWriter, MemoryMode memoryMode, boolean wrapperJsonObject) { + if (wrapperJsonObject) { + LogReusableDataMarshaler reusableDataMarshaler = + new LogReusableDataMarshaler( + memoryMode, (marshaler, numItems) -> jsonWriter.write(marshaler)); + return reusableDataMarshaler::export; + } else { + return logs -> { + // no support for low allocation marshaler + for (ResourceLogsMarshaler marshaler : ResourceLogsMarshaler.create(logs)) { + CompletableResultCode resultCode = jsonWriter.write(marshaler); + if (!resultCode.isSuccess()) { + // already logged + return resultCode; + } + } + return CompletableResultCode.ofSuccess(); + }; + } + } + @Override public CompletableResultCode export(Collection logs) { if (isShutdown.get()) { return CompletableResultCode.ofFailure(); } - if (wrapperJsonObject) { - LogsRequestMarshaler request = LogsRequestMarshaler.create(logs); - return jsonWriter.write(request); - } else { - for (ResourceLogsMarshaler resourceLogs : ResourceLogsMarshaler.create(logs)) { - CompletableResultCode resultCode = jsonWriter.write(resourceLogs); - if (!resultCode.isSuccess()) { - // already logged - return resultCode; - } - } - return CompletableResultCode.ofSuccess(); - } + return marshaler.apply(logs); } @Override @@ -87,6 +104,7 @@ public String toString() { StringJoiner joiner = new StringJoiner(", ", "OtlpStdoutLogRecordExporter{", "}"); joiner.add("jsonWriter=" + jsonWriter); joiner.add("wrapperJsonObject=" + wrapperJsonObject); + joiner.add("memoryMode=" + memoryMode); return joiner.toString(); } } diff --git a/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/logs/OtlpStdoutLogRecordExporterBuilder.java b/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/logs/OtlpStdoutLogRecordExporterBuilder.java index ea3f5c14234..76e6adb20ad 100644 --- a/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/logs/OtlpStdoutLogRecordExporterBuilder.java +++ b/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/logs/OtlpStdoutLogRecordExporterBuilder.java @@ -11,6 +11,7 @@ import io.opentelemetry.exporter.logging.otlp.internal.writer.JsonWriter; import io.opentelemetry.exporter.logging.otlp.internal.writer.LoggerJsonWriter; import io.opentelemetry.exporter.logging.otlp.internal.writer.StreamJsonWriter; +import io.opentelemetry.sdk.common.export.MemoryMode; import java.io.OutputStream; import java.util.logging.Logger; @@ -27,6 +28,7 @@ public final class OtlpStdoutLogRecordExporterBuilder { private final Logger logger; private JsonWriter jsonWriter; private boolean wrapperJsonObject = true; + private MemoryMode memoryMode = MemoryMode.IMMUTABLE_DATA; public OtlpStdoutLogRecordExporterBuilder(Logger logger) { this.logger = logger; @@ -44,6 +46,17 @@ public OtlpStdoutLogRecordExporterBuilder setWrapperJsonObject(boolean wrapperJs return this; } + /** + * Set the {@link MemoryMode}. If unset, defaults to {@link MemoryMode#IMMUTABLE_DATA}. + * + *

When memory mode is {@link MemoryMode#REUSABLE_DATA}, serialization is optimized to reduce + * memory allocation. + */ + public OtlpStdoutLogRecordExporterBuilder setMemoryMode(MemoryMode memoryMode) { + this.memoryMode = memoryMode; + return this; + } + /** * Sets the exporter to use the specified output stream. * @@ -71,6 +84,10 @@ public OtlpStdoutLogRecordExporterBuilder setOutput(Logger logger) { * @return a new exporter's instance */ public OtlpStdoutLogRecordExporter build() { - return new OtlpStdoutLogRecordExporter(logger, jsonWriter, wrapperJsonObject); + if (memoryMode == MemoryMode.REUSABLE_DATA && !wrapperJsonObject) { + throw new IllegalArgumentException( + "Reusable data mode is not supported without wrapperJsonObject"); + } + return new OtlpStdoutLogRecordExporter(logger, jsonWriter, wrapperJsonObject, memoryMode); } } diff --git a/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/logs/OtlpStdoutLogRecordExporterComponentProvider.java b/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/logs/OtlpStdoutLogRecordExporterComponentProvider.java index 0806b7f0b40..8afd4e58c85 100644 --- a/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/logs/OtlpStdoutLogRecordExporterComponentProvider.java +++ b/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/logs/OtlpStdoutLogRecordExporterComponentProvider.java @@ -5,6 +5,7 @@ package io.opentelemetry.exporter.logging.otlp.internal.logs; +import io.opentelemetry.exporter.internal.ExporterBuilderUtil; import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties; import io.opentelemetry.sdk.logs.export.LogRecordExporter; @@ -31,6 +32,7 @@ public String getName() { @Override public LogRecordExporter create(StructuredConfigProperties config) { OtlpStdoutLogRecordExporterBuilder builder = OtlpStdoutLogRecordExporter.builder(); + ExporterBuilderUtil.configureExporterMemoryMode(config, builder::setMemoryMode); return builder.build(); } } diff --git a/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/logs/OtlpStdoutLogRecordExporterProvider.java b/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/logs/OtlpStdoutLogRecordExporterProvider.java index 23ba0079295..08b8021590d 100644 --- a/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/logs/OtlpStdoutLogRecordExporterProvider.java +++ b/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/logs/OtlpStdoutLogRecordExporterProvider.java @@ -5,6 +5,7 @@ package io.opentelemetry.exporter.logging.otlp.internal.logs; +import io.opentelemetry.exporter.internal.ExporterBuilderUtil; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.logs.ConfigurableLogRecordExporterProvider; import io.opentelemetry.sdk.logs.export.LogRecordExporter; @@ -20,6 +21,7 @@ public final class OtlpStdoutLogRecordExporterProvider @Override public LogRecordExporter createExporter(ConfigProperties config) { OtlpStdoutLogRecordExporterBuilder builder = OtlpStdoutLogRecordExporter.builder(); + ExporterBuilderUtil.configureExporterMemoryMode(config, builder::setMemoryMode); return builder.build(); } diff --git a/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/metrics/OtlpStdoutMetricExporter.java b/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/metrics/OtlpStdoutMetricExporter.java index 81e9bef105c..4294c1d2571 100644 --- a/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/metrics/OtlpStdoutMetricExporter.java +++ b/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/metrics/OtlpStdoutMetricExporter.java @@ -5,10 +5,11 @@ package io.opentelemetry.exporter.logging.otlp.internal.metrics; -import io.opentelemetry.exporter.internal.otlp.metrics.MetricsRequestMarshaler; +import io.opentelemetry.exporter.internal.otlp.metrics.MetricReusableDataMarshaler; import io.opentelemetry.exporter.internal.otlp.metrics.ResourceMetricsMarshaler; import io.opentelemetry.exporter.logging.otlp.internal.writer.JsonWriter; import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.common.export.MemoryMode; import io.opentelemetry.sdk.metrics.Aggregation; import io.opentelemetry.sdk.metrics.InstrumentType; import io.opentelemetry.sdk.metrics.data.AggregationTemporality; @@ -19,6 +20,7 @@ import java.util.Collection; import java.util.StringJoiner; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function; import java.util.logging.Level; import java.util.logging.Logger; @@ -37,6 +39,8 @@ public final class OtlpStdoutMetricExporter implements MetricExporter { private final Logger logger; private final JsonWriter jsonWriter; private final boolean wrapperJsonObject; + private final MemoryMode memoryMode; + private final Function, CompletableResultCode> marshaler; private final AggregationTemporalitySelector aggregationTemporalitySelector; private final DefaultAggregationSelector defaultAggregationSelector; @@ -44,13 +48,16 @@ public final class OtlpStdoutMetricExporter implements MetricExporter { Logger logger, JsonWriter jsonWriter, boolean wrapperJsonObject, + MemoryMode memoryMode, AggregationTemporalitySelector aggregationTemporalitySelector, DefaultAggregationSelector defaultAggregationSelector) { this.logger = logger; this.jsonWriter = jsonWriter; this.wrapperJsonObject = wrapperJsonObject; + this.memoryMode = memoryMode; this.aggregationTemporalitySelector = aggregationTemporalitySelector; this.defaultAggregationSelector = defaultAggregationSelector; + marshaler = createMarshaler(jsonWriter, memoryMode, wrapperJsonObject); } /** Returns a new {@link OtlpStdoutMetricExporterBuilder}. */ @@ -59,6 +66,28 @@ public static OtlpStdoutMetricExporterBuilder builder() { return new OtlpStdoutMetricExporterBuilder(LOGGER).setOutput(System.out); } + private static Function, CompletableResultCode> createMarshaler( + JsonWriter jsonWriter, MemoryMode memoryMode, boolean wrapperJsonObject) { + if (wrapperJsonObject) { + MetricReusableDataMarshaler reusableDataMarshaler = + new MetricReusableDataMarshaler( + memoryMode, (marshaler, numItems) -> jsonWriter.write(marshaler)); + return reusableDataMarshaler::export; + } else { + return metrics -> { + // no support for low allocation marshaler + for (ResourceMetricsMarshaler marshaler : ResourceMetricsMarshaler.create(metrics)) { + CompletableResultCode resultCode = jsonWriter.write(marshaler); + if (!resultCode.isSuccess()) { + // already logged + return resultCode; + } + } + return CompletableResultCode.ofSuccess(); + }; + } + } + @Override public AggregationTemporality getAggregationTemporality(InstrumentType instrumentType) { return aggregationTemporalitySelector.getAggregationTemporality(instrumentType); @@ -69,25 +98,18 @@ public Aggregation getDefaultAggregation(InstrumentType instrumentType) { return defaultAggregationSelector.getDefaultAggregation(instrumentType); } + @Override + public MemoryMode getMemoryMode() { + return memoryMode; + } + @Override public CompletableResultCode export(Collection metrics) { if (isShutdown.get()) { return CompletableResultCode.ofFailure(); } - if (wrapperJsonObject) { - MetricsRequestMarshaler request = MetricsRequestMarshaler.create(metrics); - return jsonWriter.write(request); - } else { - for (ResourceMetricsMarshaler resourceMetrics : ResourceMetricsMarshaler.create(metrics)) { - CompletableResultCode resultCode = jsonWriter.write(resourceMetrics); - if (!resultCode.isSuccess()) { - // already logged - return resultCode; - } - } - return CompletableResultCode.ofSuccess(); - } + return marshaler.apply(metrics); } @Override @@ -110,6 +132,13 @@ public String toString() { StringJoiner joiner = new StringJoiner(", ", "OtlpStdoutMetricExporter{", "}"); joiner.add("jsonWriter=" + jsonWriter); joiner.add("wrapperJsonObject=" + wrapperJsonObject); + joiner.add("memoryMode=" + memoryMode); + joiner.add( + "aggregationTemporalitySelector=" + + AggregationTemporalitySelector.asString(aggregationTemporalitySelector)); + joiner.add( + "defaultAggregationSelector=" + + DefaultAggregationSelector.asString(defaultAggregationSelector)); return joiner.toString(); } } diff --git a/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/metrics/OtlpStdoutMetricExporterBuilder.java b/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/metrics/OtlpStdoutMetricExporterBuilder.java index 63f16c09060..945ffd778bd 100644 --- a/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/metrics/OtlpStdoutMetricExporterBuilder.java +++ b/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/metrics/OtlpStdoutMetricExporterBuilder.java @@ -11,6 +11,7 @@ import io.opentelemetry.exporter.logging.otlp.internal.writer.JsonWriter; import io.opentelemetry.exporter.logging.otlp.internal.writer.LoggerJsonWriter; import io.opentelemetry.exporter.logging.otlp.internal.writer.StreamJsonWriter; +import io.opentelemetry.sdk.common.export.MemoryMode; import io.opentelemetry.sdk.metrics.InstrumentType; import io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector; import io.opentelemetry.sdk.metrics.export.DefaultAggregationSelector; @@ -40,6 +41,7 @@ public final class OtlpStdoutMetricExporterBuilder { private final Logger logger; private JsonWriter jsonWriter; private boolean wrapperJsonObject = true; + private MemoryMode memoryMode = MemoryMode.IMMUTABLE_DATA; public OtlpStdoutMetricExporterBuilder(Logger logger) { this.logger = logger; @@ -57,6 +59,17 @@ public OtlpStdoutMetricExporterBuilder setWrapperJsonObject(boolean wrapperJsonO return this; } + /** + * Set the {@link MemoryMode}. If unset, defaults to {@link MemoryMode#IMMUTABLE_DATA}. + * + *

When memory mode is {@link MemoryMode#REUSABLE_DATA}, serialization is optimized to reduce + * memory allocation. + */ + public OtlpStdoutMetricExporterBuilder setMemoryMode(MemoryMode memoryMode) { + this.memoryMode = memoryMode; + return this; + } + /** * Sets the exporter to use the specified output stream. * @@ -114,10 +127,15 @@ public OtlpStdoutMetricExporterBuilder setDefaultAggregationSelector( * @return a new exporter's instance */ public OtlpStdoutMetricExporter build() { + if (memoryMode == MemoryMode.REUSABLE_DATA && !wrapperJsonObject) { + throw new IllegalArgumentException( + "Reusable data mode is not supported without wrapperJsonObject"); + } return new OtlpStdoutMetricExporter( logger, jsonWriter, wrapperJsonObject, + memoryMode, aggregationTemporalitySelector, defaultAggregationSelector); } diff --git a/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/metrics/OtlpStdoutMetricExporterComponentProvider.java b/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/metrics/OtlpStdoutMetricExporterComponentProvider.java index dd8b3f643fa..e1e2dc88153 100644 --- a/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/metrics/OtlpStdoutMetricExporterComponentProvider.java +++ b/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/metrics/OtlpStdoutMetricExporterComponentProvider.java @@ -32,6 +32,7 @@ public String getName() { @Override public MetricExporter create(StructuredConfigProperties config) { OtlpStdoutMetricExporterBuilder builder = OtlpStdoutMetricExporter.builder(); + ExporterBuilderUtil.configureExporterMemoryMode(config, builder::setMemoryMode); ExporterBuilderUtil.configureOtlpAggregationTemporality( config, builder::setAggregationTemporalitySelector); ExporterBuilderUtil.configureOtlpHistogramDefaultAggregation( diff --git a/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/metrics/OtlpStdoutMetricExporterProvider.java b/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/metrics/OtlpStdoutMetricExporterProvider.java index 9eace851190..84f32f56c7b 100644 --- a/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/metrics/OtlpStdoutMetricExporterProvider.java +++ b/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/metrics/OtlpStdoutMetricExporterProvider.java @@ -20,6 +20,7 @@ public final class OtlpStdoutMetricExporterProvider implements ConfigurableMetri @Override public MetricExporter createExporter(ConfigProperties config) { OtlpStdoutMetricExporterBuilder builder = OtlpStdoutMetricExporter.builder(); + ExporterBuilderUtil.configureExporterMemoryMode(config, builder::setMemoryMode); ExporterBuilderUtil.configureOtlpAggregationTemporality( config, builder::setAggregationTemporalitySelector); ExporterBuilderUtil.configureOtlpHistogramDefaultAggregation( diff --git a/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/traces/OtlpStdoutSpanExporter.java b/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/traces/OtlpStdoutSpanExporter.java index 39c8829ef9b..187cdacc245 100644 --- a/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/traces/OtlpStdoutSpanExporter.java +++ b/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/traces/OtlpStdoutSpanExporter.java @@ -6,14 +6,16 @@ package io.opentelemetry.exporter.logging.otlp.internal.traces; import io.opentelemetry.exporter.internal.otlp.traces.ResourceSpansMarshaler; -import io.opentelemetry.exporter.internal.otlp.traces.TraceRequestMarshaler; +import io.opentelemetry.exporter.internal.otlp.traces.SpanReusableDataMarshaler; import io.opentelemetry.exporter.logging.otlp.internal.writer.JsonWriter; import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.common.export.MemoryMode; import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.sdk.trace.export.SpanExporter; import java.util.Collection; import java.util.StringJoiner; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function; import java.util.logging.Level; import java.util.logging.Logger; @@ -32,11 +34,16 @@ public final class OtlpStdoutSpanExporter implements SpanExporter { private final Logger logger; private final JsonWriter jsonWriter; private final boolean wrapperJsonObject; + private final MemoryMode memoryMode; + private final Function, CompletableResultCode> marshaler; - OtlpStdoutSpanExporter(Logger logger, JsonWriter jsonWriter, boolean wrapperJsonObject) { + OtlpStdoutSpanExporter( + Logger logger, JsonWriter jsonWriter, boolean wrapperJsonObject, MemoryMode memoryMode) { this.logger = logger; this.jsonWriter = jsonWriter; this.wrapperJsonObject = wrapperJsonObject; + this.memoryMode = memoryMode; + marshaler = createMarshaler(jsonWriter, memoryMode, wrapperJsonObject); } /** Returns a new {@link OtlpStdoutSpanExporterBuilder}. */ @@ -45,25 +52,35 @@ public static OtlpStdoutSpanExporterBuilder builder() { return new OtlpStdoutSpanExporterBuilder(LOGGER).setOutput(System.out); } + private static Function, CompletableResultCode> createMarshaler( + JsonWriter jsonWriter, MemoryMode memoryMode, boolean wrapperJsonObject) { + if (wrapperJsonObject) { + SpanReusableDataMarshaler reusableDataMarshaler = + new SpanReusableDataMarshaler( + memoryMode, (marshaler, numItems) -> jsonWriter.write(marshaler)); + return reusableDataMarshaler::export; + } else { + return spans -> { + // no support for low allocation marshaler + for (ResourceSpansMarshaler marshaler : ResourceSpansMarshaler.create(spans)) { + CompletableResultCode resultCode = jsonWriter.write(marshaler); + if (!resultCode.isSuccess()) { + // already logged + return resultCode; + } + } + return CompletableResultCode.ofSuccess(); + }; + } + } + @Override public CompletableResultCode export(Collection spans) { if (isShutdown.get()) { return CompletableResultCode.ofFailure(); } - if (wrapperJsonObject) { - TraceRequestMarshaler request = TraceRequestMarshaler.create(spans); - return jsonWriter.write(request); - } else { - for (ResourceSpansMarshaler resourceSpans : ResourceSpansMarshaler.create(spans)) { - CompletableResultCode resultCode = jsonWriter.write(resourceSpans); - if (!resultCode.isSuccess()) { - // already logged - return resultCode; - } - } - return CompletableResultCode.ofSuccess(); - } + return marshaler.apply(spans); } @Override @@ -86,6 +103,7 @@ public String toString() { StringJoiner joiner = new StringJoiner(", ", "OtlpStdoutSpanExporter{", "}"); joiner.add("jsonWriter=" + jsonWriter); joiner.add("wrapperJsonObject=" + wrapperJsonObject); + joiner.add("memoryMode=" + memoryMode); return joiner.toString(); } } diff --git a/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/traces/OtlpStdoutSpanExporterBuilder.java b/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/traces/OtlpStdoutSpanExporterBuilder.java index 2ca9e5a97b3..341f63c6e49 100644 --- a/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/traces/OtlpStdoutSpanExporterBuilder.java +++ b/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/traces/OtlpStdoutSpanExporterBuilder.java @@ -11,6 +11,7 @@ import io.opentelemetry.exporter.logging.otlp.internal.writer.JsonWriter; import io.opentelemetry.exporter.logging.otlp.internal.writer.LoggerJsonWriter; import io.opentelemetry.exporter.logging.otlp.internal.writer.StreamJsonWriter; +import io.opentelemetry.sdk.common.export.MemoryMode; import java.io.OutputStream; import java.util.logging.Logger; @@ -27,6 +28,7 @@ public final class OtlpStdoutSpanExporterBuilder { private final Logger logger; private JsonWriter jsonWriter; private boolean wrapperJsonObject = true; + private MemoryMode memoryMode = MemoryMode.IMMUTABLE_DATA; public OtlpStdoutSpanExporterBuilder(Logger logger) { this.logger = logger; @@ -44,6 +46,17 @@ public OtlpStdoutSpanExporterBuilder setWrapperJsonObject(boolean wrapperJsonObj return this; } + /** + * Set the {@link MemoryMode}. If unset, defaults to {@link MemoryMode#IMMUTABLE_DATA}. + * + *

When memory mode is {@link MemoryMode#REUSABLE_DATA}, serialization is optimized to reduce + * memory allocation. + */ + public OtlpStdoutSpanExporterBuilder setMemoryMode(MemoryMode memoryMode) { + this.memoryMode = memoryMode; + return this; + } + /** * Sets the exporter to use the specified output stream. * @@ -71,6 +84,10 @@ public OtlpStdoutSpanExporterBuilder setOutput(Logger logger) { * @return a new exporter's instance */ public OtlpStdoutSpanExporter build() { - return new OtlpStdoutSpanExporter(logger, jsonWriter, wrapperJsonObject); + if (memoryMode == MemoryMode.REUSABLE_DATA && !wrapperJsonObject) { + throw new IllegalArgumentException( + "Reusable data mode is not supported without wrapperJsonObject"); + } + return new OtlpStdoutSpanExporter(logger, jsonWriter, wrapperJsonObject, memoryMode); } } diff --git a/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/traces/OtlpStdoutSpanExporterComponentProvider.java b/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/traces/OtlpStdoutSpanExporterComponentProvider.java index 1d60e1a37b8..af299c16251 100644 --- a/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/traces/OtlpStdoutSpanExporterComponentProvider.java +++ b/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/traces/OtlpStdoutSpanExporterComponentProvider.java @@ -5,6 +5,7 @@ package io.opentelemetry.exporter.logging.otlp.internal.traces; +import io.opentelemetry.exporter.internal.ExporterBuilderUtil; import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties; import io.opentelemetry.sdk.trace.export.SpanExporter; @@ -31,6 +32,7 @@ public String getName() { @Override public SpanExporter create(StructuredConfigProperties config) { OtlpStdoutSpanExporterBuilder builder = OtlpStdoutSpanExporter.builder(); + ExporterBuilderUtil.configureExporterMemoryMode(config, builder::setMemoryMode); return builder.build(); } } diff --git a/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/traces/OtlpStdoutSpanExporterProvider.java b/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/traces/OtlpStdoutSpanExporterProvider.java index e5d2f008315..84514492f24 100644 --- a/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/traces/OtlpStdoutSpanExporterProvider.java +++ b/exporters/logging-otlp/src/main/java/io/opentelemetry/exporter/logging/otlp/internal/traces/OtlpStdoutSpanExporterProvider.java @@ -5,6 +5,7 @@ package io.opentelemetry.exporter.logging.otlp.internal.traces; +import io.opentelemetry.exporter.internal.ExporterBuilderUtil; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider; import io.opentelemetry.sdk.trace.export.SpanExporter; @@ -19,6 +20,7 @@ public final class OtlpStdoutSpanExporterProvider implements ConfigurableSpanExp @Override public SpanExporter createExporter(ConfigProperties config) { OtlpStdoutSpanExporterBuilder builder = OtlpStdoutSpanExporter.builder(); + ExporterBuilderUtil.configureExporterMemoryMode(config, builder::setMemoryMode); return builder.build(); } diff --git a/exporters/logging-otlp/src/test/java/io/opentelemetry/exporter/logging/otlp/AbstractOtlpStdoutExporterTest.java b/exporters/logging-otlp/src/test/java/io/opentelemetry/exporter/logging/otlp/AbstractOtlpStdoutExporterTest.java index b18f432a4de..3988fae332d 100644 --- a/exporters/logging-otlp/src/test/java/io/opentelemetry/exporter/logging/otlp/AbstractOtlpStdoutExporterTest.java +++ b/exporters/logging-otlp/src/test/java/io/opentelemetry/exporter/logging/otlp/AbstractOtlpStdoutExporterTest.java @@ -6,8 +6,11 @@ package io.opentelemetry.exporter.logging.otlp; import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import com.google.common.collect.ImmutableList; import com.google.common.collect.Streams; @@ -16,6 +19,7 @@ import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties; +import io.opentelemetry.sdk.common.export.MemoryMode; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -27,6 +31,7 @@ import java.nio.file.Path; import java.util.ServiceLoader; import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; import java.util.stream.Stream; import javax.annotation.Nullable; import org.json.JSONException; @@ -75,7 +80,7 @@ public AbstractOtlpStdoutExporterTest( } protected abstract T createExporter( - @Nullable OutputStream outputStream, boolean wrapperJsonObject); + @Nullable OutputStream outputStream, MemoryMode memoryMode, boolean wrapperJsonObject); protected abstract T createDefaultExporter(); @@ -128,12 +133,13 @@ enum OutputType { } public static class TestCase { - + private final MemoryMode memoryMode; private final boolean wrapperJsonObject; private final OutputType outputType; - public TestCase(OutputType outputType, boolean wrapperJsonObject) { + public TestCase(OutputType outputType, MemoryMode memoryMode, boolean wrapperJsonObject) { this.outputType = outputType; + this.memoryMode = memoryMode; this.wrapperJsonObject = wrapperJsonObject; } @@ -144,25 +150,55 @@ public OutputType getOutputType() { public boolean isWrapperJsonObject() { return wrapperJsonObject; } + + public MemoryMode getMemoryMode() { + return memoryMode; + } } static Stream exportTestCases() { return ImmutableList.of( - testCase(OutputType.SYSTEM_OUT, /* wrapperJsonObject= */ true), - testCase(OutputType.SYSTEM_OUT, /* wrapperJsonObject= */ false), - testCase(OutputType.FILE, /* wrapperJsonObject= */ true), - testCase(OutputType.FILE, /* wrapperJsonObject= */ false), - testCase(OutputType.FILE_AND_BUFFERED_WRITER, /* wrapperJsonObject= */ true), - testCase(OutputType.FILE_AND_BUFFERED_WRITER, /* wrapperJsonObject= */ false), - testCase(OutputType.LOGGER, /* wrapperJsonObject= */ true), - testCase(OutputType.LOGGER, /* wrapperJsonObject= */ false)) + testCase(OutputType.SYSTEM_OUT, MemoryMode.IMMUTABLE_DATA, /* wrapperJsonObject= */ true), + testCase(OutputType.SYSTEM_OUT, MemoryMode.IMMUTABLE_DATA, /* wrapperJsonObject= */ false), + testCase(OutputType.FILE, MemoryMode.IMMUTABLE_DATA, /* wrapperJsonObject= */ true), + testCase(OutputType.FILE, MemoryMode.IMMUTABLE_DATA, /* wrapperJsonObject= */ false), + testCase( + OutputType.FILE_AND_BUFFERED_WRITER, + MemoryMode.IMMUTABLE_DATA, + /* wrapperJsonObject= */ true), + testCase( + OutputType.FILE_AND_BUFFERED_WRITER, + MemoryMode.IMMUTABLE_DATA, + /* wrapperJsonObject= */ false), + testCase(OutputType.LOGGER, MemoryMode.IMMUTABLE_DATA, /* wrapperJsonObject= */ true), + testCase(OutputType.LOGGER, MemoryMode.IMMUTABLE_DATA, /* wrapperJsonObject= */ false), + testCase(OutputType.SYSTEM_OUT, MemoryMode.REUSABLE_DATA, /* wrapperJsonObject= */ true), + testCase(OutputType.SYSTEM_OUT, MemoryMode.REUSABLE_DATA, /* wrapperJsonObject= */ false), + testCase(OutputType.FILE, MemoryMode.REUSABLE_DATA, /* wrapperJsonObject= */ true), + testCase(OutputType.FILE, MemoryMode.REUSABLE_DATA, /* wrapperJsonObject= */ false), + testCase( + OutputType.FILE_AND_BUFFERED_WRITER, + MemoryMode.REUSABLE_DATA, + /* wrapperJsonObject= */ true), + testCase( + OutputType.FILE_AND_BUFFERED_WRITER, + MemoryMode.REUSABLE_DATA, + /* wrapperJsonObject= */ false), + testCase(OutputType.LOGGER, MemoryMode.REUSABLE_DATA, /* wrapperJsonObject= */ true), + testCase(OutputType.LOGGER, MemoryMode.REUSABLE_DATA, /* wrapperJsonObject= */ false)) .stream(); } - private static Arguments testCase(OutputType type, boolean wrapperJsonObject) { + private static Arguments testCase( + OutputType type, MemoryMode memoryMode, boolean wrapperJsonObject) { return Arguments.of( - "output=" + type + ", wrapperJsonObject=" + wrapperJsonObject, - new TestCase(type, wrapperJsonObject)); + "output=" + + type + + ", wrapperJsonObject=" + + wrapperJsonObject + + ", memoryMode=" + + memoryMode, + new TestCase(type, memoryMode, wrapperJsonObject)); } @SuppressWarnings("SystemOut") @@ -190,8 +226,19 @@ void exportWithProgrammaticConfig(String name, TestCase testCase) default: throw new IllegalStateException("Unexpected value: " + testCase.getOutputType()); } - T exporter = createExporter(outputStream, testCase.isWrapperJsonObject()); - testDataExporter.export(exporter); + + Supplier exporter = + () -> + createExporter(outputStream, testCase.getMemoryMode(), testCase.isWrapperJsonObject()); + + if (testCase.getMemoryMode() == MemoryMode.REUSABLE_DATA && !testCase.isWrapperJsonObject()) { + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(exporter::get) + .withMessage("Reusable data mode is not supported without wrapperJsonObject"); + return; + } + + testDataExporter.export(exporter.get()); String output = output(outputStream, file); String expectedJson = testDataExporter.getExpectedJson(testCase.isWrapperJsonObject()); @@ -215,40 +262,69 @@ void testShutdown() { @Test void defaultToString() { - assertFullToString(createDefaultExporter(), defaultConfigString); + assertThat(createDefaultExporter()).hasToString(defaultConfigString); - assertFullToString( - loadExporter(DefaultConfigProperties.createFromMap(emptyMap())), defaultConfigString); + assertThat(exporterFromProvider(DefaultConfigProperties.createFromMap(emptyMap()))) + .hasToString(defaultConfigString); } - protected Object exporterFromComponentProvider(StructuredConfigProperties properties) { - return ((ComponentProvider) - loadSpi(ComponentProvider.class) - .filter( - p -> { - ComponentProvider c = (ComponentProvider) p; - return "experimental-otlp/stdout".equals(c.getName()) - && c.getType().equals(componentProviderType); - }) - .findFirst() - .orElseThrow(() -> new IllegalStateException("No provider found"))) - .create(properties); + @Test + void providerConfig() { + assertThat( + exporterFromProvider( + DefaultConfigProperties.createFromMap( + singletonMap("otel.java.experimental.exporter.memory_mode", "immutable_data")))) + .extracting("memoryMode") + .isEqualTo(MemoryMode.IMMUTABLE_DATA); + assertThat( + exporterFromProvider( + DefaultConfigProperties.createFromMap( + singletonMap("otel.java.experimental.exporter.memory_mode", "reusable_data")))) + .extracting("memoryMode") + .isEqualTo(MemoryMode.REUSABLE_DATA); } @Test void componentProviderConfig() { StructuredConfigProperties properties = mock(StructuredConfigProperties.class); - Object exporter = exporterFromComponentProvider(properties); + T exporter = exporterFromComponentProvider(properties); assertThat(exporter).extracting("wrapperJsonObject").isEqualTo(true); + assertThat(exporter).extracting("memoryMode").isEqualTo(MemoryMode.IMMUTABLE_DATA); assertThat(exporter) .extracting("jsonWriter") .extracting(Object::toString) .isEqualTo("StreamJsonWriter{outputStream=stdout}"); + + when(properties.getString("memory_mode")).thenReturn("IMMUTABLE_DATA"); + assertThat(exporterFromComponentProvider(properties)) + .extracting("memoryMode") + .isEqualTo(MemoryMode.IMMUTABLE_DATA); + + when(properties.getString("memory_mode")).thenReturn("REUSABLE_DATA"); + assertThat(exporterFromComponentProvider(properties)) + .extracting("memoryMode") + .isEqualTo(MemoryMode.REUSABLE_DATA); } @SuppressWarnings("unchecked") - protected T loadExporter(ConfigProperties config) { + protected T exporterFromComponentProvider(StructuredConfigProperties properties) { + return (T) + ((ComponentProvider) + loadSpi(ComponentProvider.class) + .filter( + p -> { + ComponentProvider c = (ComponentProvider) p; + return "experimental-otlp/stdout".equals(c.getName()) + && c.getType().equals(componentProviderType); + }) + .findFirst() + .orElseThrow(() -> new IllegalStateException("No provider found"))) + .create(properties); + } + + @SuppressWarnings("unchecked") + protected T exporterFromProvider(ConfigProperties config) { Object provider = loadProvider(); try { @@ -280,8 +356,4 @@ private Object loadProvider() { protected static Stream loadSpi(Class type) { return Streams.stream(ServiceLoader.load(type, type.getClassLoader()).iterator()); } - - private void assertFullToString(T exporter, String expected) { - assertThat(exporter.toString()).isEqualTo(expected); - } } diff --git a/exporters/logging-otlp/src/test/java/io/opentelemetry/exporter/logging/otlp/OtlpStdoutLogRecordExporterTest.java b/exporters/logging-otlp/src/test/java/io/opentelemetry/exporter/logging/otlp/OtlpStdoutLogRecordExporterTest.java index e234b9745dc..c19fba0fe3e 100644 --- a/exporters/logging-otlp/src/test/java/io/opentelemetry/exporter/logging/otlp/OtlpStdoutLogRecordExporterTest.java +++ b/exporters/logging-otlp/src/test/java/io/opentelemetry/exporter/logging/otlp/OtlpStdoutLogRecordExporterTest.java @@ -8,6 +8,7 @@ import io.opentelemetry.exporter.logging.otlp.internal.logs.OtlpStdoutLogRecordExporter; import io.opentelemetry.exporter.logging.otlp.internal.logs.OtlpStdoutLogRecordExporterBuilder; import io.opentelemetry.sdk.autoconfigure.spi.logs.ConfigurableLogRecordExporterProvider; +import io.opentelemetry.sdk.common.export.MemoryMode; import io.opentelemetry.sdk.logs.export.LogRecordExporter; import java.io.OutputStream; import java.util.logging.Logger; @@ -22,7 +23,7 @@ public OtlpStdoutLogRecordExporterTest() { OtlpStdoutLogRecordExporter.class, ConfigurableLogRecordExporterProvider.class, LogRecordExporter.class, - "OtlpStdoutLogRecordExporter{jsonWriter=StreamJsonWriter{outputStream=stdout}, wrapperJsonObject=true}"); + "OtlpStdoutLogRecordExporter{jsonWriter=StreamJsonWriter{outputStream=stdout}, wrapperJsonObject=true, memoryMode=IMMUTABLE_DATA}"); } @Override @@ -32,9 +33,11 @@ protected OtlpStdoutLogRecordExporter createDefaultExporter() { @Override protected OtlpStdoutLogRecordExporter createExporter( - @Nullable OutputStream outputStream, boolean wrapperJsonObject) { + @Nullable OutputStream outputStream, MemoryMode memoryMode, boolean wrapperJsonObject) { OtlpStdoutLogRecordExporterBuilder builder = - OtlpStdoutLogRecordExporter.builder().setWrapperJsonObject(wrapperJsonObject); + OtlpStdoutLogRecordExporter.builder() + .setMemoryMode(memoryMode) + .setWrapperJsonObject(wrapperJsonObject); if (outputStream != null) { builder.setOutput(outputStream); } else { diff --git a/exporters/logging-otlp/src/test/java/io/opentelemetry/exporter/logging/otlp/OtlpStdoutMetricExporterTest.java b/exporters/logging-otlp/src/test/java/io/opentelemetry/exporter/logging/otlp/OtlpStdoutMetricExporterTest.java index fdc6d945fc4..fc081e229f4 100644 --- a/exporters/logging-otlp/src/test/java/io/opentelemetry/exporter/logging/otlp/OtlpStdoutMetricExporterTest.java +++ b/exporters/logging-otlp/src/test/java/io/opentelemetry/exporter/logging/otlp/OtlpStdoutMetricExporterTest.java @@ -16,6 +16,7 @@ import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.metrics.ConfigurableMetricExporterProvider; +import io.opentelemetry.sdk.common.export.MemoryMode; import io.opentelemetry.sdk.metrics.Aggregation; import io.opentelemetry.sdk.metrics.InstrumentType; import io.opentelemetry.sdk.metrics.data.AggregationTemporality; @@ -36,7 +37,7 @@ public OtlpStdoutMetricExporterTest() { OtlpStdoutMetricExporter.class, ConfigurableMetricExporterProvider.class, MetricExporter.class, - "OtlpStdoutMetricExporter{jsonWriter=StreamJsonWriter{outputStream=stdout}, wrapperJsonObject=true}"); + "OtlpStdoutMetricExporter{jsonWriter=StreamJsonWriter{outputStream=stdout}, wrapperJsonObject=true, memoryMode=IMMUTABLE_DATA, aggregationTemporalitySelector=AggregationTemporalitySelector{COUNTER=CUMULATIVE, UP_DOWN_COUNTER=CUMULATIVE, HISTOGRAM=CUMULATIVE, OBSERVABLE_COUNTER=CUMULATIVE, OBSERVABLE_UP_DOWN_COUNTER=CUMULATIVE, OBSERVABLE_GAUGE=CUMULATIVE, GAUGE=CUMULATIVE}, defaultAggregationSelector=DefaultAggregationSelector{COUNTER=default, UP_DOWN_COUNTER=default, HISTOGRAM=default, OBSERVABLE_COUNTER=default, OBSERVABLE_UP_DOWN_COUNTER=default, OBSERVABLE_GAUGE=default, GAUGE=default}}"); } @Override @@ -46,9 +47,11 @@ protected OtlpStdoutMetricExporter createDefaultExporter() { @Override protected OtlpStdoutMetricExporter createExporter( - @Nullable OutputStream outputStream, boolean wrapperJsonObject) { + @Nullable OutputStream outputStream, MemoryMode memoryMode, boolean wrapperJsonObject) { OtlpStdoutMetricExporterBuilder builder = - OtlpStdoutMetricExporter.builder().setWrapperJsonObject(wrapperJsonObject); + OtlpStdoutMetricExporter.builder() + .setMemoryMode(memoryMode) + .setWrapperJsonObject(wrapperJsonObject); if (outputStream != null) { builder.setOutput(outputStream); } else { @@ -61,7 +64,7 @@ protected OtlpStdoutMetricExporter createExporter( @Test void providerMetricConfig() { OtlpStdoutMetricExporter exporter = - loadExporter( + exporterFromProvider( DefaultConfigProperties.createFromMap( ImmutableMap.of( "otel.exporter.otlp.metrics.temporality.preference", @@ -83,8 +86,7 @@ void componentProviderMetricConfig() { when(properties.getString("default_histogram_aggregation")) .thenReturn("BASE2_EXPONENTIAL_BUCKET_HISTOGRAM"); - OtlpStdoutMetricExporter exporter = - (OtlpStdoutMetricExporter) exporterFromComponentProvider(properties); + OtlpStdoutMetricExporter exporter = exporterFromComponentProvider(properties); assertThat(exporter.getAggregationTemporality(InstrumentType.COUNTER)) .isEqualTo(AggregationTemporality.DELTA); diff --git a/exporters/logging-otlp/src/test/java/io/opentelemetry/exporter/logging/otlp/OtlpStdoutSpanExporterTest.java b/exporters/logging-otlp/src/test/java/io/opentelemetry/exporter/logging/otlp/OtlpStdoutSpanExporterTest.java index 472ff4cd731..01d3a96ccd2 100644 --- a/exporters/logging-otlp/src/test/java/io/opentelemetry/exporter/logging/otlp/OtlpStdoutSpanExporterTest.java +++ b/exporters/logging-otlp/src/test/java/io/opentelemetry/exporter/logging/otlp/OtlpStdoutSpanExporterTest.java @@ -8,6 +8,7 @@ import io.opentelemetry.exporter.logging.otlp.internal.traces.OtlpStdoutSpanExporter; import io.opentelemetry.exporter.logging.otlp.internal.traces.OtlpStdoutSpanExporterBuilder; import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider; +import io.opentelemetry.sdk.common.export.MemoryMode; import io.opentelemetry.sdk.trace.export.SpanExporter; import java.io.OutputStream; import java.util.logging.Logger; @@ -21,7 +22,7 @@ public OtlpStdoutSpanExporterTest() { OtlpStdoutSpanExporter.class, ConfigurableSpanExporterProvider.class, SpanExporter.class, - "OtlpStdoutSpanExporter{jsonWriter=StreamJsonWriter{outputStream=stdout}, wrapperJsonObject=true}"); + "OtlpStdoutSpanExporter{jsonWriter=StreamJsonWriter{outputStream=stdout}, wrapperJsonObject=true, memoryMode=IMMUTABLE_DATA}"); } @Override @@ -31,9 +32,11 @@ protected OtlpStdoutSpanExporter createDefaultExporter() { @Override protected OtlpStdoutSpanExporter createExporter( - @Nullable OutputStream outputStream, boolean wrapperJsonObject) { + @Nullable OutputStream outputStream, MemoryMode memoryMode, boolean wrapperJsonObject) { OtlpStdoutSpanExporterBuilder builder = - OtlpStdoutSpanExporter.builder().setWrapperJsonObject(wrapperJsonObject); + OtlpStdoutSpanExporter.builder() + .setMemoryMode(memoryMode) + .setWrapperJsonObject(wrapperJsonObject); if (outputStream != null) { builder.setOutput(outputStream); } else { diff --git a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/logs/OtlpHttpLogRecordExporter.java b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/logs/OtlpHttpLogRecordExporter.java index 4f3202ceb99..dcc8b4bcc7a 100644 --- a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/logs/OtlpHttpLogRecordExporter.java +++ b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/logs/OtlpHttpLogRecordExporter.java @@ -8,15 +8,12 @@ import io.opentelemetry.exporter.internal.http.HttpExporter; import io.opentelemetry.exporter.internal.http.HttpExporterBuilder; import io.opentelemetry.exporter.internal.marshal.Marshaler; -import io.opentelemetry.exporter.internal.otlp.logs.LogsRequestMarshaler; -import io.opentelemetry.exporter.internal.otlp.logs.LowAllocationLogsRequestMarshaler; +import io.opentelemetry.exporter.internal.otlp.logs.LogReusableDataMarshaler; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.export.MemoryMode; import io.opentelemetry.sdk.logs.data.LogRecordData; import io.opentelemetry.sdk.logs.export.LogRecordExporter; -import java.util.ArrayDeque; import java.util.Collection; -import java.util.Deque; import java.util.StringJoiner; import javax.annotation.concurrent.ThreadSafe; @@ -28,10 +25,9 @@ @ThreadSafe public final class OtlpHttpLogRecordExporter implements LogRecordExporter { - private final Deque marshalerPool = new ArrayDeque<>(); private final HttpExporterBuilder builder; private final HttpExporter delegate; - private final MemoryMode memoryMode; + private final LogReusableDataMarshaler marshaler; OtlpHttpLogRecordExporter( HttpExporterBuilder builder, @@ -39,7 +35,7 @@ public final class OtlpHttpLogRecordExporter implements LogRecordExporter { MemoryMode memoryMode) { this.builder = builder; this.delegate = delegate; - this.memoryMode = memoryMode; + this.marshaler = new LogReusableDataMarshaler(memoryMode, delegate::export); } /** @@ -71,7 +67,7 @@ public static OtlpHttpLogRecordExporterBuilder builder() { * @since 1.29.0 */ public OtlpHttpLogRecordExporterBuilder toBuilder() { - return new OtlpHttpLogRecordExporterBuilder(builder.copy(), memoryMode); + return new OtlpHttpLogRecordExporterBuilder(builder.copy(), marshaler.getMemoryMode()); } /** @@ -82,24 +78,7 @@ public OtlpHttpLogRecordExporterBuilder toBuilder() { */ @Override public CompletableResultCode export(Collection logs) { - if (memoryMode == MemoryMode.REUSABLE_DATA) { - LowAllocationLogsRequestMarshaler marshaler = marshalerPool.poll(); - if (marshaler == null) { - marshaler = new LowAllocationLogsRequestMarshaler(); - } - LowAllocationLogsRequestMarshaler exportMarshaler = marshaler; - exportMarshaler.initialize(logs); - return delegate - .export(exportMarshaler, logs.size()) - .whenComplete( - () -> { - exportMarshaler.reset(); - marshalerPool.add(exportMarshaler); - }); - } - // MemoryMode == MemoryMode.IMMUTABLE_DATA - LogsRequestMarshaler request = LogsRequestMarshaler.create(logs); - return delegate.export(request, logs.size()); + return marshaler.export(logs); } @Override @@ -117,7 +96,7 @@ public CompletableResultCode shutdown() { public String toString() { StringJoiner joiner = new StringJoiner(", ", "OtlpHttpLogRecordExporter{", "}"); joiner.add(builder.toString(false)); - joiner.add("memoryMode=" + memoryMode); + joiner.add("memoryMode=" + marshaler.getMemoryMode()); return joiner.toString(); } } diff --git a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporter.java b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporter.java index 1634d47fee5..87d7b4c7a10 100644 --- a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporter.java +++ b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporter.java @@ -8,8 +8,7 @@ import io.opentelemetry.exporter.internal.http.HttpExporter; import io.opentelemetry.exporter.internal.http.HttpExporterBuilder; import io.opentelemetry.exporter.internal.marshal.Marshaler; -import io.opentelemetry.exporter.internal.otlp.metrics.LowAllocationMetricsRequestMarshaler; -import io.opentelemetry.exporter.internal.otlp.metrics.MetricsRequestMarshaler; +import io.opentelemetry.exporter.internal.otlp.metrics.MetricReusableDataMarshaler; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.export.MemoryMode; import io.opentelemetry.sdk.metrics.Aggregation; @@ -19,9 +18,7 @@ import io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector; import io.opentelemetry.sdk.metrics.export.DefaultAggregationSelector; import io.opentelemetry.sdk.metrics.export.MetricExporter; -import java.util.ArrayDeque; import java.util.Collection; -import java.util.Deque; import java.util.StringJoiner; import javax.annotation.concurrent.ThreadSafe; @@ -33,12 +30,11 @@ @ThreadSafe public final class OtlpHttpMetricExporter implements MetricExporter { - private final Deque marshalerPool = new ArrayDeque<>(); private final HttpExporterBuilder builder; private final HttpExporter delegate; private final AggregationTemporalitySelector aggregationTemporalitySelector; private final DefaultAggregationSelector defaultAggregationSelector; - private final MemoryMode memoryMode; + private final MetricReusableDataMarshaler marshaler; OtlpHttpMetricExporter( HttpExporterBuilder builder, @@ -50,7 +46,7 @@ public final class OtlpHttpMetricExporter implements MetricExporter { this.delegate = delegate; this.aggregationTemporalitySelector = aggregationTemporalitySelector; this.defaultAggregationSelector = defaultAggregationSelector; - this.memoryMode = memoryMode; + this.marshaler = new MetricReusableDataMarshaler(memoryMode, delegate::export); } /** @@ -82,7 +78,7 @@ public static OtlpHttpMetricExporterBuilder builder() { * @since 1.29.0 */ public OtlpHttpMetricExporterBuilder toBuilder() { - return new OtlpHttpMetricExporterBuilder(builder.copy(), memoryMode); + return new OtlpHttpMetricExporterBuilder(builder.copy(), marshaler.getMemoryMode()); } @Override @@ -97,7 +93,7 @@ public Aggregation getDefaultAggregation(InstrumentType instrumentType) { @Override public MemoryMode getMemoryMode() { - return memoryMode; + return marshaler.getMemoryMode(); } /** @@ -108,24 +104,7 @@ public MemoryMode getMemoryMode() { */ @Override public CompletableResultCode export(Collection metrics) { - if (memoryMode == MemoryMode.REUSABLE_DATA) { - LowAllocationMetricsRequestMarshaler marshaler = marshalerPool.poll(); - if (marshaler == null) { - marshaler = new LowAllocationMetricsRequestMarshaler(); - } - LowAllocationMetricsRequestMarshaler exportMarshaler = marshaler; - exportMarshaler.initialize(metrics); - return delegate - .export(exportMarshaler, metrics.size()) - .whenComplete( - () -> { - exportMarshaler.reset(); - marshalerPool.add(exportMarshaler); - }); - } - // MemoryMode == MemoryMode.IMMUTABLE_DATA - MetricsRequestMarshaler request = MetricsRequestMarshaler.create(metrics); - return delegate.export(request, metrics.size()); + return marshaler.export(metrics); } /** @@ -154,7 +133,7 @@ public String toString() { joiner.add( "defaultAggregationSelector=" + DefaultAggregationSelector.asString(defaultAggregationSelector)); - joiner.add("memoryMode=" + memoryMode); + joiner.add("memoryMode=" + marshaler.getMemoryMode()); return joiner.toString(); } } diff --git a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporter.java b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporter.java index 86d4016adb6..71870e12b54 100644 --- a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporter.java +++ b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporter.java @@ -8,15 +8,12 @@ import io.opentelemetry.exporter.internal.http.HttpExporter; import io.opentelemetry.exporter.internal.http.HttpExporterBuilder; import io.opentelemetry.exporter.internal.marshal.Marshaler; -import io.opentelemetry.exporter.internal.otlp.traces.LowAllocationTraceRequestMarshaler; -import io.opentelemetry.exporter.internal.otlp.traces.TraceRequestMarshaler; +import io.opentelemetry.exporter.internal.otlp.traces.SpanReusableDataMarshaler; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.export.MemoryMode; import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.sdk.trace.export.SpanExporter; -import java.util.ArrayDeque; import java.util.Collection; -import java.util.Deque; import java.util.StringJoiner; import javax.annotation.concurrent.ThreadSafe; @@ -28,10 +25,9 @@ @ThreadSafe public final class OtlpHttpSpanExporter implements SpanExporter { - private final Deque marshalerPool = new ArrayDeque<>(); private final HttpExporterBuilder builder; private final HttpExporter delegate; - private final MemoryMode memoryMode; + private final SpanReusableDataMarshaler marshaler; OtlpHttpSpanExporter( HttpExporterBuilder builder, @@ -39,7 +35,7 @@ public final class OtlpHttpSpanExporter implements SpanExporter { MemoryMode memoryMode) { this.builder = builder; this.delegate = delegate; - this.memoryMode = memoryMode; + this.marshaler = new SpanReusableDataMarshaler(memoryMode, delegate::export); } /** @@ -71,7 +67,7 @@ public static OtlpHttpSpanExporterBuilder builder() { * @since 1.29.0 */ public OtlpHttpSpanExporterBuilder toBuilder() { - return new OtlpHttpSpanExporterBuilder(builder.copy(), memoryMode); + return new OtlpHttpSpanExporterBuilder(builder.copy(), marshaler.getMemoryMode()); } /** @@ -82,24 +78,7 @@ public OtlpHttpSpanExporterBuilder toBuilder() { */ @Override public CompletableResultCode export(Collection spans) { - if (memoryMode == MemoryMode.REUSABLE_DATA) { - LowAllocationTraceRequestMarshaler marshaler = marshalerPool.poll(); - if (marshaler == null) { - marshaler = new LowAllocationTraceRequestMarshaler(); - } - LowAllocationTraceRequestMarshaler exportMarshaler = marshaler; - exportMarshaler.initialize(spans); - return delegate - .export(exportMarshaler, spans.size()) - .whenComplete( - () -> { - exportMarshaler.reset(); - marshalerPool.add(exportMarshaler); - }); - } - // MemoryMode == MemoryMode.IMMUTABLE_DATA - TraceRequestMarshaler request = TraceRequestMarshaler.create(spans); - return delegate.export(request, spans.size()); + return marshaler.export(spans); } /** @@ -122,7 +101,7 @@ public CompletableResultCode shutdown() { public String toString() { StringJoiner joiner = new StringJoiner(", ", "OtlpHttpSpanExporter{", "}"); joiner.add(builder.toString(false)); - joiner.add("memoryMode=" + memoryMode); + joiner.add("memoryMode=" + marshaler.getMemoryMode()); return joiner.toString(); } } diff --git a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcLogRecordExporter.java b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcLogRecordExporter.java index efde0010450..e85cb76b78f 100644 --- a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcLogRecordExporter.java +++ b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcLogRecordExporter.java @@ -8,15 +8,12 @@ import io.opentelemetry.exporter.internal.grpc.GrpcExporter; import io.opentelemetry.exporter.internal.grpc.GrpcExporterBuilder; import io.opentelemetry.exporter.internal.marshal.Marshaler; -import io.opentelemetry.exporter.internal.otlp.logs.LogsRequestMarshaler; -import io.opentelemetry.exporter.internal.otlp.logs.LowAllocationLogsRequestMarshaler; +import io.opentelemetry.exporter.internal.otlp.logs.LogReusableDataMarshaler; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.export.MemoryMode; import io.opentelemetry.sdk.logs.data.LogRecordData; import io.opentelemetry.sdk.logs.export.LogRecordExporter; -import java.util.ArrayDeque; import java.util.Collection; -import java.util.Deque; import java.util.StringJoiner; import javax.annotation.concurrent.ThreadSafe; @@ -28,10 +25,9 @@ @ThreadSafe public final class OtlpGrpcLogRecordExporter implements LogRecordExporter { - private final Deque marshalerPool = new ArrayDeque<>(); private final GrpcExporterBuilder builder; private final GrpcExporter delegate; - private final MemoryMode memoryMode; + private final LogReusableDataMarshaler marshaler; /** * Returns a new {@link OtlpGrpcLogRecordExporter} using the default values. @@ -60,7 +56,7 @@ public static OtlpGrpcLogRecordExporterBuilder builder() { MemoryMode memoryMode) { this.builder = builder; this.delegate = delegate; - this.memoryMode = memoryMode; + this.marshaler = new LogReusableDataMarshaler(memoryMode, delegate::export); } /** @@ -71,7 +67,7 @@ public static OtlpGrpcLogRecordExporterBuilder builder() { * @since 1.29.0 */ public OtlpGrpcLogRecordExporterBuilder toBuilder() { - return new OtlpGrpcLogRecordExporterBuilder(builder.copy(), memoryMode); + return new OtlpGrpcLogRecordExporterBuilder(builder.copy(), marshaler.getMemoryMode()); } /** @@ -82,24 +78,7 @@ public OtlpGrpcLogRecordExporterBuilder toBuilder() { */ @Override public CompletableResultCode export(Collection logs) { - if (memoryMode == MemoryMode.REUSABLE_DATA) { - LowAllocationLogsRequestMarshaler marshaler = marshalerPool.poll(); - if (marshaler == null) { - marshaler = new LowAllocationLogsRequestMarshaler(); - } - LowAllocationLogsRequestMarshaler exportMarshaler = marshaler; - exportMarshaler.initialize(logs); - return delegate - .export(exportMarshaler, logs.size()) - .whenComplete( - () -> { - exportMarshaler.reset(); - marshalerPool.add(exportMarshaler); - }); - } - // MemoryMode == MemoryMode.IMMUTABLE_DATA - LogsRequestMarshaler request = LogsRequestMarshaler.create(logs); - return delegate.export(request, logs.size()); + return marshaler.export(logs); } @Override @@ -120,7 +99,7 @@ public CompletableResultCode shutdown() { public String toString() { StringJoiner joiner = new StringJoiner(", ", "OtlpGrpcLogRecordExporter{", "}"); joiner.add(builder.toString(false)); - joiner.add("memoryMode=" + memoryMode); + joiner.add("memoryMode=" + marshaler.getMemoryMode()); return joiner.toString(); } } diff --git a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcMetricExporter.java b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcMetricExporter.java index 1a9d3ed20e2..5dd48db4908 100644 --- a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcMetricExporter.java +++ b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcMetricExporter.java @@ -8,8 +8,7 @@ import io.opentelemetry.exporter.internal.grpc.GrpcExporter; import io.opentelemetry.exporter.internal.grpc.GrpcExporterBuilder; import io.opentelemetry.exporter.internal.marshal.Marshaler; -import io.opentelemetry.exporter.internal.otlp.metrics.LowAllocationMetricsRequestMarshaler; -import io.opentelemetry.exporter.internal.otlp.metrics.MetricsRequestMarshaler; +import io.opentelemetry.exporter.internal.otlp.metrics.MetricReusableDataMarshaler; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.export.MemoryMode; import io.opentelemetry.sdk.metrics.Aggregation; @@ -19,9 +18,7 @@ import io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector; import io.opentelemetry.sdk.metrics.export.DefaultAggregationSelector; import io.opentelemetry.sdk.metrics.export.MetricExporter; -import java.util.ArrayDeque; import java.util.Collection; -import java.util.Deque; import java.util.StringJoiner; import javax.annotation.concurrent.ThreadSafe; @@ -33,12 +30,11 @@ @ThreadSafe public final class OtlpGrpcMetricExporter implements MetricExporter { - private final Deque marshalerPool = new ArrayDeque<>(); private final GrpcExporterBuilder builder; private final GrpcExporter delegate; private final AggregationTemporalitySelector aggregationTemporalitySelector; private final DefaultAggregationSelector defaultAggregationSelector; - private final MemoryMode memoryMode; + private final MetricReusableDataMarshaler marshaler; /** * Returns a new {@link OtlpGrpcMetricExporter} using the default values. @@ -71,7 +67,7 @@ public static OtlpGrpcMetricExporterBuilder builder() { this.delegate = delegate; this.aggregationTemporalitySelector = aggregationTemporalitySelector; this.defaultAggregationSelector = defaultAggregationSelector; - this.memoryMode = memoryMode; + this.marshaler = new MetricReusableDataMarshaler(memoryMode, delegate::export); } /** @@ -82,7 +78,7 @@ public static OtlpGrpcMetricExporterBuilder builder() { * @since 1.29.0 */ public OtlpGrpcMetricExporterBuilder toBuilder() { - return new OtlpGrpcMetricExporterBuilder(builder.copy(), memoryMode); + return new OtlpGrpcMetricExporterBuilder(builder.copy(), marshaler.getMemoryMode()); } @Override @@ -97,7 +93,7 @@ public Aggregation getDefaultAggregation(InstrumentType instrumentType) { @Override public MemoryMode getMemoryMode() { - return memoryMode; + return marshaler.getMemoryMode(); } /** @@ -108,24 +104,7 @@ public MemoryMode getMemoryMode() { */ @Override public CompletableResultCode export(Collection metrics) { - if (memoryMode == MemoryMode.REUSABLE_DATA) { - LowAllocationMetricsRequestMarshaler marshaler = marshalerPool.poll(); - if (marshaler == null) { - marshaler = new LowAllocationMetricsRequestMarshaler(); - } - LowAllocationMetricsRequestMarshaler exportMarshaler = marshaler; - exportMarshaler.initialize(metrics); - return delegate - .export(exportMarshaler, metrics.size()) - .whenComplete( - () -> { - exportMarshaler.reset(); - marshalerPool.add(exportMarshaler); - }); - } - // MemoryMode == MemoryMode.IMMUTABLE_DATA - MetricsRequestMarshaler request = MetricsRequestMarshaler.create(metrics); - return delegate.export(request, metrics.size()); + return marshaler.export(metrics); } /** @@ -157,7 +136,7 @@ public String toString() { joiner.add( "defaultAggregationSelector=" + DefaultAggregationSelector.asString(defaultAggregationSelector)); - joiner.add("memoryMode=" + memoryMode); + joiner.add("memoryMode=" + marshaler.getMemoryMode()); return joiner.toString(); } } diff --git a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/trace/OtlpGrpcSpanExporter.java b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/trace/OtlpGrpcSpanExporter.java index a2c29d87bc1..6d0d3d2fffa 100644 --- a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/trace/OtlpGrpcSpanExporter.java +++ b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/trace/OtlpGrpcSpanExporter.java @@ -8,15 +8,12 @@ import io.opentelemetry.exporter.internal.grpc.GrpcExporter; import io.opentelemetry.exporter.internal.grpc.GrpcExporterBuilder; import io.opentelemetry.exporter.internal.marshal.Marshaler; -import io.opentelemetry.exporter.internal.otlp.traces.LowAllocationTraceRequestMarshaler; -import io.opentelemetry.exporter.internal.otlp.traces.TraceRequestMarshaler; +import io.opentelemetry.exporter.internal.otlp.traces.SpanReusableDataMarshaler; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.export.MemoryMode; import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.sdk.trace.export.SpanExporter; -import java.util.ArrayDeque; import java.util.Collection; -import java.util.Deque; import java.util.StringJoiner; import javax.annotation.concurrent.ThreadSafe; @@ -24,10 +21,9 @@ @ThreadSafe public final class OtlpGrpcSpanExporter implements SpanExporter { - private final Deque marshalerPool = new ArrayDeque<>(); private final GrpcExporterBuilder builder; private final GrpcExporter delegate; - private final MemoryMode memoryMode; + private final SpanReusableDataMarshaler marshaler; /** * Returns a new {@link OtlpGrpcSpanExporter} using the default values. @@ -56,7 +52,7 @@ public static OtlpGrpcSpanExporterBuilder builder() { MemoryMode memoryMode) { this.builder = builder; this.delegate = delegate; - this.memoryMode = memoryMode; + this.marshaler = new SpanReusableDataMarshaler(memoryMode, delegate::export); } /** @@ -67,7 +63,7 @@ public static OtlpGrpcSpanExporterBuilder builder() { * @since 1.29.0 */ public OtlpGrpcSpanExporterBuilder toBuilder() { - return new OtlpGrpcSpanExporterBuilder(builder.copy(), memoryMode); + return new OtlpGrpcSpanExporterBuilder(builder.copy(), marshaler.getMemoryMode()); } /** @@ -78,24 +74,7 @@ public OtlpGrpcSpanExporterBuilder toBuilder() { */ @Override public CompletableResultCode export(Collection spans) { - if (memoryMode == MemoryMode.REUSABLE_DATA) { - LowAllocationTraceRequestMarshaler marshaler = marshalerPool.poll(); - if (marshaler == null) { - marshaler = new LowAllocationTraceRequestMarshaler(); - } - LowAllocationTraceRequestMarshaler exportMarshaler = marshaler; - exportMarshaler.initialize(spans); - return delegate - .export(exportMarshaler, spans.size()) - .whenComplete( - () -> { - exportMarshaler.reset(); - marshalerPool.add(exportMarshaler); - }); - } - // MemoryMode == MemoryMode.IMMUTABLE_DATA - TraceRequestMarshaler request = TraceRequestMarshaler.create(spans); - return delegate.export(request, spans.size()); + return marshaler.export(spans); } /** @@ -121,7 +100,7 @@ public CompletableResultCode shutdown() { public String toString() { StringJoiner joiner = new StringJoiner(", ", "OtlpGrpcSpanExporter{", "}"); joiner.add(builder.toString(false)); - joiner.add("memoryMode=" + memoryMode); + joiner.add("memoryMode=" + marshaler.getMemoryMode()); return joiner.toString(); } } diff --git a/exporters/otlp/all/src/test/java/io/opentelemetry/exporter/otlp/internal/OtlpLogRecordExporterProviderTest.java b/exporters/otlp/all/src/test/java/io/opentelemetry/exporter/otlp/internal/OtlpLogRecordExporterProviderTest.java index 2f882b3ebfd..bab89d8a69a 100644 --- a/exporters/otlp/all/src/test/java/io/opentelemetry/exporter/otlp/internal/OtlpLogRecordExporterProviderTest.java +++ b/exporters/otlp/all/src/test/java/io/opentelemetry/exporter/otlp/internal/OtlpLogRecordExporterProviderTest.java @@ -30,6 +30,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import org.assertj.core.api.AbstractObjectAssert; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -128,11 +129,15 @@ void createExporter_GrpcDefaults() { verify(grpcBuilder, never()).setTrustedCertificates(any()); verify(grpcBuilder, never()).setClientTls(any(), any()); assertThat(grpcBuilder).extracting("delegate").extracting("retryPolicy").isNotNull(); - assertThat(exporter).extracting("memoryMode").isEqualTo(MemoryMode.IMMUTABLE_DATA); + getMemoryMode(exporter).isEqualTo(MemoryMode.IMMUTABLE_DATA); } Mockito.verifyNoInteractions(httpBuilder); } + private static AbstractObjectAssert getMemoryMode(LogRecordExporter exporter) { + return assertThat(exporter).extracting("marshaler").extracting("memoryMode"); + } + @Test void createExporter_GrpcWithGeneralConfiguration() throws CertificateEncodingException { Map config = new HashMap<>(); @@ -191,7 +196,7 @@ void createExporter_GrpcWithSignalConfiguration() throws CertificateEncodingExce verify(grpcBuilder).setTrustedCertificates(serverTls.certificate().getEncoded()); verify(grpcBuilder) .setClientTls(clientTls.privateKey().getEncoded(), clientTls.certificate().getEncoded()); - assertThat(exporter).extracting("memoryMode").isEqualTo(MemoryMode.REUSABLE_DATA); + getMemoryMode(exporter).isEqualTo(MemoryMode.REUSABLE_DATA); } Mockito.verifyNoInteractions(httpBuilder); } @@ -211,7 +216,7 @@ void createExporter_HttpDefaults() { verify(httpBuilder, never()).setTrustedCertificates(any()); verify(httpBuilder, never()).setClientTls(any(), any()); assertThat(httpBuilder).extracting("delegate").extracting("retryPolicy").isNotNull(); - assertThat(exporter).extracting("memoryMode").isEqualTo(MemoryMode.IMMUTABLE_DATA); + getMemoryMode(exporter).isEqualTo(MemoryMode.IMMUTABLE_DATA); } Mockito.verifyNoInteractions(grpcBuilder); } @@ -277,7 +282,7 @@ void createExporter_HttpWithSignalConfiguration() throws CertificateEncodingExce verify(httpBuilder).setTrustedCertificates(serverTls.certificate().getEncoded()); verify(httpBuilder) .setClientTls(clientTls.privateKey().getEncoded(), clientTls.certificate().getEncoded()); - assertThat(exporter).extracting("memoryMode").isEqualTo(MemoryMode.REUSABLE_DATA); + getMemoryMode(exporter).isEqualTo(MemoryMode.REUSABLE_DATA); } Mockito.verifyNoInteractions(grpcBuilder); } diff --git a/exporters/otlp/all/src/test/java/io/opentelemetry/exporter/otlp/internal/OtlpSpanExporterProviderTest.java b/exporters/otlp/all/src/test/java/io/opentelemetry/exporter/otlp/internal/OtlpSpanExporterProviderTest.java index 06d39054a0f..084826d47ff 100644 --- a/exporters/otlp/all/src/test/java/io/opentelemetry/exporter/otlp/internal/OtlpSpanExporterProviderTest.java +++ b/exporters/otlp/all/src/test/java/io/opentelemetry/exporter/otlp/internal/OtlpSpanExporterProviderTest.java @@ -30,6 +30,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import org.assertj.core.api.AbstractObjectAssert; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -129,11 +130,15 @@ void createExporter_GrpcDefaults() { verify(grpcBuilder, never()).setTrustedCertificates(any()); verify(grpcBuilder, never()).setClientTls(any(), any()); assertThat(grpcBuilder).extracting("delegate").extracting("retryPolicy").isNotNull(); - assertThat(exporter).extracting("memoryMode").isEqualTo(MemoryMode.IMMUTABLE_DATA); + getMemoryMode(exporter).isEqualTo(MemoryMode.IMMUTABLE_DATA); } Mockito.verifyNoInteractions(httpBuilder); } + private static AbstractObjectAssert getMemoryMode(SpanExporter exporter) { + return assertThat(exporter).extracting("marshaler").extracting("memoryMode"); + } + @Test void createExporter_GrpcWithGeneralConfiguration() throws CertificateEncodingException { Map config = new HashMap<>(); @@ -192,7 +197,7 @@ void createExporter_GrpcWithSignalConfiguration() throws CertificateEncodingExce verify(grpcBuilder).setTrustedCertificates(serverTls.certificate().getEncoded()); verify(grpcBuilder) .setClientTls(clientTls.privateKey().getEncoded(), clientTls.certificate().getEncoded()); - assertThat(exporter).extracting("memoryMode").isEqualTo(MemoryMode.REUSABLE_DATA); + getMemoryMode(exporter).isEqualTo(MemoryMode.REUSABLE_DATA); } Mockito.verifyNoInteractions(httpBuilder); } @@ -212,7 +217,7 @@ void createExporter_HttpDefaults() { verify(httpBuilder, never()).setTrustedCertificates(any()); verify(httpBuilder, never()).setClientTls(any(), any()); assertThat(httpBuilder).extracting("delegate").extracting("retryPolicy").isNotNull(); - assertThat(exporter).extracting("memoryMode").isEqualTo(MemoryMode.IMMUTABLE_DATA); + getMemoryMode(exporter).isEqualTo(MemoryMode.IMMUTABLE_DATA); } Mockito.verifyNoInteractions(grpcBuilder); } @@ -244,7 +249,7 @@ void createExporter_HttpWithGeneralConfiguration() throws CertificateEncodingExc verify(httpBuilder) .setClientTls(clientTls.privateKey().getEncoded(), clientTls.certificate().getEncoded()); assertThat(httpBuilder).extracting("delegate").extracting("retryPolicy").isNull(); - assertThat(exporter).extracting("memoryMode").isEqualTo(MemoryMode.IMMUTABLE_DATA); + getMemoryMode(exporter).isEqualTo(MemoryMode.IMMUTABLE_DATA); } Mockito.verifyNoInteractions(grpcBuilder); } @@ -281,7 +286,7 @@ void createExporter_HttpWithSignalConfiguration() throws CertificateEncodingExce verify(httpBuilder).setTrustedCertificates(serverTls.certificate().getEncoded()); verify(httpBuilder) .setClientTls(clientTls.privateKey().getEncoded(), clientTls.certificate().getEncoded()); - assertThat(exporter).extracting("memoryMode").isEqualTo(MemoryMode.REUSABLE_DATA); + getMemoryMode(exporter).isEqualTo(MemoryMode.REUSABLE_DATA); } Mockito.verifyNoInteractions(grpcBuilder); } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/logs/LogReusableDataMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/logs/LogReusableDataMarshaler.java new file mode 100644 index 00000000000..5f3fc50a5f5 --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/logs/LogReusableDataMarshaler.java @@ -0,0 +1,58 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.logs; + +import io.opentelemetry.exporter.internal.marshal.Marshaler; +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.common.export.MemoryMode; +import io.opentelemetry.sdk.logs.data.LogRecordData; +import java.util.ArrayDeque; +import java.util.Collection; +import java.util.Deque; +import java.util.function.BiFunction; + +/** + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. + */ +public class LogReusableDataMarshaler { + + private final Deque marshalerPool = new ArrayDeque<>(); + + private final MemoryMode memoryMode; + private final BiFunction doExport; + + public LogReusableDataMarshaler( + MemoryMode memoryMode, BiFunction doExport) { + this.memoryMode = memoryMode; + this.doExport = doExport; + } + + public MemoryMode getMemoryMode() { + return memoryMode; + } + + public CompletableResultCode export(Collection logs) { + if (memoryMode == MemoryMode.REUSABLE_DATA) { + LowAllocationLogsRequestMarshaler marshaler = marshalerPool.poll(); + if (marshaler == null) { + marshaler = new LowAllocationLogsRequestMarshaler(); + } + LowAllocationLogsRequestMarshaler exportMarshaler = marshaler; + exportMarshaler.initialize(logs); + return doExport + .apply(exportMarshaler, logs.size()) + .whenComplete( + () -> { + exportMarshaler.reset(); + marshalerPool.add(exportMarshaler); + }); + } + // MemoryMode == MemoryMode.IMMUTABLE_DATA + LogsRequestMarshaler request = LogsRequestMarshaler.create(logs); + return doExport.apply(request, logs.size()); + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/MetricReusableDataMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/MetricReusableDataMarshaler.java new file mode 100644 index 00000000000..c143e94fa5d --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/metrics/MetricReusableDataMarshaler.java @@ -0,0 +1,58 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.metrics; + +import io.opentelemetry.exporter.internal.marshal.Marshaler; +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.common.export.MemoryMode; +import io.opentelemetry.sdk.metrics.data.MetricData; +import java.util.ArrayDeque; +import java.util.Collection; +import java.util.Deque; +import java.util.function.BiFunction; + +/** + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. + */ +public class MetricReusableDataMarshaler { + + private final Deque marshalerPool = new ArrayDeque<>(); + + private final MemoryMode memoryMode; + private final BiFunction doExport; + + public MetricReusableDataMarshaler( + MemoryMode memoryMode, BiFunction doExport) { + this.memoryMode = memoryMode; + this.doExport = doExport; + } + + public MemoryMode getMemoryMode() { + return memoryMode; + } + + public CompletableResultCode export(Collection metrics) { + if (memoryMode == MemoryMode.REUSABLE_DATA) { + LowAllocationMetricsRequestMarshaler marshaler = marshalerPool.poll(); + if (marshaler == null) { + marshaler = new LowAllocationMetricsRequestMarshaler(); + } + LowAllocationMetricsRequestMarshaler exportMarshaler = marshaler; + exportMarshaler.initialize(metrics); + return doExport + .apply(exportMarshaler, metrics.size()) + .whenComplete( + () -> { + exportMarshaler.reset(); + marshalerPool.add(exportMarshaler); + }); + } + // MemoryMode == MemoryMode.IMMUTABLE_DATA + MetricsRequestMarshaler request = MetricsRequestMarshaler.create(metrics); + return doExport.apply(request, metrics.size()); + } +} diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanReusableDataMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanReusableDataMarshaler.java new file mode 100644 index 00000000000..af69e811c89 --- /dev/null +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/traces/SpanReusableDataMarshaler.java @@ -0,0 +1,58 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.internal.otlp.traces; + +import io.opentelemetry.exporter.internal.marshal.Marshaler; +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.common.export.MemoryMode; +import io.opentelemetry.sdk.trace.data.SpanData; +import java.util.ArrayDeque; +import java.util.Collection; +import java.util.Deque; +import java.util.function.BiFunction; + +/** + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. + */ +public class SpanReusableDataMarshaler { + + private final Deque marshalerPool = new ArrayDeque<>(); + + private final MemoryMode memoryMode; + private final BiFunction doExport; + + public SpanReusableDataMarshaler( + MemoryMode memoryMode, BiFunction doExport) { + this.memoryMode = memoryMode; + this.doExport = doExport; + } + + public MemoryMode getMemoryMode() { + return memoryMode; + } + + public CompletableResultCode export(Collection spans) { + if (memoryMode == MemoryMode.REUSABLE_DATA) { + LowAllocationTraceRequestMarshaler marshaler = marshalerPool.poll(); + if (marshaler == null) { + marshaler = new LowAllocationTraceRequestMarshaler(); + } + LowAllocationTraceRequestMarshaler exportMarshaler = marshaler; + exportMarshaler.initialize(spans); + return doExport + .apply(exportMarshaler, spans.size()) + .whenComplete( + () -> { + exportMarshaler.reset(); + marshalerPool.add(exportMarshaler); + }); + } + // MemoryMode == MemoryMode.IMMUTABLE_DATA + TraceRequestMarshaler request = TraceRequestMarshaler.create(spans); + return doExport.apply(request, spans.size()); + } +}