diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c7eeddabc3..77bf8fe51cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,16 @@ - New `AttributesBuilder#remove(String)` and `AttributeBuilder#removeIf(Predicate>)` methods improve ergonomics of modifying attributes. +### SDK + +#### Logging (alpha) + +- This release includes a rework of the Log SDK to + implement [OTEP-0150](https://github.com/open-telemetry/oteps/blob/main/text/logs/0150-logging-library-sdk.md) + and to have more symmetry to the Trace SDK. `LogSink` is now `LogEmitter`. `LogEmitter` instances + are obtained from `SdkLogEmitterProvider`. Other additions include `MultiLogProcessor` (accessed + via `LogProcessor#composite(...)`), `SimpleLogProcessor`, and `InMemoryLogExporter`. + ### Auto-configuration (alpha) - BREAKING CHANGE: Remove deprecated `otel.experimental.exporter.otlp.protocol`, 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 d03972a14f2..2c6ee030008 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,11 +14,11 @@ 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.LogRecord; import io.opentelemetry.sdk.logs.data.Severity; import io.opentelemetry.sdk.logs.export.LogExporter; import io.opentelemetry.sdk.resources.Resource; import java.util.Arrays; +import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -31,7 +31,7 @@ class OtlpJsonLoggingLogExporterTest { Resource.create(Attributes.builder().put("key", "value").build()); private static final LogData LOG1 = - LogRecord.builder(RESOURCE, InstrumentationLibraryInfo.create("instrumentation", "1")) + LogData.builder(RESOURCE, InstrumentationLibraryInfo.create("instrumentation", "1")) .setName("testLog1") .setBody("body1") .setFlags(0) @@ -39,12 +39,12 @@ class OtlpJsonLoggingLogExporterTest { .setSeverityText("INFO") .setSpanId("8765432112345876") .setTraceId("12345678876543211234567887654322") - .setEpochMillis(1631533710L) + .setEpoch(1631533710L, TimeUnit.MILLISECONDS) .setAttributes(Attributes.of(stringKey("animal"), "cat", longKey("lives"), 9L)) .build(); private static final LogData LOG2 = - LogRecord.builder(RESOURCE, InstrumentationLibraryInfo.create("instrumentation2", "2")) + LogData.builder(RESOURCE, InstrumentationLibraryInfo.create("instrumentation2", "2")) .setName("testLog2") .setBody("body2") .setFlags(0) @@ -52,7 +52,7 @@ class OtlpJsonLoggingLogExporterTest { .setSeverityText("INFO") .setSpanId("8765432112345875") .setTraceId("12345678876543211234567887654322") - .setEpochMillis(1631533710L) + .setEpoch(1631533710L, TimeUnit.MILLISECONDS) .setAttributes(Attributes.of(booleanKey("important"), true)) .build(); 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 c403ef94ede..b124809eadf 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,12 +17,12 @@ 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.LogRecord; import io.opentelemetry.sdk.logs.data.Severity; import io.opentelemetry.sdk.resources.Resource; import java.time.LocalDateTime; import java.time.Month; import java.time.ZoneOffset; +import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.Test; class SystemOutLogExporterTest { @@ -50,11 +50,11 @@ void format() { } private static LogData sampleLog(long timestamp) { - return LogRecord.builder(Resource.empty(), InstrumentationLibraryInfo.create("logTest", "1.0")) + return LogData.builder(Resource.empty(), InstrumentationLibraryInfo.create("logTest", "1.0")) .setAttributes(Attributes.of(stringKey("cheese"), "cheddar", longKey("amount"), 1L)) .setBody(Body.stringBody("message")) .setSeverity(Severity.ERROR3) - .setEpochMillis(timestamp) + .setEpoch(timestamp, TimeUnit.MILLISECONDS) .setTraceId(TraceId.fromLongs(1, 2)) .setSpanId(SpanId.fromLong(3)) .build(); 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 a3f15f00cd7..4dfa184c042 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,7 +31,6 @@ 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.LogRecord; import io.opentelemetry.sdk.logs.data.Severity; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.IdGenerator; @@ -319,7 +318,7 @@ private static HttpResponse buildResponse(HttpStatus httpSta } private static LogData generateFakeLog() { - return LogRecord.builder( + return LogData.builder( Resource.getDefault(), InstrumentationLibraryInfo.create("testLib", "1.0", "http://url")) .setName("log-name") @@ -329,7 +328,7 @@ private static LogData generateFakeLog() { .setSeverityText(Severity.INFO.name()) .setTraceId(IdGenerator.random().generateTraceId()) .setSpanId(IdGenerator.random().generateSpanId()) - .setEpochNanos(TimeUnit.MILLISECONDS.toNanos(Instant.now().toEpochMilli())) + .setEpoch(Instant.now()) .setFlags(0) .build(); } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/logs/LogsRequestMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/logs/LogsRequestMarshaler.java index 2781399df9d..336890fad49 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/logs/LogsRequestMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/otlp/internal/logs/LogsRequestMarshaler.java @@ -11,13 +11,12 @@ import io.opentelemetry.exporter.otlp.internal.Serializer; import io.opentelemetry.proto.collector.logs.v1.internal.ExportLogsServiceRequest; import io.opentelemetry.sdk.logs.data.LogData; -import io.opentelemetry.sdk.logs.data.LogRecord; import io.opentelemetry.sdk.trace.data.SpanData; import java.io.IOException; import java.util.Collection; /** - * {@link Marshaler} to convert SDK {@link LogRecord} to OTLP ExportLogsServiceRequest. + * {@link Marshaler} to convert SDK {@link LogData} to OTLP ExportLogsServiceRequest. * *

This class is internal and is hence not for public use. Its APIs are unstable and can change * at any time. 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 810c45efd71..e9dbca96534 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,6 +24,7 @@ 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.Severity; import io.opentelemetry.sdk.resources.Resource; import java.io.ByteArrayOutputStream; @@ -33,6 +34,7 @@ import java.util.Base64; import java.util.Collections; import java.util.Locale; +import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.Test; class LogsRequestMarshalerTest { @@ -49,7 +51,7 @@ void toProtoResourceLogs() { ResourceLogsMarshaler[] resourceLogsMarshalers = ResourceLogsMarshaler.create( Collections.singleton( - io.opentelemetry.sdk.logs.data.LogRecord.builder( + LogData.builder( Resource.builder().put("one", 1).setSchemaUrl("http://url").build(), InstrumentationLibraryInfo.create("testLib", "1.0", "http://url")) .setName(NAME) @@ -59,7 +61,7 @@ void toProtoResourceLogs() { .setTraceId(TRACE_ID) .setSpanId(SPAN_ID) .setAttributes(Attributes.of(AttributeKey.booleanKey("key"), true)) - .setEpochNanos(12345) + .setEpoch(12345, TimeUnit.NANOSECONDS) .build())); assertThat(resourceLogsMarshalers).hasSize(1); @@ -82,7 +84,7 @@ void toProtoLogRecord() { parse( LogRecord.getDefaultInstance(), LogMarshaler.create( - io.opentelemetry.sdk.logs.data.LogRecord.builder( + LogData.builder( Resource.create(Attributes.builder().put("testKey", "testValue").build()), InstrumentationLibraryInfo.create("instrumentation", "1")) .setName(NAME) @@ -92,7 +94,7 @@ void toProtoLogRecord() { .setTraceId(TRACE_ID) .setSpanId(SPAN_ID) .setAttributes(Attributes.of(AttributeKey.booleanKey("key"), true)) - .setEpochNanos(12345) + .setEpoch(12345, TimeUnit.NANOSECONDS) .build())); assertThat(logRecord.getTraceId().toByteArray()).isEqualTo(TRACE_ID_BYTES); @@ -115,13 +117,13 @@ void toProtoLogRecord_MinimalFields() { parse( LogRecord.getDefaultInstance(), LogMarshaler.create( - io.opentelemetry.sdk.logs.data.LogRecord.builder( + LogData.builder( Resource.create(Attributes.builder().put("testKey", "testValue").build()), InstrumentationLibraryInfo.create("instrumentation", "1")) .setBody(BODY) .setSeverity(Severity.INFO) .setAttributes(Attributes.of(AttributeKey.booleanKey("key"), true)) - .setEpochNanos(12345) + .setEpoch(12345, TimeUnit.NANOSECONDS) .build())); assertThat(logRecord.getTraceId().toByteArray()).isEmpty(); 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 60827a30a6a..a03c7a7942b 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 @@ -32,7 +32,6 @@ 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.LogRecord; import io.opentelemetry.sdk.logs.data.Severity; import io.opentelemetry.sdk.resources.Resource; import java.io.ByteArrayOutputStream; @@ -40,6 +39,7 @@ import java.io.UncheckedIOException; import java.nio.charset.StandardCharsets; import java.time.Duration; +import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -357,10 +357,10 @@ void usingGrpc() { } private static LogData generateFakeLog() { - return LogRecord.builder( + return LogData.builder( Resource.create(Attributes.builder().put("testKey", "testValue").build()), InstrumentationLibraryInfo.create("instrumentation", "1")) - .setEpochMillis(System.currentTimeMillis()) + .setEpoch(Instant.now()) .setTraceId(TraceId.getInvalid()) .setSpanId(SpanId.getInvalid()) .setFlags(TraceFlags.getDefault().asByte()) 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 5b7e872ff72..cfb4411b0f0 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,11 +23,11 @@ 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.LogRecord; import io.opentelemetry.sdk.logs.data.Severity; import io.opentelemetry.sdk.resources.Resource; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.time.Instant; import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; @@ -39,10 +39,10 @@ class ExportTest { private static final List LOGS = Collections.singletonList( - LogRecord.builder( + LogData.builder( Resource.create(Attributes.builder().put("testKey", "testValue").build()), InstrumentationLibraryInfo.create("instrumentation", "1")) - .setEpochMillis(System.currentTimeMillis()) + .setEpoch(Instant.now()) .setTraceId(TraceId.getInvalid()) .setSpanId(SpanId.getInvalid()) .setFlags(TraceFlags.getDefault().asByte()) 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 5b7e872ff72..cfb4411b0f0 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,11 +23,11 @@ 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.LogRecord; import io.opentelemetry.sdk.logs.data.Severity; import io.opentelemetry.sdk.resources.Resource; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.time.Instant; import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; @@ -39,10 +39,10 @@ class ExportTest { private static final List LOGS = Collections.singletonList( - LogRecord.builder( + LogData.builder( Resource.create(Attributes.builder().put("testKey", "testValue").build()), InstrumentationLibraryInfo.create("instrumentation", "1")) - .setEpochMillis(System.currentTimeMillis()) + .setEpoch(Instant.now()) .setTraceId(TraceId.getInvalid()) .setSpanId(SpanId.getInvalid()) .setFlags(TraceFlags.getDefault().asByte()) 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 5b7e872ff72..cfb4411b0f0 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,11 +23,11 @@ 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.LogRecord; import io.opentelemetry.sdk.logs.data.Severity; import io.opentelemetry.sdk.resources.Resource; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.time.Instant; import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; @@ -39,10 +39,10 @@ class ExportTest { private static final List LOGS = Collections.singletonList( - LogRecord.builder( + LogData.builder( Resource.create(Attributes.builder().put("testKey", "testValue").build()), InstrumentationLibraryInfo.create("instrumentation", "1")) - .setEpochMillis(System.currentTimeMillis()) + .setEpoch(Instant.now()) .setTraceId(TraceId.getInvalid()) .setSpanId(SpanId.getInvalid()) .setFlags(TraceFlags.getDefault().asByte()) 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 832660e9aaa..e604ff65569 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,12 +20,12 @@ 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.LogRecord; import io.opentelemetry.sdk.logs.data.Severity; import io.opentelemetry.sdk.resources.Resource; import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; +import java.time.Instant; import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -40,10 +40,10 @@ class OkHttpOnlyExportTest { private static final List LOGS = Collections.singletonList( - LogRecord.builder( + LogData.builder( Resource.create(Attributes.builder().put("testKey", "testValue").build()), InstrumentationLibraryInfo.create("instrumentation", "1")) - .setEpochMillis(System.currentTimeMillis()) + .setEpoch(Instant.now()) .setTraceId(TraceId.getInvalid()) .setSpanId(SpanId.getInvalid()) .setFlags(TraceFlags.getDefault().asByte()) 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 79550e68c5c..59c13783325 100644 --- a/integration-tests/src/testOtlpCommon/java/io/opentelemetry/integrationtest/OtlpExporterIntegrationTest.java +++ b/integration-tests/src/testOtlpCommon/java/io/opentelemetry/integrationtest/OtlpExporterIntegrationTest.java @@ -52,7 +52,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.LogRecord; +import io.opentelemetry.sdk.logs.data.LogData; import io.opentelemetry.sdk.logs.data.Severity; import io.opentelemetry.sdk.logs.export.LogExporter; import io.opentelemetry.sdk.metrics.SdkMeterProvider; @@ -72,7 +72,6 @@ import java.util.Collections; import java.util.List; import java.util.concurrent.CompletionStage; -import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import org.junit.jupiter.api.AfterAll; @@ -375,8 +374,8 @@ void testOtlpHttpLogExport(String compression) { } private static void testLogExporter(LogExporter logExporter) { - LogRecord logRecord = - LogRecord.builder( + LogData logData = + LogData.builder( RESOURCE, InstrumentationLibraryInfo.create( OtlpExporterIntegrationTest.class.getName(), null)) @@ -387,11 +386,11 @@ private static void testLogExporter(LogExporter logExporter) { .setSeverityText("DEBUG") .setTraceId(IdGenerator.random().generateTraceId()) .setSpanId(IdGenerator.random().generateSpanId()) - .setEpochNanos(TimeUnit.MILLISECONDS.toNanos(Instant.now().toEpochMilli())) + .setEpoch(Instant.now()) .setFlags(0) .build(); - logExporter.export(Collections.singletonList(logRecord)); + logExporter.export(Collections.singletonList(logData)); await() .atMost(Duration.ofSeconds(30)) @@ -425,14 +424,13 @@ private static void testLogExporter(LogExporter logExporter) { .setValue(AnyValue.newBuilder().setStringValue("value").build()) .build())); assertThat(protoLog.getSeverityNumber().getNumber()) - .isEqualTo(logRecord.getSeverity().getSeverityNumber()); + .isEqualTo(logData.getSeverity().getSeverityNumber()); assertThat(protoLog.getSeverityText()).isEqualTo("DEBUG"); assertThat(TraceId.fromBytes(protoLog.getTraceId().toByteArray())) - .isEqualTo(logRecord.getTraceId()); - assertThat(SpanId.fromBytes(protoLog.getSpanId().toByteArray())) - .isEqualTo(logRecord.getSpanId()); - assertThat(protoLog.getTimeUnixNano()).isEqualTo(logRecord.getEpochNanos()); - assertThat(protoLog.getFlags()).isEqualTo(logRecord.getFlags()); + .isEqualTo(logData.getTraceId()); + assertThat(SpanId.fromBytes(protoLog.getSpanId().toByteArray())).isEqualTo(logData.getSpanId()); + assertThat(protoLog.getTimeUnixNano()).isEqualTo(logData.getEpochNanos()); + assertThat(protoLog.getFlags()).isEqualTo(logData.getFlags()); } private static class OtlpGrpcServer extends ServerExtension { diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogBuilder.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogBuilder.java new file mode 100644 index 00000000000..e9c80c95011 --- /dev/null +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogBuilder.java @@ -0,0 +1,57 @@ +/* + * 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.Severity; +import java.time.Instant; +import java.util.concurrent.TimeUnit; + +/** + * Used to construct and emit logs from a {@link LogEmitter}. + * + *

Obtain a {@link LogBuilder} via {@link LogEmitter#logBuilder()}, add properties using the + * setters, and emit the log to downstream {@link LogProcessor}(s) by calling {@link #emit()}. + */ +public interface LogBuilder { + + /** Set the epoch timestamp using the timestamp and unit. */ + LogBuilder setEpoch(long timestamp, TimeUnit unit); + + /** Set the epoch timestamp using the instant. */ + LogBuilder setEpoch(Instant instant); + + /** Set the trace id. */ + LogBuilder setTraceId(String traceId); + + /** Set the span id. */ + LogBuilder setSpanId(String spanId); + + /** Set the flags. */ + LogBuilder setFlags(int flags); + + /** Set the severity. */ + LogBuilder setSeverity(Severity severity); + + /** Set the severity text. */ + LogBuilder setSeverityText(String severityText); + + /** Set the name. */ + LogBuilder setName(String name); + + /** Set the body. */ + LogBuilder setBody(Body body); + + /** Set the body string. */ + LogBuilder setBody(String body); + + /** Set the attributes. */ + LogBuilder setAttributes(Attributes attributes); + + /** Emit the log to downstream {@link LogProcessor}(s). */ + void emit(); +} diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogEmitter.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogEmitter.java new file mode 100644 index 00000000000..37a0a48a822 --- /dev/null +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogEmitter.java @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.logs; + +import javax.annotation.concurrent.ThreadSafe; + +/** + * A {@link LogEmitter} is the entry point into a log pipeline. + * + *

Obtain a log builder via {@link #logBuilder()}, add properties using the setters, and emit it + * to downstream {@link LogProcessor}(s) via {@link LogBuilder#emit()}. + */ +@ThreadSafe +public interface LogEmitter { + + /** + * Return a {@link LogBuilder} to emit a log. + * + *

Build the log using the {@link LogBuilder} setters, and emit it to downstream {@link + * LogProcessor}(s) via {@link LogBuilder#emit()}. + */ + LogBuilder logBuilder(); +} diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogEmitterBuilder.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogEmitterBuilder.java new file mode 100644 index 00000000000..b31986b853c --- /dev/null +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogEmitterBuilder.java @@ -0,0 +1,33 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.logs; + +/** Builder class for creating {@link LogEmitter} instances. */ +public interface LogEmitterBuilder { + + /** + * Assign an OpenTelemetry schema URL to the resulting {@link LogEmitter}. + * + * @param schemaUrl the URL of the OpenTelemetry schema being used by this instrumentation library + * @return this + */ + LogEmitterBuilder setSchemaUrl(String schemaUrl); + + /** + * Assign a version to the instrumentation library that is using the resulting {@link LogEmitter}. + * + * @param instrumentationVersion the version of the instrumentation library + * @return this + */ + LogEmitterBuilder setInstrumentationVersion(String instrumentationVersion); + + /** + * Gets or creates a {@link LogEmitter} instance. + * + * @return a log emitter instance configured with the provided options + */ + LogEmitter build(); +} 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 new file mode 100644 index 00000000000..59349debb7b --- /dev/null +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogEmitterSharedState.java @@ -0,0 +1,49 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.logs; + +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.resources.Resource; +import java.util.List; +import javax.annotation.Nullable; + +/** + * Represents shared state and config between all {@link SdkLogEmitter}s created by the same {@link + * SdkLogEmitterProvider}. + */ +final class LogEmitterSharedState { + private final Object lock = new Object(); + private final Resource resource; + private final LogProcessor logProcessor; + @Nullable private volatile CompletableResultCode shutdownResult = null; + + LogEmitterSharedState(Resource resource, List logProcessors) { + this.resource = resource; + this.logProcessor = LogProcessor.composite(logProcessors); + } + + Resource getResource() { + return resource; + } + + LogProcessor getLogProcessor() { + return logProcessor; + } + + boolean hasBeenShutdown() { + return shutdownResult != null; + } + + CompletableResultCode shutdown() { + synchronized (lock) { + if (shutdownResult != null) { + return shutdownResult; + } + shutdownResult = logProcessor.shutdown(); + return shutdownResult; + } + } +} diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogProcessor.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogProcessor.java index 0837e7806d2..77a6cbb8858 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogProcessor.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogProcessor.java @@ -6,24 +6,77 @@ package io.opentelemetry.sdk.logs; import io.opentelemetry.sdk.common.CompletableResultCode; -import io.opentelemetry.sdk.logs.data.LogRecord; -import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.logs.data.LogData; +import java.io.Closeable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeUnit; +import javax.annotation.concurrent.ThreadSafe; -public interface LogProcessor { +/** + * {@link LogProcessor} is the interface to allow synchronous hooks for logs emitted by {@link + * LogEmitter}s. + */ +@ThreadSafe +public interface LogProcessor extends Closeable { - void addLogRecord(LogRecord record); + /** + * Returns a {@link LogProcessor} which simply delegates to all processing to the {@code + * processors} in order. + */ + static LogProcessor composite(LogProcessor... processors) { + return composite(Arrays.asList(processors)); + } /** - * Called when {@link SdkTracerProvider#shutdown()} is called. + * Returns a {@link LogProcessor} which simply delegates to all processing to the {@code + * processors} in order. + */ + static LogProcessor composite(Iterable processors) { + List processorList = new ArrayList<>(); + for (LogProcessor processor : processors) { + processorList.add(processor); + } + if (processorList.isEmpty()) { + return NoopLogProcessor.getInstance(); + } + if (processorList.size() == 1) { + return processorList.get(0); + } + return MultiLogProcessor.create(processorList); + } + + /** + * Emit a log. + * + * @param logData the log + */ + void emit(LogData logData); + + /** + * Shutdown the log processor. * * @return result */ - CompletableResultCode shutdown(); + default CompletableResultCode shutdown() { + return forceFlush(); + } /** - * Processes all span events that have not yet been processed. + * Process all logs that have not yet been processed. * * @return result */ - CompletableResultCode forceFlush(); + default CompletableResultCode forceFlush() { + return CompletableResultCode.ofSuccess(); + } + + /** + * Closes this {@link LogProcessor} after processing any remaining logs, releasing any resources. + */ + @Override + default void close() { + shutdown().join(10, TimeUnit.SECONDS); + } } diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogSink.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogSink.java deleted file mode 100644 index b5e852308a1..00000000000 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogSink.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.logs; - -import io.opentelemetry.sdk.logs.data.LogRecord; - -/** A LogSink accepts logging records for transmission to an aggregator or log processing system. */ -public interface LogSink { - /** - * Pass a record to the SDK for transmission to a logging exporter. - * - * @param record record to transmit - */ - void offer(LogRecord record); -} diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogSinkSdkProvider.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogSinkSdkProvider.java deleted file mode 100644 index b405fb7f43d..00000000000 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogSinkSdkProvider.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.logs; - -import io.opentelemetry.sdk.common.CompletableResultCode; -import io.opentelemetry.sdk.logs.data.LogRecord; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -public final class LogSinkSdkProvider { - private final LogSink logSink = new SdkLogSink(); - private final List processors; - - /** - * Returns a new {@link LogSinkSdkProviderBuilder} for this class. - * - * @return a new {@link LogSinkSdkProviderBuilder} for this class. - */ - public static LogSinkSdkProviderBuilder builder() { - return new LogSinkSdkProviderBuilder(); - } - - LogSinkSdkProvider(List processors) { - this.processors = processors; - } - - public LogSink get(String instrumentationName, String instrumentationVersion) { - // Currently there is no differentiation by instrumentation library - return logSink; - } - - /** - * Flushes all attached processors. - * - * @return result - */ - public CompletableResultCode forceFlush() { - final List processorResults = new ArrayList<>(processors.size()); - for (LogProcessor processor : processors) { - processorResults.add(processor.forceFlush()); - } - return CompletableResultCode.ofAll(processorResults); - } - - /** - * Shut down of provider and associated processors. - * - * @return result - */ - public CompletableResultCode shutdown() { - Collection processorResults = new ArrayList<>(processors.size()); - for (LogProcessor processor : processors) { - processorResults.add(processor.shutdown()); - } - return CompletableResultCode.ofAll(processorResults); - } - - private class SdkLogSink implements LogSink { - @Override - public void offer(LogRecord record) { - for (LogProcessor processor : processors) { - processor.addLogRecord(record); - } - } - } -} diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogSinkSdkProviderBuilder.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogSinkSdkProviderBuilder.java deleted file mode 100644 index 9e8161c5585..00000000000 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/LogSinkSdkProviderBuilder.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.logs; - -import static java.util.Objects.requireNonNull; - -import io.opentelemetry.sdk.logs.data.LogRecord; -import java.util.ArrayList; -import java.util.List; - -public final class LogSinkSdkProviderBuilder { - - private final List logProcessors = new ArrayList<>(); - - LogSinkSdkProviderBuilder() {} - - /** - * Add a LogProcessor to the log pipeline that will be built. {@link LogProcessor} will be called - * each time a {@link LogRecord} is offered to a {@link LogSink}. - * - * @param processor the processor to be added to the processing pipeline. - * @return this - */ - public LogSinkSdkProviderBuilder addLogProcessor(LogProcessor processor) { - requireNonNull(processor, "processor can not be null"); - logProcessors.add(processor); - return this; - } - - public LogSinkSdkProvider build() { - return new LogSinkSdkProvider(logProcessors); - } -} diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/MultiLogProcessor.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/MultiLogProcessor.java new file mode 100644 index 00000000000..8f07c00a3b6 --- /dev/null +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/MultiLogProcessor.java @@ -0,0 +1,65 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.logs; + +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.logs.data.LogData; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * Implementation of {@link LogProcessor} that forwards all logs to a list of {@link LogProcessor}s. + */ +final class MultiLogProcessor implements LogProcessor { + + private final List logProcessors; + private final AtomicBoolean isShutdown = new AtomicBoolean(false); + + /** + * Create a new {@link MultiLogProcessor}. + * + * @param logProcessorsList list of log processors to forward logs to + * @return a multi log processor instance + */ + static LogProcessor create(List logProcessorsList) { + return new MultiLogProcessor( + new ArrayList<>(Objects.requireNonNull(logProcessorsList, "logProcessorsList"))); + } + + @Override + public void emit(LogData logData) { + for (LogProcessor logProcessor : logProcessors) { + logProcessor.emit(logData); + } + } + + @Override + public CompletableResultCode shutdown() { + if (isShutdown.getAndSet(true)) { + return CompletableResultCode.ofSuccess(); + } + List results = new ArrayList<>(logProcessors.size()); + for (LogProcessor logProcessor : logProcessors) { + results.add(logProcessor.shutdown()); + } + return CompletableResultCode.ofAll(results); + } + + @Override + public CompletableResultCode forceFlush() { + List results = new ArrayList<>(logProcessors.size()); + for (LogProcessor logProcessor : logProcessors) { + results.add(logProcessor.forceFlush()); + } + return CompletableResultCode.ofAll(results); + } + + private MultiLogProcessor(List logProcessorsList) { + this.logProcessors = logProcessorsList; + } +} diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/NoopLogProcessor.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/NoopLogProcessor.java new file mode 100644 index 00000000000..a7ef2f2f22d --- /dev/null +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/NoopLogProcessor.java @@ -0,0 +1,21 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.logs; + +import io.opentelemetry.sdk.logs.data.LogData; + +final class NoopLogProcessor implements LogProcessor { + private static final NoopLogProcessor INSTANCE = new NoopLogProcessor(); + + static LogProcessor getInstance() { + return INSTANCE; + } + + private NoopLogProcessor() {} + + @Override + public void emit(LogData logData) {} +} 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 new file mode 100644 index 00000000000..6d1ca7bf2bf --- /dev/null +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogEmitter.java @@ -0,0 +1,123 @@ +/* + * 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.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 { + + private final LogEmitterSharedState logEmitterSharedState; + private final InstrumentationLibraryInfo instrumentationLibraryInfo; + + SdkLogEmitter( + LogEmitterSharedState logEmitterSharedState, + InstrumentationLibraryInfo instrumentationLibraryInfo) { + this.logEmitterSharedState = logEmitterSharedState; + this.instrumentationLibraryInfo = instrumentationLibraryInfo; + } + + @Override + public LogBuilder logBuilder() { + return new SdkLogBuilder(); + } + + // 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/SdkLogEmitterBuilder.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogEmitterBuilder.java new file mode 100644 index 00000000000..30b8903dad1 --- /dev/null +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogEmitterBuilder.java @@ -0,0 +1,39 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.logs; + +import io.opentelemetry.sdk.internal.ComponentRegistry; +import javax.annotation.Nullable; + +final class SdkLogEmitterBuilder implements LogEmitterBuilder { + + private final ComponentRegistry registry; + private final String instrumentationName; + @Nullable private String getInstrumentationVersion; + @Nullable private String schemaUrl; + + SdkLogEmitterBuilder(ComponentRegistry registry, String instrumentationName) { + this.registry = registry; + this.instrumentationName = instrumentationName; + } + + @Override + public SdkLogEmitterBuilder setSchemaUrl(String schemaUrl) { + this.schemaUrl = schemaUrl; + return this; + } + + @Override + public SdkLogEmitterBuilder setInstrumentationVersion(String instrumentationVersion) { + this.getInstrumentationVersion = instrumentationVersion; + return this; + } + + @Override + public SdkLogEmitter build() { + return registry.get(instrumentationName, getInstrumentationVersion, schemaUrl); + } +} 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 new file mode 100644 index 00000000000..a963606f75c --- /dev/null +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogEmitterProvider.java @@ -0,0 +1,84 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.logs; + +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.internal.ComponentRegistry; +import io.opentelemetry.sdk.resources.Resource; +import java.io.Closeable; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** SDK registry for creating {@link LogEmitter}s. */ +public final class SdkLogEmitterProvider implements Closeable { + + static final String DEFAULT_EMITTER_NAME = "unknown"; + private static final Logger LOGGER = Logger.getLogger(SdkLogEmitterProvider.class.getName()); + + private final LogEmitterSharedState sharedState; + private final ComponentRegistry logEmitterComponentRegistry; + + /** + * Returns a new {@link SdkLogEmitterProviderBuilder} for {@link SdkLogEmitterProvider}. + * + * @return a new builder instance + */ + public static SdkLogEmitterProviderBuilder builder() { + return new SdkLogEmitterProviderBuilder(); + } + + SdkLogEmitterProvider(Resource resource, List processors) { + this.sharedState = new LogEmitterSharedState(resource, processors); + this.logEmitterComponentRegistry = + new ComponentRegistry<>( + instrumentationLibraryInfo -> + new SdkLogEmitter(sharedState, instrumentationLibraryInfo)); + } + + /** + * Creates a {@link LogEmitterBuilder} instance. + * + * @param instrumentationName the name of the instrumentation library + * @return a log emitter builder instance + */ + public LogEmitterBuilder logEmitterBuilder(String instrumentationName) { + if (instrumentationName == null || instrumentationName.isEmpty()) { + LOGGER.fine("LogEmitter requested without instrumentation name."); + instrumentationName = DEFAULT_EMITTER_NAME; + } + return new SdkLogEmitterBuilder(logEmitterComponentRegistry, instrumentationName); + } + + /** + * Request the active log processor to process all logs that have not yet been processed. + * + * @return a {@link CompletableResultCode} which is completed when the flush is finished + */ + public CompletableResultCode forceFlush() { + return sharedState.getLogProcessor().forceFlush(); + } + + /** + * Attempt to shut down the active log processor. + * + * @return a {@link CompletableResultCode} which is completed when the active log process has been + * shut down. + */ + public CompletableResultCode shutdown() { + if (sharedState.hasBeenShutdown()) { + LOGGER.log(Level.WARNING, "Calling shutdown() multiple times."); + return CompletableResultCode.ofSuccess(); + } + return sharedState.shutdown(); + } + + @Override + public void close() { + shutdown().join(10, TimeUnit.SECONDS); + } +} 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 new file mode 100644 index 00000000000..9b638dba1ae --- /dev/null +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogEmitterProviderBuilder.java @@ -0,0 +1,57 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.logs; + +import static java.util.Objects.requireNonNull; + +import io.opentelemetry.sdk.logs.data.LogData; +import io.opentelemetry.sdk.resources.Resource; +import java.util.ArrayList; +import java.util.List; + +/** Builder class for {@link SdkLogEmitterProvider} instances. */ +public final class SdkLogEmitterProviderBuilder { + + private final List logProcessors = new ArrayList<>(); + private Resource resource = Resource.getDefault(); + + SdkLogEmitterProviderBuilder() {} + + /** + * Assign a {@link Resource} to be attached to all {@link LogData} created by {@link LogEmitter}s + * obtained from the {@link SdkLogEmitterProvider}. + * + * @param resource the resource + * @return this + */ + public SdkLogEmitterProviderBuilder setResource(Resource resource) { + requireNonNull(resource, "resource"); + this.resource = resource; + return this; + } + + /** + * Add a log processor. {@link LogProcessor#emit(LogData)} will be called each time a log is + * emitted by {@link LogEmitter} instances obtained from the {@link SdkLogEmitterProvider}. + * + * @param processor the log processor + * @return this + */ + public SdkLogEmitterProviderBuilder addLogProcessor(LogProcessor processor) { + requireNonNull(processor, "processor"); + logProcessors.add(processor); + return this; + } + + /** + * Create a {@link SdkLogEmitterProvider} instance. + * + * @return an instance configured with the provided options + */ + public SdkLogEmitterProvider build() { + return new SdkLogEmitterProvider(resource, logProcessors); + } +} 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 4b5dd5a07f2..61d6d74b710 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 @@ -12,91 +12,53 @@ import javax.annotation.concurrent.Immutable; /** - * The interface for a log as defined in the OpenTelemetry - * logging model. + * Log definition as described in OpenTelemetry + * Log Data Model. */ @Immutable public interface LogData { - /** - * Returns the resource of this log. - * - * @return the resource. - */ + /** 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(); - /** - * Returns the instrumentation library that generated this log. - * - * @return an instance of {@link InstrumentationLibraryInfo}. - */ + /** Returns the instrumentation library that generated this log. */ InstrumentationLibraryInfo getInstrumentationLibraryInfo(); - /** - * Returns the epoch timestamp in nanos when the log was recorded. - * - * @return the epoch timestamp in nanos. - */ + /** Returns the epoch timestamp in nanos when the log was recorded. */ long getEpochNanos(); - /** - * Returns the trace id for this log. - * - * @return the trace id. - */ + /** Returns the trace id for this log. */ @Nullable String getTraceId(); - /** - * Returns the span id for this log. - * - * @return the span id. - */ + /** Returns the span id for this log. */ @Nullable String getSpanId(); - /** - * Returns the flags for this log. - * - * @return the flags. - */ + /** Returns the flags for this log. */ int getFlags(); - /** - * Returns the severity for this log. - * - * @return the severity. - */ + /** Returns the severity for this log. */ Severity getSeverity(); - /** - * Returns the severity text for this log. - * - * @return the severity text. - */ + /** Returns the severity text for this log. */ @Nullable String getSeverityText(); - /** - * Returns the name for this log. - * - * @return the name. - */ + /** Returns the name for this log. */ @Nullable String getName(); - /** - * Returns the body for this log. - * - * @return the body. - */ + /** Returns the body for this log. */ Body getBody(); - /** - * Returns the attributes for this log. - * - * @return the attributes. - */ + /** Returns the attributes for this log. */ Attributes getAttributes(); } diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/LogRecordBuilder.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/LogDataBuilder.java similarity index 56% rename from sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/LogRecordBuilder.java rename to sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/LogDataBuilder.java index 310cd76e328..7084c8f4263 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/LogRecordBuilder.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/LogDataBuilder.java @@ -9,11 +9,13 @@ import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; import io.opentelemetry.sdk.resources.Resource; +import java.time.Instant; import java.util.concurrent.TimeUnit; import javax.annotation.Nullable; -/** Builder for {@link LogRecord}. */ -public final class LogRecordBuilder { +/** Builder for {@link LogData}. */ +public final class LogDataBuilder { + private final Resource resource; private final InstrumentationLibraryInfo instrumentationLibraryInfo; @@ -27,74 +29,82 @@ public final class LogRecordBuilder { private Body body = Body.stringBody(""); private final AttributesBuilder attributeBuilder = Attributes.builder(); - LogRecordBuilder(Resource resource, InstrumentationLibraryInfo instrumentationLibraryInfo) { + LogDataBuilder(Resource resource, InstrumentationLibraryInfo instrumentationLibraryInfo) { this.resource = resource; this.instrumentationLibraryInfo = instrumentationLibraryInfo; } - public LogRecordBuilder setEpochNanos(long timestamp) { - this.epochNanos = timestamp; + /** Set the epoch timestamp using the timestamp and unit. */ + public LogDataBuilder setEpoch(long timestamp, TimeUnit unit) { + this.epochNanos = unit.toNanos(timestamp); return this; } - public LogRecordBuilder setEpochMillis(long timestamp) { - return setEpochNanos(TimeUnit.MILLISECONDS.toNanos(timestamp)); + /** Set the epoch timestamp using the instant. */ + public LogDataBuilder setEpoch(Instant instant) { + this.epochNanos = TimeUnit.SECONDS.toNanos(instant.getEpochSecond()) + instant.getNano(); + return this; } - public LogRecordBuilder setTraceId(String traceId) { + /** Set the trace id. */ + public LogDataBuilder setTraceId(String traceId) { this.traceId = traceId; return this; } - public LogRecordBuilder setSpanId(String spanId) { + /** Set the span id. */ + public LogDataBuilder setSpanId(String spanId) { this.spanId = spanId; return this; } - public LogRecordBuilder setFlags(int flags) { + /** Set the flags. */ + public LogDataBuilder setFlags(int flags) { this.flags = flags; return this; } - public LogRecordBuilder setSeverity(Severity severity) { + /** Set the severity. */ + public LogDataBuilder setSeverity(Severity severity) { this.severity = severity; return this; } - public LogRecordBuilder setSeverityText(String severityText) { + /** Set the severity text. */ + public LogDataBuilder setSeverityText(String severityText) { this.severityText = severityText; return this; } - public LogRecordBuilder setName(String name) { + /** Set the name. */ + public LogDataBuilder setName(String name) { this.name = name; return this; } - public LogRecordBuilder setBody(Body body) { + /** Set the body. */ + public LogDataBuilder setBody(Body body) { this.body = body; return this; } - public LogRecordBuilder setBody(String body) { + /** Set the body string. */ + public LogDataBuilder setBody(String body) { return setBody(Body.stringBody(body)); } - public LogRecordBuilder setAttributes(Attributes attributes) { + /** Set the attributes. */ + public LogDataBuilder setAttributes(Attributes attributes) { this.attributeBuilder.putAll(attributes); return this; } - /** - * Build a LogRecord instance. - * - * @return value object being built - */ - public LogRecord build() { + /** Build a {@link LogData} instance from the configured properties. */ + public LogData build() { if (epochNanos == 0) { epochNanos = TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis()); } - return LogRecord.create( + return LogDataImpl.create( resource, instrumentationLibraryInfo, epochNanos, diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/LogRecord.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/LogDataImpl.java similarity index 74% rename from sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/LogRecord.java rename to sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/LogDataImpl.java index c24bd4cf991..b6533630f6c 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/LogRecord.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/LogDataImpl.java @@ -12,18 +12,13 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; -@Immutable @AutoValue -public abstract class LogRecord implements LogData { - - LogRecord() {} +@Immutable +abstract class LogDataImpl implements LogData { - public static LogRecordBuilder builder( - Resource resource, InstrumentationLibraryInfo instrumentationLibraryInfo) { - return new LogRecordBuilder(resource, instrumentationLibraryInfo); - } + LogDataImpl() {} - static LogRecord create( + static LogDataImpl create( Resource resource, InstrumentationLibraryInfo instrumentationLibraryInfo, long epochNanos, @@ -35,7 +30,7 @@ static LogRecord create( @Nullable String name, Body body, Attributes attributes) { - return new AutoValue_LogRecord( + return new AutoValue_LogDataImpl( resource, instrumentationLibraryInfo, epochNanos, diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/export/BatchLogProcessor.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/export/BatchLogProcessor.java index c51aab11612..8f6b4cb3177 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/export/BatchLogProcessor.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/export/BatchLogProcessor.java @@ -15,7 +15,6 @@ import io.opentelemetry.sdk.internal.DaemonThreadFactory; import io.opentelemetry.sdk.logs.LogProcessor; import io.opentelemetry.sdk.logs.data.LogData; -import io.opentelemetry.sdk.logs.data.LogRecord; import java.util.ArrayList; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; @@ -51,8 +50,8 @@ public static BatchLogProcessorBuilder builder(LogExporter logExporter) { } @Override - public void addLogRecord(LogRecord record) { - worker.addLogRecord(record); + public void emit(LogData logData) { + worker.addLog(logData); } @Override @@ -69,7 +68,7 @@ public CompletableResultCode forceFlush() { private static class Worker implements Runnable { static { // TODO: As of Specification 1.4, this should have a telemetry schema version. - Meter meter = GlobalMeterProvider.get().meterBuilder("io.opentelemetry.sdk.trace").build(); + Meter meter = GlobalMeterProvider.get().meterBuilder("io.opentelemetry.sdk.logs").build(); LongCounter logRecordsProcessed = meter .counterBuilder("logRecordsProcessed") @@ -221,8 +220,8 @@ private CompletableResultCode forceFlush() { return flushResult; } - public void addLogRecord(LogRecord record) { - if (!queue.offer(record)) { + public void addLog(LogData logData) { + if (!queue.offer(logData)) { queueFullRecordCounter.add(1); } } diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/export/LogExporter.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/export/LogExporter.java index 6f0e2299810..5628823577d 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/export/LogExporter.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/export/LogExporter.java @@ -7,15 +7,26 @@ import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.logs.data.LogData; -import io.opentelemetry.sdk.logs.data.LogRecord; import java.util.Collection; /** - * An exporter is responsible for taking a list of {@link LogRecord}s and transmitting them to their - * ultimate destination. + * An exporter is responsible for taking a collection of {@link LogData}s and transmitting them to + * their ultimate destination. */ public interface LogExporter { + + /** + * Exports the collections of given {@link LogData}. + * + * @param logs the collection of {@link LogData} to be exported + * @return the result of the export, which is often an asynchronous operation + */ CompletableResultCode export(Collection logs); + /** + * Exports the collection of {@link LogData} that have not yet been exported. + * + * @return the result of the flush, which is often an asynchronous operation + */ CompletableResultCode shutdown(); } diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/export/SimpleLogProcessor.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/export/SimpleLogProcessor.java index 03f6528a0b1..8e68af8ba8d 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/export/SimpleLogProcessor.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/export/SimpleLogProcessor.java @@ -10,7 +10,6 @@ import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.logs.LogProcessor; import io.opentelemetry.sdk.logs.data.LogData; -import io.opentelemetry.sdk.logs.data.LogRecord; import java.util.Collections; import java.util.List; import java.util.Set; @@ -20,7 +19,7 @@ import java.util.logging.Logger; /** - * An implementation of the {@link LogProcessor} that passes {@link LogRecord }it directly to the + * An implementation of the {@link LogProcessor} that passes {@link LogData} directly to the * configured exporter. * *

This processor will cause all logs to be exported directly as they finish, meaning each export @@ -58,9 +57,9 @@ public static LogProcessor create(LogExporter exporter) { } @Override - public void addLogRecord(LogRecord logRecord) { + public void emit(LogData logData) { try { - List logs = Collections.singletonList(logRecord); + List logs = Collections.singletonList(logData); final CompletableResultCode result = logExporter.export(logs); pendingExports.add(result); result.whenComplete( diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/package-info.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/package-info.java index 4adcab4a99b..3382f24ef97 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/package-info.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/package-info.java @@ -6,7 +6,7 @@ /** * The OpenTelemetry SDK implementation of logging. * - * @see io.opentelemetry.sdk.logs.LogSinkSdkProvider + * @see io.opentelemetry.sdk.logs.SdkLogEmitterProvider */ @ParametersAreNonnullByDefault package io.opentelemetry.sdk.logs; diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LogSinkSdkProviderTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LogSinkSdkProviderTest.java deleted file mode 100644 index 35aa6fd10b5..00000000000 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/LogSinkSdkProviderTest.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.logs; - -import static io.opentelemetry.sdk.logs.util.TestUtil.createLog; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; -import static org.awaitility.Awaitility.await; - -import io.opentelemetry.sdk.common.CompletableResultCode; -import io.opentelemetry.sdk.logs.data.LogData; -import io.opentelemetry.sdk.logs.data.LogRecord; -import io.opentelemetry.sdk.logs.data.Severity; -import io.opentelemetry.sdk.logs.export.BatchLogProcessor; -import io.opentelemetry.sdk.logs.util.TestLogExporter; -import io.opentelemetry.sdk.logs.util.TestLogProcessor; -import java.time.Duration; -import java.util.List; -import java.util.concurrent.TimeUnit; -import org.junit.jupiter.api.Test; - -class LogSinkSdkProviderTest { - - @Test - void testLogSinkSdkProvider() { - TestLogExporter exporter = new TestLogExporter(); - LogProcessor processor = BatchLogProcessor.builder(exporter).build(); - LogSinkSdkProvider provider = LogSinkSdkProvider.builder().addLogProcessor(processor).build(); - LogSink sink = provider.get("test", "0.1a"); - LogRecord log = createLog(Severity.ERROR, "test"); - sink.offer(log); - provider.forceFlush().join(500, TimeUnit.MILLISECONDS); - List records = exporter.getRecords(); - assertThat(records).singleElement().isEqualTo(log); - assertThat(log.getSeverity().getSeverityNumber()).isEqualTo(Severity.ERROR.getSeverityNumber()); - } - - @Test - void testBatchSize() { - TestLogExporter exporter = new TestLogExporter(); - LogProcessor processor = - BatchLogProcessor.builder(exporter) - .setScheduleDelayMillis(10000) // Long enough to not be in play - .setMaxExportBatchSize(5) - .setMaxQueueSize(10) - .build(); - LogSinkSdkProvider provider = LogSinkSdkProvider.builder().addLogProcessor(processor).build(); - LogSink sink = provider.get("test", "0.1a"); - - for (int i = 0; i < 7; i++) { - sink.offer(createLog(Severity.WARN, "test #" + i)); - } - // Ensure that more than batch size kicks off a flush - await().atMost(Duration.ofSeconds(5)).until(() -> exporter.getRecords().size() > 0); - // Ensure that everything gets through - CompletableResultCode result = provider.forceFlush(); - result.join(1, TimeUnit.SECONDS); - assertThat(exporter.getCallCount()).isGreaterThanOrEqualTo(2); - } - - @Test - void testNoBlocking() { - TestLogExporter exporter = new TestLogExporter(); - exporter.setOnCall( - () -> { - try { - Thread.sleep(250); - } catch (InterruptedException ex) { - fail("Exporter wait interrupted", ex); - } - }); - LogProcessor processor = - BatchLogProcessor.builder(exporter) - .setScheduleDelayMillis(3000) // Long enough to not be in play - .setMaxExportBatchSize(5) - .setMaxQueueSize(10) - .build(); - LogSinkSdkProvider provider = LogSinkSdkProvider.builder().addLogProcessor(processor).build(); - LogSink sink = provider.get("test", "0.1a"); - - long start = System.currentTimeMillis(); - int testRecordCount = 700; - for (int i = 0; i < testRecordCount; i++) { - sink.offer(createLog(Severity.WARN, "test #" + i)); - } - long end = System.currentTimeMillis(); - assertThat(end - start).isLessThan(250L); - provider.forceFlush().join(1, TimeUnit.SECONDS); - assertThat(exporter.getRecords().size()).isLessThan(testRecordCount); // We dropped records - } - - @Test - void testMultipleProcessors() { - TestLogProcessor processorOne = new TestLogProcessor(); - TestLogProcessor processorTwo = new TestLogProcessor(); - LogSinkSdkProvider provider = - LogSinkSdkProvider.builder() - .addLogProcessor(processorOne) - .addLogProcessor(processorTwo) - .build(); - LogSink sink = provider.get("test", "0.1"); - LogRecord record = createLog(Severity.INFO, "test"); - sink.offer(record); - assertThat(processorOne.getRecords().size()).isEqualTo(1); - assertThat(processorTwo.getRecords().size()).isEqualTo(1); - assertThat(processorOne.getRecords().get(0)).isEqualTo(record); - assertThat(processorTwo.getRecords().get(0)).isEqualTo(record); - - CompletableResultCode flushResult = provider.forceFlush(); - flushResult.join(1, TimeUnit.SECONDS); - assertThat(processorOne.getFlushes()).isEqualTo(1); - assertThat(processorTwo.getFlushes()).isEqualTo(1); - - CompletableResultCode shutdownResult = provider.shutdown(); - shutdownResult.join(1, TimeUnit.SECONDS); - assertThat(processorOne.shutdownHasBeenCalled()).isEqualTo(true); - assertThat(processorTwo.shutdownHasBeenCalled()).isEqualTo(true); - } -} diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/MultiLogProcessorTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/MultiLogProcessorTest.java new file mode 100644 index 00000000000..5d8e1c23585 --- /dev/null +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/MultiLogProcessorTest.java @@ -0,0 +1,70 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.logs; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.same; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.logs.data.LogData; +import io.opentelemetry.sdk.logs.data.Severity; +import io.opentelemetry.sdk.logs.util.TestUtil; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +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 MultiLogProcessorTest { + + @Mock private LogProcessor logProcessor1; + @Mock private LogProcessor logProcessor2; + private static final LogData logData = TestUtil.createLogData(Severity.DEBUG, "message"); + + @BeforeEach + void setup() { + when(logProcessor1.forceFlush()).thenReturn(CompletableResultCode.ofSuccess()); + when(logProcessor2.forceFlush()).thenReturn(CompletableResultCode.ofSuccess()); + when(logProcessor1.shutdown()).thenReturn(CompletableResultCode.ofSuccess()); + when(logProcessor2.shutdown()).thenReturn(CompletableResultCode.ofSuccess()); + } + + @Test + void empty() { + LogProcessor multiLogProcessor = LogProcessor.composite(); + assertThat(multiLogProcessor).isInstanceOf(NoopLogProcessor.class); + multiLogProcessor.emit(logData); + multiLogProcessor.shutdown(); + } + + @Test + void oneLogProcessor() { + LogProcessor multiLogProcessor = LogProcessor.composite(logProcessor1); + assertThat(multiLogProcessor).isSameAs(logProcessor1); + } + + @Test + void twoLogProcessor() { + LogProcessor multiLogProcessor = LogProcessor.composite(logProcessor1, logProcessor2); + multiLogProcessor.emit(logData); + verify(logProcessor1).emit(same(logData)); + verify(logProcessor2).emit(same(logData)); + + multiLogProcessor.forceFlush(); + verify(logProcessor1).forceFlush(); + verify(logProcessor2).forceFlush(); + + multiLogProcessor.shutdown(); + verify(logProcessor1).shutdown(); + verify(logProcessor2).shutdown(); + } +} diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/NoopLogProcessorTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/NoopLogProcessorTest.java new file mode 100644 index 00000000000..40ac3f57820 --- /dev/null +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/NoopLogProcessorTest.java @@ -0,0 +1,23 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.logs; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import io.opentelemetry.sdk.logs.data.Severity; +import io.opentelemetry.sdk.logs.util.TestUtil; +import org.junit.jupiter.api.Test; + +class NoopLogProcessorTest { + + @Test + void noCrash() { + LogProcessor logProcessor = NoopLogProcessor.getInstance(); + logProcessor.emit(TestUtil.createLogData(Severity.DEBUG, "message")); + assertThat(logProcessor.forceFlush().isSuccess()).isEqualTo(true); + assertThat(logProcessor.shutdown().isSuccess()).isEqualTo(true); + } +} 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 new file mode 100644 index 00000000000..32b05de2738 --- /dev/null +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogEmitterProviderTest.java @@ -0,0 +1,182 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +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.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; +import io.opentelemetry.sdk.resources.Resource; +import org.assertj.core.api.InstanceOfAssertFactories; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +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 SdkLogEmitterProviderTest { + + @Mock private LogProcessor logProcessor; + + private SdkLogEmitterProvider sdkLogEmitterProvider; + + @BeforeEach + void setup() { + sdkLogEmitterProvider = SdkLogEmitterProvider.builder().addLogProcessor(logProcessor).build(); + when(logProcessor.forceFlush()).thenReturn(CompletableResultCode.ofSuccess()); + when(logProcessor.shutdown()).thenReturn(CompletableResultCode.ofSuccess()); + } + + @Test + void builder_defaultResource() { + assertThat(SdkLogEmitterProvider.builder().build()) + .extracting("sharedState", as(InstanceOfAssertFactories.type(LogEmitterSharedState.class))) + .extracting(LogEmitterSharedState::getResource) + .isEqualTo(Resource.getDefault()); + } + + @Test + void builder_resourceProvided() { + Resource resource = Resource.create(Attributes.builder().put("key", "value").build()); + + assertThat(SdkLogEmitterProvider.builder().setResource(resource).build()) + .extracting("sharedState", as(InstanceOfAssertFactories.type(LogEmitterSharedState.class))) + .extracting(LogEmitterSharedState::getResource) + .isEqualTo(resource); + } + + @Test + void builder_noProcessor() { + assertThat(SdkLogEmitterProvider.builder().build()) + .extracting("sharedState", as(InstanceOfAssertFactories.type(LogEmitterSharedState.class))) + .extracting(LogEmitterSharedState::getLogProcessor) + .isSameAs(NoopLogProcessor.getInstance()); + } + + @Test + void builder_multipleProcessors() { + assertThat( + SdkLogEmitterProvider.builder() + .addLogProcessor(logProcessor) + .addLogProcessor(logProcessor) + .build()) + .extracting("sharedState", as(InstanceOfAssertFactories.type(LogEmitterSharedState.class))) + .extracting(LogEmitterSharedState::getLogProcessor) + .satisfies( + activeLogProcessor -> { + assertThat(activeLogProcessor).isInstanceOf(MultiLogProcessor.class); + assertThat(activeLogProcessor) + .extracting( + "logProcessors", as(InstanceOfAssertFactories.list(LogProcessor.class))) + .hasSize(2); + }); + } + + @Test + void logEmitterBuilder_SameName() { + assertThat(sdkLogEmitterProvider.logEmitterBuilder("test").build()) + .isSameAs(sdkLogEmitterProvider.logEmitterBuilder("test").build()) + .isNotSameAs( + sdkLogEmitterProvider + .logEmitterBuilder("test") + .setInstrumentationVersion("version") + .build()); + } + + @Test + void logEmitterBuilder_SameNameAndVersion() { + assertThat( + sdkLogEmitterProvider + .logEmitterBuilder("test") + .setInstrumentationVersion("version") + .build()) + .isSameAs( + sdkLogEmitterProvider + .logEmitterBuilder("test") + .setInstrumentationVersion("version") + .build()) + .isNotSameAs( + sdkLogEmitterProvider + .logEmitterBuilder("test") + .setInstrumentationVersion("version") + .setSchemaUrl("http://url") + .build()); + } + + @Test + void logEmitterBuilder_SameNameVersionAndSchema() { + assertThat( + sdkLogEmitterProvider + .logEmitterBuilder("test") + .setInstrumentationVersion("version") + .setSchemaUrl("http://url") + .build()) + .isSameAs( + sdkLogEmitterProvider + .logEmitterBuilder("test") + .setInstrumentationVersion("version") + .setSchemaUrl("http://url") + .build()); + } + + @Test + void logEmitterBuilder_PropagatesToEmitter() { + InstrumentationLibraryInfo expected = + InstrumentationLibraryInfo.create("test", "version", "http://url"); + assertThat( + ((SdkLogEmitter) + sdkLogEmitterProvider + .logEmitterBuilder("test") + .setInstrumentationVersion("version") + .setSchemaUrl("http://url") + .build()) + .getInstrumentationLibraryInfo()) + .isEqualTo(expected); + } + + @Test + void logEmitterBuilder_DefaultEmitterName() { + assertThat( + ((SdkLogEmitter) sdkLogEmitterProvider.logEmitterBuilder(null).build()) + .getInstrumentationLibraryInfo() + .getName()) + .isEqualTo(SdkLogEmitterProvider.DEFAULT_EMITTER_NAME); + + assertThat( + ((SdkLogEmitter) sdkLogEmitterProvider.logEmitterBuilder("").build()) + .getInstrumentationLibraryInfo() + .getName()) + .isEqualTo(SdkLogEmitterProvider.DEFAULT_EMITTER_NAME); + } + + @Test + void forceFlush() { + sdkLogEmitterProvider.forceFlush(); + verify(logProcessor).forceFlush(); + } + + @Test + void shutdown() { + sdkLogEmitterProvider.shutdown(); + sdkLogEmitterProvider.shutdown(); + verify(logProcessor, times(1)).shutdown(); + } + + @Test + void close() { + sdkLogEmitterProvider.close(); + verify(logProcessor).shutdown(); + } +} 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 new file mode 100644 index 00000000000..ba217108527 --- /dev/null +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogEmitterTest.java @@ -0,0 +1,80 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +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.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 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(); + + ArgumentCaptor captor = ArgumentCaptor.forClass(LogData.class); + verify(logProcessor).emit(captor.capture()); + + 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); + } + + @Test + void emit_AfterShutdown() { + sdkLogEmitterProvider.shutdown().join(10, TimeUnit.SECONDS); + + sdkLogEmitter.logBuilder().setEpoch(Instant.now()).setBody("message").emit(); + verify(logProcessor, never()).emit(any()); + } +} diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/export/BatchLogProcessorTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/export/BatchLogProcessorTest.java index f983de0f7a9..2e0ba4cc91d 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/export/BatchLogProcessorTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/export/BatchLogProcessorTest.java @@ -5,18 +5,84 @@ package io.opentelemetry.sdk.logs.export; -import static io.opentelemetry.sdk.logs.util.TestUtil.createLog; +import static io.opentelemetry.sdk.logs.util.TestUtil.createLogData; +import static org.assertj.core.api.Assertions.fail; import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; import static org.awaitility.Awaitility.await; -import io.opentelemetry.sdk.logs.data.LogRecord; +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.logs.LogEmitter; +import io.opentelemetry.sdk.logs.LogProcessor; +import io.opentelemetry.sdk.logs.SdkLogEmitterProvider; +import io.opentelemetry.sdk.logs.data.LogData; import io.opentelemetry.sdk.logs.data.Severity; import io.opentelemetry.sdk.logs.util.TestLogExporter; +import java.time.Duration; import java.util.concurrent.TimeUnit; +import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; class BatchLogProcessorTest { + @Test + void testBatchSize() { + TestLogExporter exporter = new TestLogExporter(); + LogProcessor processor = + BatchLogProcessor.builder(exporter) + .setScheduleDelayMillis(10000) // Long enough to not be in play + .setMaxExportBatchSize(5) + .setMaxQueueSize(10) + .build(); + SdkLogEmitterProvider provider = + SdkLogEmitterProvider.builder().addLogProcessor(processor).build(); + LogEmitter emitter = + provider.logEmitterBuilder("test").setInstrumentationVersion("0.1a").build(); + + for (int i = 0; i < 7; i++) { + emitter.logBuilder().setSeverity(Severity.WARN).setBody("test #" + i).emit(); + } + // Ensure that more than batch size kicks off a flush + await().atMost(Duration.ofSeconds(5)).until(() -> exporter.getRecords().size() > 0); + // Ensure that everything gets through + CompletableResultCode result = provider.forceFlush(); + result.join(1, TimeUnit.SECONDS); + Assertions.assertThat(exporter.getCallCount()).isGreaterThanOrEqualTo(2); + } + + @Test + void testNoBlocking() { + TestLogExporter exporter = new TestLogExporter(); + exporter.setOnCall( + () -> { + try { + Thread.sleep(250); + } catch (InterruptedException ex) { + fail("Exporter wait interrupted", ex); + } + }); + LogProcessor processor = + BatchLogProcessor.builder(exporter) + .setScheduleDelayMillis(3000) // Long enough to not be in play + .setMaxExportBatchSize(5) + .setMaxQueueSize(10) + .build(); + SdkLogEmitterProvider provider = + SdkLogEmitterProvider.builder().addLogProcessor(processor).build(); + LogEmitter emitter = + provider.logEmitterBuilder("test").setInstrumentationVersion("0.1a").build(); + + long start = System.currentTimeMillis(); + int testRecordCount = 700; + for (int i = 0; i < testRecordCount; i++) { + emitter.logBuilder().setSeverity(Severity.WARN).setBody("test #" + i).emit(); + } + long end = System.currentTimeMillis(); + Assertions.assertThat(end - start).isLessThan(250L); + provider.forceFlush().join(1, TimeUnit.SECONDS); + Assertions.assertThat(exporter.getRecords().size()) + .isLessThan(testRecordCount); // We dropped records + } + @Test void testForceExport() { int batchSize = 10; @@ -29,8 +95,8 @@ void testForceExport() { .setScheduleDelayMillis(2000) // longer than test .build(); for (int i = 0; i < 17; i++) { - LogRecord record = createLog(Severity.INFO, Integer.toString(i)); - processor.addLogRecord(record); + LogData logData = createLogData(Severity.INFO, Integer.toString(i)); + processor.emit(logData); } await().until(() -> exporter.getCallCount() > 0); assertThat(exporter.getRecords().size()).isEqualTo(batchSize); diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/export/InMemoryLogExporterTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/export/InMemoryLogExporterTest.java index 49297f9be28..15644382fba 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/export/InMemoryLogExporterTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/export/InMemoryLogExporterTest.java @@ -6,13 +6,12 @@ package io.opentelemetry.sdk.logs.export; import static io.opentelemetry.sdk.logs.data.Severity.DEBUG; -import static io.opentelemetry.sdk.logs.util.TestUtil.createLog; +import static io.opentelemetry.sdk.logs.util.TestUtil.createLogData; import static org.assertj.core.api.Assertions.assertThat; -import io.opentelemetry.sdk.logs.LogSink; -import io.opentelemetry.sdk.logs.LogSinkSdkProvider; +import io.opentelemetry.sdk.logs.LogEmitter; +import io.opentelemetry.sdk.logs.SdkLogEmitterProvider; import io.opentelemetry.sdk.logs.data.LogData; -import io.opentelemetry.sdk.logs.data.LogRecord; import java.util.Collections; import java.util.List; import org.junit.jupiter.api.AfterEach; @@ -23,26 +22,28 @@ class InMemoryLogExporterTest { private final InMemoryLogExporter exporter = InMemoryLogExporter.create(); - private LogSinkSdkProvider logSinkSdkProvider; - private LogSink logSink; + private SdkLogEmitterProvider logEmitterProvider; + private LogEmitter logEmitter; @BeforeEach void setup() { - logSinkSdkProvider = - LogSinkSdkProvider.builder().addLogProcessor(SimpleLogProcessor.create(exporter)).build(); - logSink = logSinkSdkProvider.get(null, null); + logEmitterProvider = + SdkLogEmitterProvider.builder() + .addLogProcessor(SimpleLogProcessor.create(exporter)) + .build(); + logEmitter = logEmitterProvider.logEmitterBuilder("emitter").build(); } @AfterEach void tearDown() { - logSinkSdkProvider.shutdown(); + logEmitterProvider.shutdown(); } @Test void getFinishedLogItems() { - logSink.offer(createLog(DEBUG, "message 1")); - logSink.offer(createLog(DEBUG, "message 2")); - logSink.offer(createLog(DEBUG, "message 3")); + logEmitter.logBuilder().setSeverity(DEBUG).setBody("message 1").emit(); + logEmitter.logBuilder().setSeverity(DEBUG).setBody("message 2").emit(); + logEmitter.logBuilder().setSeverity(DEBUG).setBody("message 3").emit(); List logItems = exporter.getFinishedLogItems(); assertThat(logItems).isNotNull(); @@ -54,9 +55,9 @@ void getFinishedLogItems() { @Test void reset() { - logSink.offer(createLog(DEBUG, "message 1")); - logSink.offer(createLog(DEBUG, "message 2")); - logSink.offer(createLog(DEBUG, "message 3")); + logEmitter.logBuilder().setSeverity(DEBUG).setBody("message 1").emit(); + logEmitter.logBuilder().setSeverity(DEBUG).setBody("message 2").emit(); + logEmitter.logBuilder().setSeverity(DEBUG).setBody("message 3").emit(); List logItems = exporter.getFinishedLogItems(); assertThat(logItems).isNotNull(); assertThat(logItems.size()).isEqualTo(3); @@ -67,9 +68,9 @@ void reset() { @Test void shutdown() { - logSink.offer(createLog(DEBUG, "message 1")); - logSink.offer(createLog(DEBUG, "message 2")); - logSink.offer(createLog(DEBUG, "message 3")); + logEmitter.logBuilder().setSeverity(DEBUG).setBody("message 1").emit(); + logEmitter.logBuilder().setSeverity(DEBUG).setBody("message 2").emit(); + logEmitter.logBuilder().setSeverity(DEBUG).setBody("message 3").emit(); List logItems = exporter.getFinishedLogItems(); assertThat(logItems).isNotNull(); assertThat(logItems.size()).isEqualTo(3); @@ -77,19 +78,19 @@ void shutdown() { exporter.shutdown(); assertThat(exporter.getFinishedLogItems()).isEmpty(); // Cannot add new elements after the shutdown. - logSink.offer(createLog(DEBUG, "message 1")); + logEmitter.logBuilder().setSeverity(DEBUG).setBody("message 1").emit(); assertThat(exporter.getFinishedLogItems()).isEmpty(); } @Test void export_ReturnCode() { - LogRecord logRecord = createLog(DEBUG, "message 1"); - assertThat(exporter.export(Collections.singletonList(logRecord)).isSuccess()).isTrue(); + LogData logData = createLogData(DEBUG, "message 1"); + assertThat(exporter.export(Collections.singletonList(logData)).isSuccess()).isTrue(); exporter.shutdown(); // After shutdown no more export. - assertThat(exporter.export(Collections.singletonList(logRecord)).isSuccess()).isFalse(); + assertThat(exporter.export(Collections.singletonList(logData)).isSuccess()).isFalse(); exporter.reset(); // Reset does not do anything if already shutdown. - assertThat(exporter.export(Collections.singletonList(logRecord)).isSuccess()).isFalse(); + assertThat(exporter.export(Collections.singletonList(logData)).isSuccess()).isFalse(); } } diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/export/SimpleLogProcessorTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/export/SimpleLogProcessorTest.java index 6ce3cfd4f45..b5915596c35 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/export/SimpleLogProcessorTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/export/SimpleLogProcessorTest.java @@ -16,7 +16,7 @@ import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.logs.LogProcessor; -import io.opentelemetry.sdk.logs.data.LogRecord; +import io.opentelemetry.sdk.logs.data.LogData; import io.opentelemetry.sdk.logs.util.TestUtil; import java.util.Collections; import org.junit.jupiter.api.BeforeEach; @@ -50,18 +50,18 @@ void create_NullExporter() { @Test void addLogRecord() { - LogRecord logRecord = TestUtil.createLog(DEBUG, "Log message"); - logProcessor.addLogRecord(logRecord); - verify(logExporter).export(Collections.singletonList(logRecord)); + LogData logData = TestUtil.createLogData(DEBUG, "Log message"); + logProcessor.emit(logData); + verify(logExporter).export(Collections.singletonList(logData)); } @Test void addLogRecord_ExporterError() { - LogRecord logRecord = TestUtil.createLog(DEBUG, "Log message"); + LogData logData = TestUtil.createLogData(DEBUG, "Log message"); when(logExporter.export(any())).thenThrow(new RuntimeException("Exporter error!")); - logProcessor.addLogRecord(logRecord); - logProcessor.addLogRecord(logRecord); - verify(logExporter, times(2)).export(Collections.singletonList(logRecord)); + logProcessor.emit(logData); + logProcessor.emit(logData); + verify(logExporter, times(2)).export(Collections.singletonList(logData)); } @Test @@ -71,11 +71,11 @@ void forceFlush() { when(logExporter.export(any())).thenReturn(export1, export2); - LogRecord logRecord = TestUtil.createLog(DEBUG, "Log message"); - logProcessor.addLogRecord(logRecord); - logProcessor.addLogRecord(logRecord); + LogData logData = TestUtil.createLogData(DEBUG, "Log message"); + logProcessor.emit(logData); + logProcessor.emit(logData); - verify(logExporter, times(2)).export(Collections.singletonList(logRecord)); + verify(logExporter, times(2)).export(Collections.singletonList(logData)); CompletableResultCode flush = logProcessor.forceFlush(); assertThat(flush.isDone()).isFalse(); @@ -95,11 +95,11 @@ void shutdown() { when(logExporter.export(any())).thenReturn(export1, export2); - LogRecord logRecord = TestUtil.createLog(DEBUG, "Log message"); - logProcessor.addLogRecord(logRecord); - logProcessor.addLogRecord(logRecord); + LogData logData = TestUtil.createLogData(DEBUG, "Log message"); + logProcessor.emit(logData); + logProcessor.emit(logData); - verify(logExporter, times(2)).export(Collections.singletonList(logRecord)); + verify(logExporter, times(2)).export(Collections.singletonList(logData)); CompletableResultCode shutdown = logProcessor.shutdown(); assertThat(shutdown.isDone()).isFalse(); diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/util/TestLogProcessor.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/util/TestLogProcessor.java deleted file mode 100644 index e92a5635e7b..00000000000 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/util/TestLogProcessor.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.logs.util; - -import io.opentelemetry.sdk.common.CompletableResultCode; -import io.opentelemetry.sdk.logs.LogProcessor; -import io.opentelemetry.sdk.logs.data.LogRecord; -import java.util.ArrayList; -import java.util.List; - -public class TestLogProcessor implements LogProcessor { - private final List records = new ArrayList<>(); - private boolean shutdownCalled = false; - private int flushes = 0; - - @Override - public void addLogRecord(LogRecord record) { - records.add(record); - } - - @Override - public CompletableResultCode shutdown() { - shutdownCalled = true; - return CompletableResultCode.ofSuccess(); - } - - @Override - public CompletableResultCode forceFlush() { - flushes++; - return CompletableResultCode.ofSuccess(); - } - - public List getRecords() { - return records; - } - - public int getFlushes() { - return flushes; - } - - public boolean shutdownHasBeenCalled() { - return shutdownCalled; - } -} 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 c0f6762ad55..194db14f8e1 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 @@ -10,17 +10,18 @@ import io.opentelemetry.api.trace.TraceFlags; import io.opentelemetry.api.trace.TraceId; import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; -import io.opentelemetry.sdk.logs.data.LogRecord; +import io.opentelemetry.sdk.logs.data.LogData; import io.opentelemetry.sdk.logs.data.Severity; import io.opentelemetry.sdk.resources.Resource; +import java.util.concurrent.TimeUnit; public final class TestUtil { - public static LogRecord createLog(Severity severity, String message) { - return LogRecord.builder( + public static LogData createLogData(Severity severity, String message) { + return LogData.builder( Resource.create(Attributes.builder().put("testKey", "testValue").build()), InstrumentationLibraryInfo.create("instrumentation", "1")) - .setEpochMillis(System.currentTimeMillis()) + .setEpoch(System.currentTimeMillis(), TimeUnit.MILLISECONDS) .setTraceId(TraceId.getInvalid()) .setSpanId(SpanId.getInvalid()) .setFlags(TraceFlags.getDefault().asByte())