diff --git a/exporters/logging-otlp/src/test/java/io/opentelemetry/exporter/logging/otlp/OtlpJsonLoggingLogExporterTest.java b/exporters/logging-otlp/src/test/java/io/opentelemetry/exporter/logging/otlp/OtlpJsonLoggingLogExporterTest.java index 2c6ee03000..ab6aaefc51 100644 --- a/exporters/logging-otlp/src/test/java/io/opentelemetry/exporter/logging/otlp/OtlpJsonLoggingLogExporterTest.java +++ b/exporters/logging-otlp/src/test/java/io/opentelemetry/exporter/logging/otlp/OtlpJsonLoggingLogExporterTest.java @@ -14,6 +14,7 @@ import io.github.netmikey.logunit.api.LogCapturer; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; import io.opentelemetry.sdk.logs.data.LogData; +import io.opentelemetry.sdk.logs.data.LogDataBuilder; import io.opentelemetry.sdk.logs.data.Severity; import io.opentelemetry.sdk.logs.export.LogExporter; import io.opentelemetry.sdk.resources.Resource; @@ -31,7 +32,7 @@ class OtlpJsonLoggingLogExporterTest { Resource.create(Attributes.builder().put("key", "value").build()); private static final LogData LOG1 = - LogData.builder(RESOURCE, InstrumentationLibraryInfo.create("instrumentation", "1")) + LogDataBuilder.create(RESOURCE, InstrumentationLibraryInfo.create("instrumentation", "1")) .setName("testLog1") .setBody("body1") .setFlags(0) @@ -44,7 +45,7 @@ class OtlpJsonLoggingLogExporterTest { .build(); private static final LogData LOG2 = - LogData.builder(RESOURCE, InstrumentationLibraryInfo.create("instrumentation2", "2")) + LogDataBuilder.create(RESOURCE, InstrumentationLibraryInfo.create("instrumentation2", "2")) .setName("testLog2") .setBody("body2") .setFlags(0) diff --git a/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/SystemOutLogExporterTest.java b/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/SystemOutLogExporterTest.java index b124809ead..72a153b6e3 100644 --- a/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/SystemOutLogExporterTest.java +++ b/exporters/logging/src/test/java/io/opentelemetry/exporter/logging/SystemOutLogExporterTest.java @@ -17,6 +17,7 @@ import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; import io.opentelemetry.sdk.logs.data.Body; import io.opentelemetry.sdk.logs.data.LogData; +import io.opentelemetry.sdk.logs.data.LogDataBuilder; import io.opentelemetry.sdk.logs.data.Severity; import io.opentelemetry.sdk.resources.Resource; import java.time.LocalDateTime; @@ -50,7 +51,8 @@ class SystemOutLogExporterTest { } private static LogData sampleLog(long timestamp) { - return LogData.builder(Resource.empty(), InstrumentationLibraryInfo.create("logTest", "1.0")) + return LogDataBuilder.create( + Resource.empty(), InstrumentationLibraryInfo.create("logTest", "1.0")) .setAttributes(Attributes.of(stringKey("cheese"), "cheddar", longKey("amount"), 1L)) .setBody(Body.stringBody("message")) .setSeverity(Severity.ERROR3) diff --git a/exporters/otlp-http/logs/src/test/java/io/opentelemetry/exporter/otlp/http/logs/OtlpHttpLogExporterTest.java b/exporters/otlp-http/logs/src/test/java/io/opentelemetry/exporter/otlp/http/logs/OtlpHttpLogExporterTest.java index 4dfa184c04..672857b4ed 100644 --- a/exporters/otlp-http/logs/src/test/java/io/opentelemetry/exporter/otlp/http/logs/OtlpHttpLogExporterTest.java +++ b/exporters/otlp-http/logs/src/test/java/io/opentelemetry/exporter/otlp/http/logs/OtlpHttpLogExporterTest.java @@ -31,6 +31,7 @@ import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; import io.opentelemetry.sdk.logs.data.Body; import io.opentelemetry.sdk.logs.data.LogData; +import io.opentelemetry.sdk.logs.data.LogDataBuilder; import io.opentelemetry.sdk.logs.data.Severity; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.IdGenerator; @@ -318,7 +319,7 @@ class OtlpHttpLogExporterTest { } private static LogData generateFakeLog() { - return LogData.builder( + return LogDataBuilder.create( Resource.getDefault(), InstrumentationLibraryInfo.create("testLib", "1.0", "http://url")) .setName("log-name") diff --git a/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/otlp/internal/logs/LogsRequestMarshalerTest.java b/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/otlp/internal/logs/LogsRequestMarshalerTest.java index e9dbca9653..4c152db700 100644 --- a/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/otlp/internal/logs/LogsRequestMarshalerTest.java +++ b/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/otlp/internal/logs/LogsRequestMarshalerTest.java @@ -24,7 +24,7 @@ import io.opentelemetry.proto.logs.v1.InstrumentationLibraryLogs; import io.opentelemetry.proto.logs.v1.LogRecord; import io.opentelemetry.proto.logs.v1.ResourceLogs; import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; -import io.opentelemetry.sdk.logs.data.LogData; +import io.opentelemetry.sdk.logs.data.LogDataBuilder; import io.opentelemetry.sdk.logs.data.Severity; import io.opentelemetry.sdk.resources.Resource; import java.io.ByteArrayOutputStream; @@ -51,7 +51,7 @@ class LogsRequestMarshalerTest { ResourceLogsMarshaler[] resourceLogsMarshalers = ResourceLogsMarshaler.create( Collections.singleton( - LogData.builder( + LogDataBuilder.create( Resource.builder().put("one", 1).setSchemaUrl("http://url").build(), InstrumentationLibraryInfo.create("testLib", "1.0", "http://url")) .setName(NAME) @@ -84,7 +84,7 @@ class LogsRequestMarshalerTest { parse( LogRecord.getDefaultInstance(), LogMarshaler.create( - LogData.builder( + LogDataBuilder.create( Resource.create(Attributes.builder().put("testKey", "testValue").build()), InstrumentationLibraryInfo.create("instrumentation", "1")) .setName(NAME) @@ -117,7 +117,7 @@ class LogsRequestMarshalerTest { parse( LogRecord.getDefaultInstance(), LogMarshaler.create( - LogData.builder( + LogDataBuilder.create( Resource.create(Attributes.builder().put("testKey", "testValue").build()), InstrumentationLibraryInfo.create("instrumentation", "1")) .setBody(BODY) diff --git a/exporters/otlp/logs/src/test/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcLogsExporterTest.java b/exporters/otlp/logs/src/test/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcLogsExporterTest.java index 1fd2d5e54e..16ebf8623b 100644 --- a/exporters/otlp/logs/src/test/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcLogsExporterTest.java +++ b/exporters/otlp/logs/src/test/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcLogsExporterTest.java @@ -33,6 +33,7 @@ import io.opentelemetry.proto.logs.v1.ResourceLogs; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; import io.opentelemetry.sdk.logs.data.LogData; +import io.opentelemetry.sdk.logs.data.LogDataBuilder; import io.opentelemetry.sdk.logs.data.Severity; import io.opentelemetry.sdk.resources.Resource; import java.io.ByteArrayOutputStream; @@ -368,7 +369,7 @@ class OtlpGrpcLogsExporterTest { } private static LogData generateFakeLog() { - return LogData.builder( + return LogDataBuilder.create( Resource.create(Attributes.builder().put("testKey", "testValue").build()), InstrumentationLibraryInfo.create("instrumentation", "1")) .setEpoch(Instant.now()) diff --git a/exporters/otlp/logs/src/testGrpcNetty/java/io/opentelemetry/exporter/otlp/logs/ExportTest.java b/exporters/otlp/logs/src/testGrpcNetty/java/io/opentelemetry/exporter/otlp/logs/ExportTest.java index cfb4411b0f..a55c3bc468 100644 --- a/exporters/otlp/logs/src/testGrpcNetty/java/io/opentelemetry/exporter/otlp/logs/ExportTest.java +++ b/exporters/otlp/logs/src/testGrpcNetty/java/io/opentelemetry/exporter/otlp/logs/ExportTest.java @@ -23,6 +23,7 @@ import io.opentelemetry.proto.collector.logs.v1.ExportLogsServiceResponse; import io.opentelemetry.proto.collector.logs.v1.LogsServiceGrpc; import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; import io.opentelemetry.sdk.logs.data.LogData; +import io.opentelemetry.sdk.logs.data.LogDataBuilder; import io.opentelemetry.sdk.logs.data.Severity; import io.opentelemetry.sdk.resources.Resource; import java.nio.charset.StandardCharsets; @@ -39,7 +40,7 @@ class ExportTest { private static final List LOGS = Collections.singletonList( - LogData.builder( + LogDataBuilder.create( Resource.create(Attributes.builder().put("testKey", "testValue").build()), InstrumentationLibraryInfo.create("instrumentation", "1")) .setEpoch(Instant.now()) diff --git a/exporters/otlp/logs/src/testGrpcNettyShaded/java/io/opentelemetry/exporter/otlp/logs/ExportTest.java b/exporters/otlp/logs/src/testGrpcNettyShaded/java/io/opentelemetry/exporter/otlp/logs/ExportTest.java index cfb4411b0f..a55c3bc468 100644 --- a/exporters/otlp/logs/src/testGrpcNettyShaded/java/io/opentelemetry/exporter/otlp/logs/ExportTest.java +++ b/exporters/otlp/logs/src/testGrpcNettyShaded/java/io/opentelemetry/exporter/otlp/logs/ExportTest.java @@ -23,6 +23,7 @@ import io.opentelemetry.proto.collector.logs.v1.ExportLogsServiceResponse; import io.opentelemetry.proto.collector.logs.v1.LogsServiceGrpc; import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; import io.opentelemetry.sdk.logs.data.LogData; +import io.opentelemetry.sdk.logs.data.LogDataBuilder; import io.opentelemetry.sdk.logs.data.Severity; import io.opentelemetry.sdk.resources.Resource; import java.nio.charset.StandardCharsets; @@ -39,7 +40,7 @@ class ExportTest { private static final List LOGS = Collections.singletonList( - LogData.builder( + LogDataBuilder.create( Resource.create(Attributes.builder().put("testKey", "testValue").build()), InstrumentationLibraryInfo.create("instrumentation", "1")) .setEpoch(Instant.now()) diff --git a/exporters/otlp/logs/src/testGrpcOkhttp/java/io/opentelemetry/exporter/otlp/logs/ExportTest.java b/exporters/otlp/logs/src/testGrpcOkhttp/java/io/opentelemetry/exporter/otlp/logs/ExportTest.java index cfb4411b0f..a55c3bc468 100644 --- a/exporters/otlp/logs/src/testGrpcOkhttp/java/io/opentelemetry/exporter/otlp/logs/ExportTest.java +++ b/exporters/otlp/logs/src/testGrpcOkhttp/java/io/opentelemetry/exporter/otlp/logs/ExportTest.java @@ -23,6 +23,7 @@ import io.opentelemetry.proto.collector.logs.v1.ExportLogsServiceResponse; import io.opentelemetry.proto.collector.logs.v1.LogsServiceGrpc; import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; import io.opentelemetry.sdk.logs.data.LogData; +import io.opentelemetry.sdk.logs.data.LogDataBuilder; import io.opentelemetry.sdk.logs.data.Severity; import io.opentelemetry.sdk.resources.Resource; import java.nio.charset.StandardCharsets; @@ -39,7 +40,7 @@ class ExportTest { private static final List LOGS = Collections.singletonList( - LogData.builder( + LogDataBuilder.create( Resource.create(Attributes.builder().put("testKey", "testValue").build()), InstrumentationLibraryInfo.create("instrumentation", "1")) .setEpoch(Instant.now()) diff --git a/exporters/otlp/logs/src/testOkHttpOnly/java/io/opentelemetry/exporter/otlp/logs/OkHttpOnlyExportTest.java b/exporters/otlp/logs/src/testOkHttpOnly/java/io/opentelemetry/exporter/otlp/logs/OkHttpOnlyExportTest.java index e604ff6556..7d7e2dea61 100644 --- a/exporters/otlp/logs/src/testOkHttpOnly/java/io/opentelemetry/exporter/otlp/logs/OkHttpOnlyExportTest.java +++ b/exporters/otlp/logs/src/testOkHttpOnly/java/io/opentelemetry/exporter/otlp/logs/OkHttpOnlyExportTest.java @@ -20,6 +20,7 @@ import io.opentelemetry.exporter.otlp.internal.grpc.OkHttpGrpcExporterBuilder; import io.opentelemetry.proto.collector.logs.v1.ExportLogsServiceResponse; import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; import io.opentelemetry.sdk.logs.data.LogData; +import io.opentelemetry.sdk.logs.data.LogDataBuilder; import io.opentelemetry.sdk.logs.data.Severity; import io.opentelemetry.sdk.resources.Resource; import java.net.InetAddress; @@ -40,7 +41,7 @@ class OkHttpOnlyExportTest { private static final List LOGS = Collections.singletonList( - LogData.builder( + LogDataBuilder.create( Resource.create(Attributes.builder().put("testKey", "testValue").build()), InstrumentationLibraryInfo.create("instrumentation", "1")) .setEpoch(Instant.now()) diff --git a/integration-tests/src/testOtlpCommon/java/io/opentelemetry/integrationtest/OtlpExporterIntegrationTest.java b/integration-tests/src/testOtlpCommon/java/io/opentelemetry/integrationtest/OtlpExporterIntegrationTest.java index 59c1378332..d007f9630f 100644 --- a/integration-tests/src/testOtlpCommon/java/io/opentelemetry/integrationtest/OtlpExporterIntegrationTest.java +++ b/integration-tests/src/testOtlpCommon/java/io/opentelemetry/integrationtest/OtlpExporterIntegrationTest.java @@ -53,6 +53,7 @@ import io.opentelemetry.proto.trace.v1.Span.Link; import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; import io.opentelemetry.sdk.logs.data.Body; import io.opentelemetry.sdk.logs.data.LogData; +import io.opentelemetry.sdk.logs.data.LogDataBuilder; import io.opentelemetry.sdk.logs.data.Severity; import io.opentelemetry.sdk.logs.export.LogExporter; import io.opentelemetry.sdk.metrics.SdkMeterProvider; @@ -375,7 +376,7 @@ abstract class OtlpExporterIntegrationTest { private static void testLogExporter(LogExporter logExporter) { LogData logData = - LogData.builder( + LogDataBuilder.create( RESOURCE, InstrumentationLibraryInfo.create( OtlpExporterIntegrationTest.class.getName(), null)) diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogEmitterSharedState.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogEmitterSharedState.java index 59349debb7..9abcbf834c 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogEmitterSharedState.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogEmitterSharedState.java @@ -5,6 +5,7 @@ package io.opentelemetry.sdk.logs; +import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.resources.Resource; import java.util.List; @@ -18,11 +19,13 @@ final class LogEmitterSharedState { private final Object lock = new Object(); private final Resource resource; private final LogProcessor logProcessor; + private final Clock clock; @Nullable private volatile CompletableResultCode shutdownResult = null; - LogEmitterSharedState(Resource resource, List logProcessors) { + LogEmitterSharedState(Resource resource, List logProcessors, Clock clock) { this.resource = resource; this.logProcessor = LogProcessor.composite(logProcessors); + this.clock = clock; } Resource getResource() { @@ -33,6 +36,10 @@ final class LogEmitterSharedState { return logProcessor; } + Clock getClock() { + return clock; + } + boolean hasBeenShutdown() { return shutdownResult != null; } diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogBuilder.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogBuilder.java new file mode 100644 index 0000000000..9a2d1e2af3 --- /dev/null +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogBuilder.java @@ -0,0 +1,99 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.logs; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.sdk.logs.data.Body; +import io.opentelemetry.sdk.logs.data.LogDataBuilder; +import io.opentelemetry.sdk.logs.data.Severity; +import java.time.Instant; +import java.util.concurrent.TimeUnit; + +/** {@link SdkLogBuilder} is the SDK implementation of {@link LogBuilder}. */ +final class SdkLogBuilder implements LogBuilder { + + private final LogDataBuilder logDataBuilder; + private final LogEmitterSharedState logEmitterSharedState; + + SdkLogBuilder(LogEmitterSharedState logEmitterSharedState, LogDataBuilder logDataBuilder) { + this.logEmitterSharedState = logEmitterSharedState; + this.logDataBuilder = logDataBuilder; + } + + @Override + public LogBuilder setEpoch(long timestamp, TimeUnit unit) { + logDataBuilder.setEpoch(timestamp, unit); + return this; + } + + @Override + public LogBuilder setEpoch(Instant instant) { + logDataBuilder.setEpoch(instant); + return this; + } + + @Override + public LogBuilder setTraceId(String traceId) { + logDataBuilder.setTraceId(traceId); + return this; + } + + @Override + public LogBuilder setSpanId(String spanId) { + logDataBuilder.setSpanId(spanId); + return this; + } + + @Override + public LogBuilder setFlags(int flags) { + logDataBuilder.setFlags(flags); + return this; + } + + @Override + public LogBuilder setSeverity(Severity severity) { + logDataBuilder.setSeverity(severity); + return this; + } + + @Override + public LogBuilder setSeverityText(String severityText) { + logDataBuilder.setSeverityText(severityText); + return this; + } + + @Override + public LogBuilder setName(String name) { + logDataBuilder.setName(name); + return this; + } + + @Override + public LogBuilder setBody(Body body) { + logDataBuilder.setBody(body); + return this; + } + + @Override + public LogBuilder setBody(String body) { + logDataBuilder.setBody(body); + return this; + } + + @Override + public LogBuilder setAttributes(Attributes attributes) { + logDataBuilder.setAttributes(attributes); + return this; + } + + @Override + public void emit() { + if (logEmitterSharedState.hasBeenShutdown()) { + return; + } + logEmitterSharedState.getLogProcessor().emit(logDataBuilder.build()); + } +} diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogEmitter.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogEmitter.java index 6d1ca7bf2b..7acf71336a 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogEmitter.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogEmitter.java @@ -5,14 +5,8 @@ package io.opentelemetry.sdk.logs; -import io.opentelemetry.api.common.Attributes; import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; -import io.opentelemetry.sdk.logs.data.Body; -import io.opentelemetry.sdk.logs.data.LogData; import io.opentelemetry.sdk.logs.data.LogDataBuilder; -import io.opentelemetry.sdk.logs.data.Severity; -import java.time.Instant; -import java.util.concurrent.TimeUnit; /** SDK implementation of {@link LogEmitter}. */ final class SdkLogEmitter implements LogEmitter { @@ -29,95 +23,16 @@ final class SdkLogEmitter implements LogEmitter { @Override public LogBuilder logBuilder() { - return new SdkLogBuilder(); + LogDataBuilder logDataBuilder = + LogDataBuilder.create( + logEmitterSharedState.getResource(), + instrumentationLibraryInfo, + logEmitterSharedState.getClock()); + return new SdkLogBuilder(logEmitterSharedState, logDataBuilder); } // VisibleForTesting InstrumentationLibraryInfo getInstrumentationLibraryInfo() { return instrumentationLibraryInfo; } - - private final class SdkLogBuilder implements LogBuilder { - - private final LogDataBuilder logDataBuilder; - - SdkLogBuilder() { - this.logDataBuilder = - LogData.builder(logEmitterSharedState.getResource(), instrumentationLibraryInfo); - } - - @Override - public LogBuilder setEpoch(long timestamp, TimeUnit unit) { - logDataBuilder.setEpoch(timestamp, unit); - return this; - } - - @Override - public LogBuilder setEpoch(Instant instant) { - logDataBuilder.setEpoch(instant); - return this; - } - - @Override - public LogBuilder setTraceId(String traceId) { - logDataBuilder.setTraceId(traceId); - return this; - } - - @Override - public LogBuilder setSpanId(String spanId) { - logDataBuilder.setSpanId(spanId); - return this; - } - - @Override - public LogBuilder setFlags(int flags) { - logDataBuilder.setFlags(flags); - return this; - } - - @Override - public LogBuilder setSeverity(Severity severity) { - logDataBuilder.setSeverity(severity); - return this; - } - - @Override - public LogBuilder setSeverityText(String severityText) { - logDataBuilder.setSeverityText(severityText); - return this; - } - - @Override - public LogBuilder setName(String name) { - logDataBuilder.setName(name); - return this; - } - - @Override - public LogBuilder setBody(Body body) { - logDataBuilder.setBody(body); - return this; - } - - @Override - public LogBuilder setBody(String body) { - logDataBuilder.setBody(body); - return this; - } - - @Override - public LogBuilder setAttributes(Attributes attributes) { - logDataBuilder.setAttributes(attributes); - return this; - } - - @Override - public void emit() { - if (logEmitterSharedState.hasBeenShutdown()) { - return; - } - logEmitterSharedState.getLogProcessor().emit(logDataBuilder.build()); - } - } } diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogEmitterProvider.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogEmitterProvider.java index a963606f75..95e55ea3fb 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogEmitterProvider.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogEmitterProvider.java @@ -5,6 +5,7 @@ package io.opentelemetry.sdk.logs; +import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.internal.ComponentRegistry; import io.opentelemetry.sdk.resources.Resource; @@ -32,8 +33,8 @@ public final class SdkLogEmitterProvider implements Closeable { return new SdkLogEmitterProviderBuilder(); } - SdkLogEmitterProvider(Resource resource, List processors) { - this.sharedState = new LogEmitterSharedState(resource, processors); + SdkLogEmitterProvider(Resource resource, List processors, Clock clock) { + this.sharedState = new LogEmitterSharedState(resource, processors, clock); this.logEmitterComponentRegistry = new ComponentRegistry<>( instrumentationLibraryInfo -> diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogEmitterProviderBuilder.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogEmitterProviderBuilder.java index 9b638dba1a..909d38c5b5 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogEmitterProviderBuilder.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogEmitterProviderBuilder.java @@ -7,6 +7,7 @@ package io.opentelemetry.sdk.logs; import static java.util.Objects.requireNonNull; +import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.logs.data.LogData; import io.opentelemetry.sdk.resources.Resource; import java.util.ArrayList; @@ -17,6 +18,7 @@ public final class SdkLogEmitterProviderBuilder { private final List logProcessors = new ArrayList<>(); private Resource resource = Resource.getDefault(); + private Clock clock = Clock.getDefault(); SdkLogEmitterProviderBuilder() {} @@ -46,12 +48,28 @@ public final class SdkLogEmitterProviderBuilder { return this; } + /** + * Assign a {@link Clock}. The {@link Clock} may be used to determine "now" in the event that the + * epoch millis are not set directly. + * + *

The {@code clock} must be thread-safe and return immediately (no remote calls, as contention + * free as possible). + * + * @param clock The clock to use for all temporal needs. + * @return this + */ + public SdkLogEmitterProviderBuilder setClock(Clock clock) { + requireNonNull(clock, "clock"); + this.clock = clock; + return this; + } + /** * Create a {@link SdkLogEmitterProvider} instance. * * @return an instance configured with the provided options */ public SdkLogEmitterProvider build() { - return new SdkLogEmitterProvider(resource, logProcessors); + return new SdkLogEmitterProvider(resource, logProcessors, clock); } } diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/LogData.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/LogData.java index 61d6d74b71..8f79dcac03 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/LogData.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/LogData.java @@ -19,12 +19,6 @@ import javax.annotation.concurrent.Immutable; @Immutable public interface LogData { - /** Returns a new {@link LogDataBuilder}. */ - static LogDataBuilder builder( - Resource resource, InstrumentationLibraryInfo instrumentationLibraryInfo) { - return new LogDataBuilder(resource, instrumentationLibraryInfo); - } - /** Returns the resource of this log. */ Resource getResource(); diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/LogDataBuilder.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/LogDataBuilder.java index 7084c8f426..52ad7d2c23 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/LogDataBuilder.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/LogDataBuilder.java @@ -7,6 +7,7 @@ package io.opentelemetry.sdk.logs.data; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.common.AttributesBuilder; +import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; import io.opentelemetry.sdk.resources.Resource; import java.time.Instant; @@ -27,11 +28,26 @@ public final class LogDataBuilder { @Nullable private String severityText; @Nullable private String name; private Body body = Body.stringBody(""); + private final Clock clock; private final AttributesBuilder attributeBuilder = Attributes.builder(); - LogDataBuilder(Resource resource, InstrumentationLibraryInfo instrumentationLibraryInfo) { + private LogDataBuilder( + Resource resource, InstrumentationLibraryInfo instrumentationLibraryInfo, Clock clock) { this.resource = resource; this.instrumentationLibraryInfo = instrumentationLibraryInfo; + this.clock = clock; + } + + /** Returns a new {@link LogDataBuilder} with the default clock. */ + public static LogDataBuilder create( + Resource resource, InstrumentationLibraryInfo instrumentationLibraryInfo) { + return create(resource, instrumentationLibraryInfo, Clock.getDefault()); + } + + /** Returns a new {@link LogDataBuilder}. */ + public static LogDataBuilder create( + Resource resource, InstrumentationLibraryInfo instrumentationLibraryInfo, Clock clock) { + return new LogDataBuilder(resource, instrumentationLibraryInfo, clock); } /** Set the epoch timestamp using the timestamp and unit. */ @@ -102,7 +118,7 @@ public final class LogDataBuilder { /** Build a {@link LogData} instance from the configured properties. */ public LogData build() { if (epochNanos == 0) { - epochNanos = TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis()); + epochNanos = clock.now(); } return LogDataImpl.create( resource, diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LogEmitterSharedStateTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LogEmitterSharedStateTest.java new file mode 100644 index 0000000000..61d67a9aef --- /dev/null +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LogEmitterSharedStateTest.java @@ -0,0 +1,31 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.logs; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import io.opentelemetry.sdk.common.CompletableResultCode; +import java.util.Collections; +import java.util.List; +import org.junit.jupiter.api.Test; + +class LogEmitterSharedStateTest { + + @Test + void shutdown() { + LogProcessor logProcessor = mock(LogProcessor.class); + CompletableResultCode code = new CompletableResultCode(); + when(logProcessor.shutdown()).thenReturn(code); + List processors = Collections.singletonList(logProcessor); + LogEmitterSharedState state = new LogEmitterSharedState(null, processors, null); + state.shutdown(); + state.shutdown(); + verify(logProcessor, times(1)).shutdown(); + } +} diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogBuilderTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogBuilderTest.java new file mode 100644 index 0000000000..d99148eb09 --- /dev/null +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogBuilderTest.java @@ -0,0 +1,88 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.logs; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.when; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.sdk.logs.data.Body; +import io.opentelemetry.sdk.logs.data.LogData; +import io.opentelemetry.sdk.logs.data.LogDataBuilder; +import io.opentelemetry.sdk.logs.data.Severity; +import java.time.Instant; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import org.junit.jupiter.api.Test; + +class SdkLogBuilderTest { + + @Test + void buildAndEmit() { + Instant now = Instant.now(); + String name = "skippy"; + String bodyStr = "body"; + String spanId = "abc123"; + String traceId = "99321"; + int flags = 21; + String sevText = "sevText"; + Severity severity = Severity.DEBUG3; + Attributes attrs = Attributes.empty(); + AtomicReference seenLog = new AtomicReference<>(); + LogProcessor logProcessor = seenLog::set; + + LogEmitterSharedState state = mock(LogEmitterSharedState.class); + LogDataBuilder delegate = mock(LogDataBuilder.class); + LogData logData = mock(LogData.class); + Body body = mock(Body.class); + + when(state.getLogProcessor()).thenReturn(logProcessor); + when(delegate.build()).thenReturn(logData); + + SdkLogBuilder builder = new SdkLogBuilder(state, delegate); + builder.setBody(body); + verify(delegate).setBody(body); + builder.setBody(bodyStr); + verify(delegate).setBody(bodyStr); + builder.setEpoch(123, TimeUnit.SECONDS); + verify(delegate).setEpoch(123, TimeUnit.SECONDS); + builder.setEpoch(now); + verify(delegate).setEpoch(now); + builder.setAttributes(attrs); + verify(delegate).setAttributes(attrs); + builder.setFlags(flags); + verify(delegate).setFlags(flags); + builder.setName(name); + verify(delegate).setName(name); + builder.setSeverity(severity); + verify(delegate).setSeverity(severity); + builder.setSeverityText(sevText); + verify(delegate).setSeverityText(sevText); + builder.setSpanId(spanId); + verify(delegate).setSpanId(spanId); + builder.setTraceId(traceId); + verify(delegate).setTraceId(traceId); + builder.emit(); + assertThat(seenLog.get()).isSameAs(logData); + } + + @Test + void emitAfterShutdown() { + LogEmitterSharedState state = mock(LogEmitterSharedState.class); + LogDataBuilder delegate = mock(LogDataBuilder.class); + + when(state.hasBeenShutdown()).thenReturn(true); + + SdkLogBuilder builder = new SdkLogBuilder(state, delegate); + builder.emit(); + verify(state, never()).getLogProcessor(); + verifyNoInteractions(delegate); + } +} diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogEmitterProviderBuilderTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogEmitterProviderBuilderTest.java new file mode 100644 index 0000000000..c957c203e3 --- /dev/null +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogEmitterProviderBuilderTest.java @@ -0,0 +1,41 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.logs; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import io.opentelemetry.sdk.common.Clock; +import io.opentelemetry.sdk.logs.data.LogData; +import io.opentelemetry.sdk.resources.Resource; +import java.util.LinkedList; +import java.util.List; +import org.junit.jupiter.api.Test; + +class SdkLogEmitterProviderBuilderTest { + + @Test + void canSetClock() { + Clock clock = mock(Clock.class); + when(clock.now()).thenReturn(13L); + + List seenLogs = new LinkedList<>(); + + LogProcessor processor = seenLogs::add; + + SdkLogEmitterProviderBuilder builder = + new SdkLogEmitterProviderBuilder() + .setResource(Resource.getDefault()) + .addLogProcessor(processor) + .setClock(clock); + + SdkLogEmitterProvider provider = builder.build(); + provider.logEmitterBuilder("inst").build().logBuilder().emit(); + assertThat(seenLogs.size()).isEqualTo(1); + assertThat(seenLogs.get(0).getEpochNanos()).isEqualTo(13L); + } +} diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogEmitterProviderTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogEmitterProviderTest.java index 32b05de273..6ef05c45ef 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogEmitterProviderTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogEmitterProviderTest.java @@ -7,14 +7,20 @@ package io.opentelemetry.sdk.logs; import static org.assertj.core.api.Assertions.as; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; +import io.opentelemetry.sdk.logs.data.LogData; import io.opentelemetry.sdk.resources.Resource; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.TimeUnit; import org.assertj.core.api.InstanceOfAssertFactories; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -179,4 +185,18 @@ class SdkLogEmitterProviderTest { sdkLogEmitterProvider.close(); verify(logProcessor).shutdown(); } + + @Test + void canSetClock() { + long now = TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis()); + Clock clock = mock(Clock.class); + when(clock.now()).thenReturn(now); + List seenLogs = new LinkedList<>(); + logProcessor = seenLogs::add; + sdkLogEmitterProvider = + SdkLogEmitterProvider.builder().setClock(clock).addLogProcessor(logProcessor).build(); + sdkLogEmitterProvider.logEmitterBuilder(null).build().logBuilder().emit(); + assertThat(seenLogs.size()).isEqualTo(1); + assertThat(seenLogs.get(0).getEpochNanos()).isEqualTo(now); + } } diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogEmitterTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogEmitterTest.java index ba21710852..a287f1d5f7 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogEmitterTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogEmitterTest.java @@ -6,75 +6,36 @@ package io.opentelemetry.sdk.logs; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; -import io.opentelemetry.sdk.logs.data.Body; import io.opentelemetry.sdk.logs.data.LogData; import io.opentelemetry.sdk.resources.Resource; import java.time.Instant; -import java.util.concurrent.TimeUnit; -import org.junit.jupiter.api.BeforeEach; +import java.util.concurrent.atomic.AtomicReference; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.mockito.junit.jupiter.MockitoSettings; -import org.mockito.quality.Strictness; -@ExtendWith(MockitoExtension.class) -@MockitoSettings(strictness = Strictness.LENIENT) class SdkLogEmitterTest { - private static final String INSTRUMENTATION_LIBRARY_NAME = SdkLogEmitter.class.getName(); - private static final String INSTRUMENTATION_LIBRARY_VERSION = "0.0.1"; - private static final String SCHEMA_URL = "http://schemaurl"; - - @Mock private LogProcessor logProcessor; - private SdkLogEmitterProvider sdkLogEmitterProvider; - private LogEmitter sdkLogEmitter; - - @BeforeEach - void setup() { - when(logProcessor.shutdown()).thenReturn(CompletableResultCode.ofSuccess()); - sdkLogEmitterProvider = SdkLogEmitterProvider.builder().addLogProcessor(logProcessor).build(); - sdkLogEmitter = - sdkLogEmitterProvider - .logEmitterBuilder(INSTRUMENTATION_LIBRARY_NAME) - .setInstrumentationVersion(INSTRUMENTATION_LIBRARY_VERSION) - .setSchemaUrl(SCHEMA_URL) - .build(); - } - @Test - void emit() { - long epochMillis = System.currentTimeMillis(); - Body body = Body.stringBody("message"); - sdkLogEmitter.logBuilder().setEpoch(epochMillis, TimeUnit.MILLISECONDS).setBody(body).emit(); + void logBuilder() { + Instant now = Instant.now(); + LogEmitterSharedState state = mock(LogEmitterSharedState.class); + InstrumentationLibraryInfo info = InstrumentationLibraryInfo.create("foo", "bar"); + AtomicReference seenLog = new AtomicReference<>(); + LogProcessor logProcessor = seenLog::set; - ArgumentCaptor captor = ArgumentCaptor.forClass(LogData.class); - verify(logProcessor).emit(captor.capture()); + when(state.getResource()).thenReturn(Resource.getDefault()); + when(state.getLogProcessor()).thenReturn(logProcessor); - LogData logData = captor.getValue(); - assertThat(logData.getResource()).isEqualTo(Resource.getDefault()); - assertThat(logData.getInstrumentationLibraryInfo()) - .isEqualTo( - InstrumentationLibraryInfo.create( - INSTRUMENTATION_LIBRARY_NAME, INSTRUMENTATION_LIBRARY_VERSION, SCHEMA_URL)); - assertThat(logData.getEpochNanos()).isEqualTo(TimeUnit.MILLISECONDS.toNanos(epochMillis)); - assertThat(logData.getBody()).isEqualTo(body); - } + SdkLogEmitter emitter = new SdkLogEmitter(state, info); + LogBuilder logBuilder = emitter.logBuilder(); + logBuilder.setEpoch(now); + logBuilder.setBody("foo"); - @Test - void emit_AfterShutdown() { - sdkLogEmitterProvider.shutdown().join(10, TimeUnit.SECONDS); - - sdkLogEmitter.logBuilder().setEpoch(Instant.now()).setBody("message").emit(); - verify(logProcessor, never()).emit(any()); + // Have to test through the builder + logBuilder.emit(); + assertThat(seenLog.get().getBody().asString()).isEqualTo("foo"); } } diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/data/LogDataBuilderTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/data/LogDataBuilderTest.java new file mode 100644 index 0000000000..eb8b11d500 --- /dev/null +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/data/LogDataBuilderTest.java @@ -0,0 +1,30 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.logs.data; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import io.opentelemetry.sdk.common.Clock; +import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; +import io.opentelemetry.sdk.resources.Resource; +import org.junit.jupiter.api.Test; + +class LogDataBuilderTest { + + @Test + void canSetClock() { + Resource resource = Resource.getDefault(); + InstrumentationLibraryInfo libraryInfo = InstrumentationLibraryInfo.empty(); + Clock clock = mock(Clock.class); + when(clock.now()).thenReturn(12L); + LogDataBuilder builder = LogDataBuilder.create(resource, libraryInfo, clock); + + LogData result = builder.build(); + assertEquals(12L, result.getEpochNanos()); + } +} diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/util/TestUtil.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/util/TestUtil.java index 194db14f8e..d898ec3907 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/util/TestUtil.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/util/TestUtil.java @@ -11,6 +11,7 @@ import io.opentelemetry.api.trace.TraceFlags; import io.opentelemetry.api.trace.TraceId; import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; import io.opentelemetry.sdk.logs.data.LogData; +import io.opentelemetry.sdk.logs.data.LogDataBuilder; import io.opentelemetry.sdk.logs.data.Severity; import io.opentelemetry.sdk.resources.Resource; import java.util.concurrent.TimeUnit; @@ -18,7 +19,7 @@ import java.util.concurrent.TimeUnit; public final class TestUtil { public static LogData createLogData(Severity severity, String message) { - return LogData.builder( + return LogDataBuilder.create( Resource.create(Attributes.builder().put("testKey", "testValue").build()), InstrumentationLibraryInfo.create("instrumentation", "1")) .setEpoch(System.currentTimeMillis(), TimeUnit.MILLISECONDS) diff --git a/sdk/logs/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/sdk/logs/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker new file mode 100644 index 0000000000..ca6ee9cea8 --- /dev/null +++ b/sdk/logs/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker @@ -0,0 +1 @@ +mock-maker-inline \ No newline at end of file