diff --git a/api/events/build.gradle.kts b/api/events/build.gradle.kts index 9a0262cded0..d0aa3006cc4 100644 --- a/api/events/build.gradle.kts +++ b/api/events/build.gradle.kts @@ -10,4 +10,5 @@ otelJava.moduleName.set("io.opentelemetry.api.events") dependencies { api(project(":api:all")) + api(project(":extensions:incubator")) } diff --git a/api/events/src/main/java/io/opentelemetry/api/events/DefaultEventEmitter.java b/api/events/src/main/java/io/opentelemetry/api/events/DefaultEventEmitter.java index 8d9a81f8e7f..1cadacda8f7 100644 --- a/api/events/src/main/java/io/opentelemetry/api/events/DefaultEventEmitter.java +++ b/api/events/src/main/java/io/opentelemetry/api/events/DefaultEventEmitter.java @@ -6,6 +6,9 @@ package io.opentelemetry.api.events; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.logs.Severity; +import io.opentelemetry.context.Context; +import io.opentelemetry.extension.incubator.logs.AnyValue; import java.time.Instant; import java.util.concurrent.TimeUnit; @@ -20,10 +23,13 @@ static EventEmitter getInstance() { } @Override - public void emit(String eventName, Attributes attributes) {} + public void emit(String eventName) {} @Override - public EventBuilder builder(String eventName, Attributes attributes) { + public void emit(String eventName, AnyValue payload) {} + + @Override + public EventBuilder builder(String eventName) { return NoOpEventBuilder.INSTANCE; } @@ -31,6 +37,11 @@ private static class NoOpEventBuilder implements EventBuilder { public static final EventBuilder INSTANCE = new NoOpEventBuilder(); + @Override + public EventBuilder setPayload(AnyValue payload) { + return this; + } + @Override public EventBuilder setTimestamp(long timestamp, TimeUnit unit) { return this; @@ -41,6 +52,21 @@ public EventBuilder setTimestamp(Instant instant) { return this; } + @Override + public EventBuilder setContext(Context context) { + return this; + } + + @Override + public EventBuilder setSeverity(Severity severity) { + return this; + } + + @Override + public EventBuilder setAttributes(Attributes attributes) { + return this; + } + @Override public void emit() {} } diff --git a/api/events/src/main/java/io/opentelemetry/api/events/DefaultEventEmitterProvider.java b/api/events/src/main/java/io/opentelemetry/api/events/DefaultEventEmitterProvider.java index 2f5b69826fd..59f75872fa1 100644 --- a/api/events/src/main/java/io/opentelemetry/api/events/DefaultEventEmitterProvider.java +++ b/api/events/src/main/java/io/opentelemetry/api/events/DefaultEventEmitterProvider.java @@ -34,11 +34,6 @@ public EventEmitterBuilder setInstrumentationVersion(String instrumentationVersi return this; } - @Override - public EventEmitterBuilder setEventDomain(String eventDomain) { - return this; - } - @Override public EventEmitter build() { return DefaultEventEmitter.getInstance(); diff --git a/api/events/src/main/java/io/opentelemetry/api/events/EventBuilder.java b/api/events/src/main/java/io/opentelemetry/api/events/EventBuilder.java index a9acabbca6c..ba7cddd9ce9 100644 --- a/api/events/src/main/java/io/opentelemetry/api/events/EventBuilder.java +++ b/api/events/src/main/java/io/opentelemetry/api/events/EventBuilder.java @@ -5,14 +5,37 @@ package io.opentelemetry.api.events; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.logs.Severity; +import io.opentelemetry.context.Context; +import io.opentelemetry.extension.incubator.logs.AnyValue; import java.time.Instant; +import java.util.Map; import java.util.concurrent.TimeUnit; /** The EventBuilder is used to {@link #emit()} events. */ public interface EventBuilder { /** - * Set the epoch {@code timestamp} for the event, using the timestamp and unit. + * Set the {@code payload}. + * + *

The {@code payload} is expected to match the schema of other events with the same {@code + * eventName}. + */ + EventBuilder setPayload(AnyValue payload); + + /** + * Set the {@code payload}. + * + *

The {@code payload} is expected to match the schema of other events with the same {@code + * eventName}. + */ + default EventBuilder setPayload(Map> payload) { + return setPayload(AnyValue.of(payload)); + } + + /** + * Set the epoch {@code timestamp}, using the timestamp and unit. * *

The {@code timestamp} is the time at which the event occurred. If unset, it will be set to * the current time when {@link #emit()} is called. @@ -20,13 +43,27 @@ public interface EventBuilder { EventBuilder setTimestamp(long timestamp, TimeUnit unit); /** - * Set the epoch {@code timestamp} for the event, using the instant. + * Set the epoch {@code timestamp}t, using the instant. * *

The {@code timestamp} is the time at which the event occurred. If unset, it will be set to * the current time when {@link #emit()} is called. */ EventBuilder setTimestamp(Instant instant); + /** Set the context. */ + EventBuilder setContext(Context context); + + /** Set the severity. */ + EventBuilder setSeverity(Severity severity); + + /** + * Set the attributes. + * + *

Event {@link io.opentelemetry.api.common.Attributes} provide additional details about the + * Event which are not part of the well-defined {@link AnyValue} {@code payload}. + */ + EventBuilder setAttributes(Attributes attributes); + /** Emit an event. */ void emit(); } diff --git a/api/events/src/main/java/io/opentelemetry/api/events/EventEmitter.java b/api/events/src/main/java/io/opentelemetry/api/events/EventEmitter.java index a8dc47c83d7..292aebdde4d 100644 --- a/api/events/src/main/java/io/opentelemetry/api/events/EventEmitter.java +++ b/api/events/src/main/java/io/opentelemetry/api/events/EventEmitter.java @@ -5,7 +5,8 @@ package io.opentelemetry.api.events; -import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.extension.incubator.logs.AnyValue; +import java.util.Map; import javax.annotation.concurrent.ThreadSafe; /** @@ -13,17 +14,17 @@ * *

Example usage emitting events: * + *

// TODO: rework + * *

{@code
  * class MyClass {
  *   private final EventEmitter eventEmitter = openTelemetryEventEmitterProvider.eventEmitterBuilder("scope-name")
- *         .setEventDomain("acme.observability")
  *         .build();
  *
  *   void doWork() {
- *     eventEmitter.emit("my-event", Attributes.builder()
- *         .put("key1", "value1")
- *         .put("key2", "value2")
- *         .build())
+ *     eventEmitter.emit("namespace.my-event", AnyValue.of(Map.of(
+ *        "key1", AnyValue.of("value1"),
+ *        "key2", AnyValue.of("value2"))));
  *     // do work
  *   }
  * }
@@ -35,18 +36,41 @@ public interface EventEmitter {
   /**
    * Emit an event.
    *
-   * @param eventName the event name, which acts as a classifier for events. Within a particular
-   *     event domain, event name defines a particular class or type of event.
-   * @param attributes attributes associated with the event
+   * @param eventName the event name, which defines the class or type of event. Events names SHOULD
+   *     include a namespace to avoid collisions with other event names.
+   */
+  void emit(String eventName);
+
+  /**
+   * Emit an event.
+   *
+   * @param eventName the event name, which defines the class or type of event. Events names SHOULD
+   *     include a namespace to avoid collisions with other event names.
+   * @param payload the eventPayload, which is expected to match the schema of other events with the
+   *     same {@code eventName}.
+   */
+  void emit(String eventName, AnyValue payload);
+
+  /**
+   * Emit an event.
+   *
+   * 

This is equivalent to calling {@link #emit(String, AnyValue)} with a {@link + * AnyValue#of(Map)} payload. + * + * @param eventName the event name, which defines the class or type of event. Events names SHOULD + * include a namespace to avoid collisions with other event names. + * @param payload the eventPayload, which is expected to match the schema of other events with the + * same {@code eventName}. */ - void emit(String eventName, Attributes attributes); + default void emit(String eventName, Map> payload) { + emit(eventName, AnyValue.of(payload)); + } /** * Return a {@link EventBuilder} to emit an event. * - * @param eventName the event name, which acts as a classifier for events. Within a particular - * event domain, event name defines a particular class or type of event. - * @param attributes attributes associated with the event + * @param eventName the event name, which defines the class or type of event. Events names SHOULD + * include a namespace to avoid collisions with other event names. */ - EventBuilder builder(String eventName, Attributes attributes); + EventBuilder builder(String eventName); } diff --git a/api/events/src/main/java/io/opentelemetry/api/events/EventEmitterBuilder.java b/api/events/src/main/java/io/opentelemetry/api/events/EventEmitterBuilder.java index 0aa67a25b08..0bdb9e2f57e 100644 --- a/api/events/src/main/java/io/opentelemetry/api/events/EventEmitterBuilder.java +++ b/api/events/src/main/java/io/opentelemetry/api/events/EventEmitterBuilder.java @@ -14,15 +14,6 @@ */ public interface EventEmitterBuilder { - /** - * Sets the event domain. Event domain is not part of {@link EventEmitter} identity. - * - * @param eventDomain The event domain, which acts as a namespace for event names. Within a - * particular event domain, event name defines a particular class or type of event. - * @return this - */ - EventEmitterBuilder setEventDomain(String eventDomain); - /** * Set the scope schema URL of the resulting {@link EventEmitter}. Schema URL is part of {@link * EventEmitter} identity. diff --git a/api/events/src/test/java/io/opentelemetry/api/events/DefaultEventEmitterProviderTest.java b/api/events/src/test/java/io/opentelemetry/api/events/DefaultEventEmitterProviderTest.java index 33651e89c6e..ea0d51daaef 100644 --- a/api/events/src/test/java/io/opentelemetry/api/events/DefaultEventEmitterProviderTest.java +++ b/api/events/src/test/java/io/opentelemetry/api/events/DefaultEventEmitterProviderTest.java @@ -8,7 +8,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; -import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.extension.incubator.logs.AnyValue; import org.junit.jupiter.api.Test; class DefaultEventEmitterProviderTest { @@ -23,7 +23,6 @@ void noopEventEmitterProvider_doesNotThrow() { () -> provider .eventEmitterBuilder("scope-name") - .setEventDomain("event-domain") .setInstrumentationVersion("1.0") .setSchemaUrl("http://schema.com") .build()) @@ -34,7 +33,7 @@ void noopEventEmitterProvider_doesNotThrow() { provider .eventEmitterBuilder("scope-name") .build() - .emit("event-name", Attributes.empty())) + .emit("namespace.event-name", AnyValue.of("payload"))) .doesNotThrowAnyException(); } } diff --git a/api/events/src/test/java/io/opentelemetry/api/events/DefaultEventEmitterTest.java b/api/events/src/test/java/io/opentelemetry/api/events/DefaultEventEmitterTest.java index 460cb1583ac..f7c8e041e74 100644 --- a/api/events/src/test/java/io/opentelemetry/api/events/DefaultEventEmitterTest.java +++ b/api/events/src/test/java/io/opentelemetry/api/events/DefaultEventEmitterTest.java @@ -8,7 +8,11 @@ import static org.assertj.core.api.Assertions.assertThatCode; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.logs.Severity; +import io.opentelemetry.context.Context; +import io.opentelemetry.extension.incubator.logs.AnyValue; import java.time.Instant; +import java.util.Collections; import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.Test; @@ -16,25 +20,40 @@ class DefaultEventEmitterTest { @Test void emit() { - assertThatCode(() -> DefaultEventEmitter.getInstance().emit("event-name", Attributes.empty())) + assertThatCode(() -> DefaultEventEmitter.getInstance().emit("namespace.event-name")) .doesNotThrowAnyException(); + + assertThatCode( + () -> + DefaultEventEmitter.getInstance() + .emit( + "namespace.event-name", + AnyValue.of(Collections.singletonMap("key1", AnyValue.of("value1"))))) + .doesNotThrowAnyException(); + assertThatCode( () -> DefaultEventEmitter.getInstance() - .emit("event-name", Attributes.builder().put("key1", "value1").build())) + .emit( + "namespace.event-name", + Collections.singletonMap("key1", AnyValue.of("value1")))) .doesNotThrowAnyException(); } @Test void builder() { - Attributes attributes = Attributes.builder().put("key1", "value1").build(); EventEmitter emitter = DefaultEventEmitter.getInstance(); assertThatCode( () -> emitter - .builder("myEvent", attributes) + .builder("namespace.myEvent") + .setPayload(AnyValue.of("payload")) + .setPayload(Collections.singletonMap("key1", AnyValue.of("value1"))) .setTimestamp(123456L, TimeUnit.NANOSECONDS) .setTimestamp(Instant.now()) + .setContext(Context.current()) + .setSeverity(Severity.DEBUG) + .setAttributes(Attributes.empty()) .emit()) .doesNotThrowAnyException(); } diff --git a/integration-tests/otlp/src/main/java/io/opentelemetry/integrationtest/OtlpExporterIntegrationTest.java b/integration-tests/otlp/src/main/java/io/opentelemetry/integrationtest/OtlpExporterIntegrationTest.java index 7bfa82a3876..b07c4242bf0 100644 --- a/integration-tests/otlp/src/main/java/io/opentelemetry/integrationtest/OtlpExporterIntegrationTest.java +++ b/integration-tests/otlp/src/main/java/io/opentelemetry/integrationtest/OtlpExporterIntegrationTest.java @@ -528,7 +528,6 @@ private static void testLogRecordExporter(LogRecordExporter logRecordExporter) { EventEmitter eventEmitter = SdkEventEmitterProvider.create(loggerProvider) .eventEmitterBuilder(OtlpExporterIntegrationTest.class.getName()) - .setEventDomain("event-domain") .build(); SpanContext spanContext = @@ -548,7 +547,10 @@ private static void testLogRecordExporter(LogRecordExporter logRecordExporter) { .setSeverityText("DEBUG") .setContext(Context.current()) .emit(); - eventEmitter.emit("event-name", Attributes.builder().put("key", "value").build()); + eventEmitter.emit( + "namespace.event-name", + Collections.singletonMap( + "key", io.opentelemetry.extension.incubator.logs.AnyValue.of("value"))); } // Closing triggers flush of processor @@ -597,20 +599,18 @@ private static void testLogRecordExporter(LogRecordExporter logRecordExporter) { // LogRecord via EventEmitter.emit(String, Attributes) io.opentelemetry.proto.logs.v1.LogRecord protoLog2 = ilLogs.getLogRecords(1); - assertThat(protoLog2.getBody().getStringValue()).isEmpty(); + assertThat(protoLog2.getBody()) + .isEqualTo( + AnyValue.newBuilder() + // TODO: update after merging + // https://github.com/open-telemetry/opentelemetry-java/pull/5938 + .setStringValue("[key=value]") + .build()); assertThat(protoLog2.getAttributesList()) .containsExactlyInAnyOrder( - KeyValue.newBuilder() - .setKey("event.domain") - .setValue(AnyValue.newBuilder().setStringValue("event-domain").build()) - .build(), KeyValue.newBuilder() .setKey("event.name") - .setValue(AnyValue.newBuilder().setStringValue("event-name").build()) - .build(), - KeyValue.newBuilder() - .setKey("key") - .setValue(AnyValue.newBuilder().setStringValue("value").build()) + .setValue(AnyValue.newBuilder().setStringValue("namespace.event-name").build()) .build()); assertThat(protoLog2.getSeverityText()).isEmpty(); assertThat(TraceId.fromBytes(protoLog2.getTraceId().toByteArray())) diff --git a/sdk-extensions/autoconfigure/src/testFullConfig/java/io/opentelemetry/sdk/autoconfigure/FullConfigTest.java b/sdk-extensions/autoconfigure/src/testFullConfig/java/io/opentelemetry/sdk/autoconfigure/FullConfigTest.java index affe5d4fd63..4490c7d4f42 100644 --- a/sdk-extensions/autoconfigure/src/testFullConfig/java/io/opentelemetry/sdk/autoconfigure/FullConfigTest.java +++ b/sdk-extensions/autoconfigure/src/testFullConfig/java/io/opentelemetry/sdk/autoconfigure/FullConfigTest.java @@ -38,10 +38,12 @@ import io.opentelemetry.proto.collector.trace.v1.TraceServiceGrpc; import io.opentelemetry.proto.common.v1.AnyValue; import io.opentelemetry.proto.common.v1.KeyValue; +import io.opentelemetry.proto.logs.v1.SeverityNumber; import io.opentelemetry.proto.metrics.v1.Metric; import io.opentelemetry.sdk.OpenTelemetrySdk; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingDeque; @@ -207,11 +209,12 @@ void configures() throws Exception { logger.logRecordBuilder().setBody("info log message").setSeverity(Severity.INFO).emit(); EventEmitter eventEmitter = - GlobalEventEmitterProvider.get() - .eventEmitterBuilder("test") - .setEventDomain("test-domain") - .build(); - eventEmitter.emit("test-name", Attributes.builder().put("cow", "moo").build()); + GlobalEventEmitterProvider.get().eventEmitterBuilder("test").build(); + eventEmitter.emit( + "namespace.test-name", + io.opentelemetry.extension.incubator.logs.AnyValue.of( + Collections.singletonMap( + "cow", io.opentelemetry.extension.incubator.logs.AnyValue.of("moo")))); openTelemetrySdk.getSdkTracerProvider().forceFlush().join(10, TimeUnit.SECONDS); openTelemetrySdk.getSdkLoggerProvider().forceFlush().join(10, TimeUnit.SECONDS); @@ -333,21 +336,20 @@ void configures() throws Exception { assertThat(logRecord.getSeverityNumberValue()) .isEqualTo(Severity.INFO.getSeverityNumber()); }, - logRecord -> - assertThat(logRecord.getAttributesList()) - .containsExactlyInAnyOrder( - KeyValue.newBuilder() - .setKey("event.domain") - .setValue(AnyValue.newBuilder().setStringValue("test-domain").build()) - .build(), - KeyValue.newBuilder() - .setKey("event.name") - .setValue(AnyValue.newBuilder().setStringValue("test-name").build()) - .build(), - KeyValue.newBuilder() - .setKey("cow") - .setValue(AnyValue.newBuilder().setStringValue("moo").build()) - .build())); + logRecord -> { + // TODO: update after merging + // https://github.com/open-telemetry/opentelemetry-java/pull/5938 + assertThat(logRecord.getBody().getStringValue()).isEqualTo("[cow=moo]"); + assertThat(logRecord.getSeverityNumber()) + .isEqualTo(SeverityNumber.SEVERITY_NUMBER_INFO); + assertThat(logRecord.getAttributesList()) + .containsExactlyInAnyOrder( + KeyValue.newBuilder() + .setKey("event.name") + .setValue( + AnyValue.newBuilder().setStringValue("namespace.test-name").build()) + .build()); + }); } private static List getFirstDataPointLabels(Metric metric) { diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/SdkEventBuilder.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/SdkEventBuilder.java index a79b09babc3..d52cf6a39d0 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/SdkEventBuilder.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/SdkEventBuilder.java @@ -5,37 +5,75 @@ package io.opentelemetry.sdk.logs.internal; +import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.events.EventBuilder; import io.opentelemetry.api.logs.LogRecordBuilder; +import io.opentelemetry.api.logs.Severity; +import io.opentelemetry.context.Context; +import io.opentelemetry.extension.incubator.logs.AnyValue; +import io.opentelemetry.extension.incubator.logs.ExtendedLogRecordBuilder; +import io.opentelemetry.sdk.common.Clock; import java.time.Instant; import java.util.concurrent.TimeUnit; class SdkEventBuilder implements EventBuilder { + private final Clock clock; private final LogRecordBuilder logRecordBuilder; - private final String eventDomain; private final String eventName; + private boolean hasTimestamp = false; - SdkEventBuilder(LogRecordBuilder logRecordBuilder, String eventDomain, String eventName) { + SdkEventBuilder(Clock clock, LogRecordBuilder logRecordBuilder, String eventName) { + this.clock = clock; this.logRecordBuilder = logRecordBuilder; - this.eventDomain = eventDomain; this.eventName = eventName; } + @Override + public EventBuilder setPayload(AnyValue payload) { + ((ExtendedLogRecordBuilder) logRecordBuilder).setBody(payload); + return this; + } + @Override public EventBuilder setTimestamp(long timestamp, TimeUnit unit) { this.logRecordBuilder.setTimestamp(timestamp, unit); + this.hasTimestamp = true; return this; } @Override public EventBuilder setTimestamp(Instant instant) { this.logRecordBuilder.setTimestamp(instant); + this.hasTimestamp = true; + return this; + } + + @Override + public EventBuilder setContext(Context context) { + logRecordBuilder.setContext(context); + return this; + } + + @Override + public EventBuilder setSeverity(Severity severity) { + logRecordBuilder.setSeverity(severity); + return this; + } + + @Override + public EventBuilder setAttributes(Attributes attributes) { + logRecordBuilder.setAllAttributes(attributes); return this; } @Override public void emit() { - SdkEventEmitterProvider.addEventNameAndDomain(logRecordBuilder, eventDomain, eventName); + long now = clock.now(); + logRecordBuilder.setObservedTimestamp(now, TimeUnit.NANOSECONDS); + if (!hasTimestamp) { + logRecordBuilder.setTimestamp(now, TimeUnit.NANOSECONDS); + } + SdkEventEmitterProvider.addEventName(logRecordBuilder, eventName); logRecordBuilder.emit(); } } diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/SdkEventEmitterProvider.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/SdkEventEmitterProvider.java index 1cc6768667e..d095f2397aa 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/SdkEventEmitterProvider.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/SdkEventEmitterProvider.java @@ -6,7 +6,6 @@ package io.opentelemetry.sdk.logs.internal; import io.opentelemetry.api.common.AttributeKey; -import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.events.EventBuilder; import io.opentelemetry.api.events.EventEmitter; import io.opentelemetry.api.events.EventEmitterBuilder; @@ -15,8 +14,13 @@ import io.opentelemetry.api.logs.Logger; import io.opentelemetry.api.logs.LoggerBuilder; import io.opentelemetry.api.logs.LoggerProvider; +import io.opentelemetry.api.logs.Severity; +import io.opentelemetry.context.Context; +import io.opentelemetry.extension.incubator.logs.AnyValue; +import io.opentelemetry.extension.incubator.logs.ExtendedLogRecordBuilder; import io.opentelemetry.sdk.common.Clock; import java.util.concurrent.TimeUnit; +import javax.annotation.Nullable; /** * SDK implementation for {@link EventEmitterProvider}. @@ -26,11 +30,8 @@ */ public final class SdkEventEmitterProvider implements EventEmitterProvider { - static final AttributeKey EVENT_DOMAIN = AttributeKey.stringKey("event.domain"); static final AttributeKey EVENT_NAME = AttributeKey.stringKey("event.name"); - static final String DEFAULT_EVENT_DOMAIN = "unknown"; - private final LoggerProvider delegateLoggerProvider; private final Clock clock; @@ -53,13 +54,6 @@ public static SdkEventEmitterProvider create(LoggerProvider delegateLoggerProvid return new SdkEventEmitterProvider(delegateLoggerProvider, clock); } - @Override - public EventEmitter get(String instrumentationScopeName) { - return eventEmitterBuilder(instrumentationScopeName) - .setEventDomain(DEFAULT_EVENT_DOMAIN) - .build(); - } - @Override public EventEmitterBuilder eventEmitterBuilder(String instrumentationScopeName) { return new SdkEventEmitterBuilder( @@ -70,19 +64,12 @@ private static class SdkEventEmitterBuilder implements EventEmitterBuilder { private final Clock clock; private final LoggerBuilder delegateLoggerBuilder; - private String eventDomain = DEFAULT_EVENT_DOMAIN; private SdkEventEmitterBuilder(Clock clock, LoggerBuilder delegateLoggerBuilder) { this.clock = clock; this.delegateLoggerBuilder = delegateLoggerBuilder; } - @Override - public EventEmitterBuilder setEventDomain(String eventDomain) { - this.eventDomain = eventDomain; - return this; - } - @Override public EventEmitterBuilder setSchemaUrl(String schemaUrl) { delegateLoggerBuilder.setSchemaUrl(schemaUrl); @@ -97,47 +84,61 @@ public EventEmitterBuilder setInstrumentationVersion(String instrumentationScope @Override public EventEmitter build() { - return new SdkEventEmitter(clock, delegateLoggerBuilder.build(), eventDomain); + return new SdkEventEmitter(clock, delegateLoggerBuilder.build()); } } private static class SdkEventEmitter implements EventEmitter { + private static final Severity DEFAULT_SEVERITY = Severity.INFO; + private final Clock clock; private final Logger delegateLogger; - private final String eventDomain; - private SdkEventEmitter(Clock clock, Logger delegateLogger, String eventDomain) { + private SdkEventEmitter(Clock clock, Logger delegateLogger) { this.clock = clock; this.delegateLogger = delegateLogger; - this.eventDomain = eventDomain; } @Override - public EventBuilder builder(String eventName, Attributes attributes) { + public EventBuilder builder(String eventName) { return new SdkEventBuilder( + clock, delegateLogger .logRecordBuilder() - .setTimestamp(clock.now(), TimeUnit.NANOSECONDS) - .setAllAttributes(attributes), - eventDomain, + .setSeverity(DEFAULT_SEVERITY) + .setContext(Context.current()), eventName); } @Override - public void emit(String eventName, Attributes attributes) { - LogRecordBuilder logRecordBuilder = - delegateLogger - .logRecordBuilder() - .setTimestamp(clock.now(), TimeUnit.NANOSECONDS) - .setAllAttributes(attributes); - addEventNameAndDomain(logRecordBuilder, eventDomain, eventName); + public void emit(String eventName) { + emitInternal(eventName, null); + } + + @Override + public void emit(String eventName, AnyValue payload) { + emitInternal(eventName, payload); + } + + private void emitInternal(String eventName, @Nullable AnyValue payload) { + long now = clock.now(); + ExtendedLogRecordBuilder logRecordBuilder = + ((ExtendedLogRecordBuilder) delegateLogger.logRecordBuilder()); + if (payload != null) { + logRecordBuilder.setBody(payload); + } + logRecordBuilder + .setSeverity(DEFAULT_SEVERITY) + .setContext(Context.current()) + .setTimestamp(now, TimeUnit.NANOSECONDS) + .setObservedTimestamp(now, TimeUnit.NANOSECONDS); + addEventName(logRecordBuilder, eventName); logRecordBuilder.emit(); } } - static void addEventNameAndDomain( - LogRecordBuilder logRecordBuilder, String eventDomain, String eventName) { - logRecordBuilder.setAttribute(EVENT_DOMAIN, eventDomain).setAttribute(EVENT_NAME, eventName); + static void addEventName(LogRecordBuilder logRecordBuilder, String eventName) { + logRecordBuilder.setAttribute(EVENT_NAME, eventName); } } diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/internal/SdkEventBuilderTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/internal/SdkEventBuilderTest.java index 2115463a771..a3a76d094d5 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/internal/SdkEventBuilderTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/internal/SdkEventBuilderTest.java @@ -12,7 +12,11 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.logs.LogRecordBuilder; +import io.opentelemetry.api.logs.Severity; +import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.common.Clock; import java.time.Instant; import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.Test; @@ -21,22 +25,31 @@ class SdkEventBuilderTest { @Test void emit() { - String eventDomain = "mydomain"; - String eventName = "banana"; + String eventName = "namespace.banana"; LogRecordBuilder logRecordBuilder = mock(LogRecordBuilder.class); when(logRecordBuilder.setTimestamp(anyLong(), any())).thenReturn(logRecordBuilder); when(logRecordBuilder.setAttribute(any(), any())).thenReturn(logRecordBuilder); + when(logRecordBuilder.setContext(any())).thenReturn(logRecordBuilder); + when(logRecordBuilder.setSeverity(any())).thenReturn(logRecordBuilder); + when(logRecordBuilder.setAllAttributes(any())).thenReturn(logRecordBuilder); Instant instant = Instant.now(); - new SdkEventBuilder(logRecordBuilder, eventDomain, eventName) + Context context = Context.root(); + Attributes attributes = Attributes.builder().put("extra-attribute", "value").build(); + new SdkEventBuilder(Clock.getDefault(), logRecordBuilder, eventName) .setTimestamp(123456L, TimeUnit.NANOSECONDS) .setTimestamp(instant) + .setContext(context) + .setSeverity(Severity.DEBUG) + .setAttributes(attributes) .emit(); - verify(logRecordBuilder).setAttribute(stringKey("event.domain"), eventDomain); verify(logRecordBuilder).setAttribute(stringKey("event.name"), eventName); verify(logRecordBuilder).setTimestamp(123456L, TimeUnit.NANOSECONDS); verify(logRecordBuilder).setTimestamp(instant); + verify(logRecordBuilder).setContext(context); + verify(logRecordBuilder).setSeverity(Severity.DEBUG); + verify(logRecordBuilder).setAllAttributes(attributes); verify(logRecordBuilder).emit(); } } diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/internal/SdkEventEmitterProviderTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/internal/SdkEventEmitterProviderTest.java index 7f22b1376a8..53ba2cbbedd 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/internal/SdkEventEmitterProviderTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/internal/SdkEventEmitterProviderTest.java @@ -5,18 +5,21 @@ package io.opentelemetry.sdk.logs.internal; -import static io.opentelemetry.api.common.AttributeKey.stringKey; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.events.EventEmitter; +import io.opentelemetry.api.logs.Severity; +import io.opentelemetry.extension.incubator.logs.AnyValue; import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.logs.ReadWriteLogRecord; import io.opentelemetry.sdk.logs.SdkLoggerProvider; +import io.opentelemetry.sdk.logs.data.Body; import io.opentelemetry.sdk.resources.Resource; +import java.util.Collections; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import org.junit.jupiter.api.Test; @@ -37,84 +40,71 @@ class SdkEventEmitterProviderTest { clock); @Test - void emit_WithDomain() { + void emit_NoPayload() { when(clock.now()).thenReturn(10L); - eventEmitterProvider - .eventEmitterBuilder("test-scope") - .setEventDomain("event-domain") - .build() - .emit( - "event-name", - Attributes.builder() - .put("key1", "value1") - // should be overridden by the eventName argument passed to emit - .put("event.name", "foo") - // should be overridden by the eventDomain - .put("event.domain", "foo") - .build()); + eventEmitterProvider.eventEmitterBuilder("test-scope").build().emit("namespace.event-name"); assertThat(seenLog.get().toLogRecordData()) .hasResource(RESOURCE) .hasInstrumentationScope(InstrumentationScopeInfo.create("test-scope")) .hasTimestamp(10L) - .hasAttributes( - Attributes.builder() - .put("key1", "value1") - .put("event.domain", "event-domain") - .put("event.name", "event-name") - .build()); + .hasObservedTimestamp(10L) + .hasSeverity(Severity.INFO) + .hasAttributes(Attributes.builder().put("event.name", "namespace.event-name").build()); + assertThat(seenLog.get().toLogRecordData().getBody()).isEqualTo(Body.empty()); } @Test - void emit_NoDomain() { + void emit_WithPayload() { when(clock.now()).thenReturn(10L); + AnyValue payload = AnyValue.of(Collections.singletonMap("key1", AnyValue.of("value1"))); + eventEmitterProvider .eventEmitterBuilder("test-scope") .build() - .emit( - "event-name", - Attributes.builder() - .put("key1", "value1") - // should be overridden by the eventName argument passed to emit - .put("event.name", "foo") - // should be overridden by the default eventDomain - .put("event.domain", "foo") - .build()); + .emit("namespace.event-name", payload); assertThat(seenLog.get().toLogRecordData()) .hasResource(RESOURCE) .hasInstrumentationScope(InstrumentationScopeInfo.create("test-scope")) .hasTimestamp(10L) - .hasAttributes( - Attributes.builder() - .put("key1", "value1") - .put("event.domain", "unknown") - .put("event.name", "event-name") - .build()); + .hasObservedTimestamp(10L) + .hasSeverity(Severity.INFO) + .hasAttributes(Attributes.builder().put("event.name", "namespace.event-name").build()); + assertThat(((AnyValueBody) seenLog.get().toLogRecordData().getBody()).asAnyValue()) + .isEqualTo(payload); } @Test void builder() { - long yesterday = System.nanoTime() - TimeUnit.DAYS.toNanos(1); - Attributes attributes = Attributes.of(stringKey("foo"), "bar"); + when(clock.now()).thenReturn(10L); + long yesterday = System.nanoTime() - TimeUnit.DAYS.toNanos(1); EventEmitter emitter = eventEmitterProvider.eventEmitterBuilder("test-scope").build(); - emitter.builder("testing", attributes).setTimestamp(yesterday, TimeUnit.NANOSECONDS).emit(); - verifySeen(yesterday, attributes); - } + AnyValue payload = AnyValue.of(Collections.singletonMap("key1", AnyValue.of("value1"))); + emitter + .builder("namespace.event-name") + .setPayload(payload) + .setTimestamp(yesterday, TimeUnit.NANOSECONDS) + .setSeverity(Severity.DEBUG) + .setAttributes(Attributes.builder().put("extra-attribute", "value").build()) + .emit(); - private void verifySeen(long timestamp, Attributes attributes) { assertThat(seenLog.get().toLogRecordData()) .hasResource(RESOURCE) .hasInstrumentationScope(InstrumentationScopeInfo.create("test-scope")) - .hasTimestamp(timestamp) + .hasTimestamp(yesterday) + .hasObservedTimestamp(10L) + .hasSeverity(Severity.DEBUG) .hasAttributes( - attributes.toBuilder() - .put("event.domain", "unknown") - .put("event.name", "testing") + Attributes.builder() + .put("event.name", "namespace.event-name") + .put("extra-attribute", "value") .build()); + assertThat(((AnyValueBody) seenLog.get().toLogRecordData().getBody()).asAnyValue()) + .isEqualTo(payload); } }