Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Event API to reflect spec changes #6001

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api/events/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ otelJava.moduleName.set("io.opentelemetry.api.events")

dependencies {
api(project(":api:all"))
api(project(":extensions:incubator"))
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -20,17 +23,22 @@ static EventEmitter getInstance() {
}

@Override
public void emit(String eventName, Attributes attributes) {}
public void emit(String eventName, AnyValue<?> payload) {}

@Override
public EventBuilder builder(String eventName, Attributes attributes) {
public EventBuilder builder(String eventName) {
return NoOpEventBuilder.INSTANCE;
}

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;
Expand All @@ -41,6 +49,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() {}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,65 @@

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}.
*
* <p>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}.
*
* <p>The {@code payload} is expected to match the schema of other events with the same {@code
* eventName}.
*/
default EventBuilder setPayload(Map<String, AnyValue<?>> payload) {
return setPayload(AnyValue.of(payload));
}

/**
* Set the epoch {@code timestamp}, using the timestamp and unit.
*
* <p>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(long timestamp, TimeUnit unit);

/**
* Set the epoch {@code timestamp} for the event, using the instant.
* Set the epoch {@code timestamp}t, using the instant.
*
* <p>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.
*
* <p>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();
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,26 @@

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;

/**
* A {@link EventEmitter} is the entry point into an event pipeline.
*
* <p>Example usage emitting events:
*
* <p>// TODO: rework
*
* <pre>{@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
* }
* }
Expand All @@ -35,18 +36,30 @@ 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.
* @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.
*
* @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<String, AnyValue<?>> payload) {
jack-berg marked this conversation as resolved.
Show resolved Hide resolved
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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -23,7 +23,6 @@ void noopEventEmitterProvider_doesNotThrow() {
() ->
provider
.eventEmitterBuilder("scope-name")
.setEventDomain("event-domain")
.setInstrumentationVersion("1.0")
.setSchemaUrl("http://schema.com")
.build())
Expand All @@ -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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,49 @@
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;

class DefaultEventEmitterTest {

@Test
void emit() {
assertThatCode(() -> DefaultEventEmitter.getInstance().emit("event-name", Attributes.empty()))
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();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand All @@ -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
Expand Down Expand Up @@ -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()))
Expand Down
Loading