Allow events to be emitted with timestamp (#5928)
Co-authored-by: Jack Berg <jberg@newrelic.com>
This commit is contained in:
parent
b03ec3aa62
commit
83993e03d3
|
@ -6,6 +6,8 @@
|
|||
package io.opentelemetry.api.events;
|
||||
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
class DefaultEventEmitter implements EventEmitter {
|
||||
|
||||
|
@ -19,4 +21,27 @@ class DefaultEventEmitter implements EventEmitter {
|
|||
|
||||
@Override
|
||||
public void emit(String eventName, Attributes attributes) {}
|
||||
|
||||
@Override
|
||||
public EventBuilder builder(String eventName, Attributes attributes) {
|
||||
return NoOpEventBuilder.INSTANCE;
|
||||
}
|
||||
|
||||
private static class NoOpEventBuilder implements EventBuilder {
|
||||
|
||||
public static final EventBuilder INSTANCE = new NoOpEventBuilder();
|
||||
|
||||
@Override
|
||||
public EventBuilder setTimestamp(long timestamp, TimeUnit unit) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventBuilder setTimestamp(Instant instant) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emit() {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.api.events;
|
||||
|
||||
import java.time.Instant;
|
||||
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.
|
||||
*
|
||||
* <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.
|
||||
*
|
||||
* <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);
|
||||
|
||||
/** Emit an event. */
|
||||
void emit();
|
||||
}
|
|
@ -40,4 +40,13 @@ public interface EventEmitter {
|
|||
* @param attributes attributes associated with the event
|
||||
*/
|
||||
void emit(String eventName, Attributes attributes);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
EventBuilder builder(String eventName, Attributes attributes);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ package io.opentelemetry.api.events;
|
|||
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class DefaultEventEmitterTest {
|
||||
|
@ -22,4 +24,18 @@ class DefaultEventEmitterTest {
|
|||
.emit("event-name", Attributes.builder().put("key1", "value1").build()))
|
||||
.doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void builder() {
|
||||
Attributes attributes = Attributes.builder().put("key1", "value1").build();
|
||||
EventEmitter emitter = DefaultEventEmitter.getInstance();
|
||||
assertThatCode(
|
||||
() ->
|
||||
emitter
|
||||
.builder("myEvent", attributes)
|
||||
.setTimestamp(123456L, TimeUnit.NANOSECONDS)
|
||||
.setTimestamp(Instant.now())
|
||||
.emit())
|
||||
.doesNotThrowAnyException();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.sdk.logs.internal;
|
||||
|
||||
import io.opentelemetry.api.events.EventBuilder;
|
||||
import io.opentelemetry.api.logs.LogRecordBuilder;
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
class SdkEventBuilder implements EventBuilder {
|
||||
private final LogRecordBuilder logRecordBuilder;
|
||||
private final String eventDomain;
|
||||
private final String eventName;
|
||||
|
||||
SdkEventBuilder(LogRecordBuilder logRecordBuilder, String eventDomain, String eventName) {
|
||||
this.logRecordBuilder = logRecordBuilder;
|
||||
this.eventDomain = eventDomain;
|
||||
this.eventName = eventName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventBuilder setTimestamp(long timestamp, TimeUnit unit) {
|
||||
this.logRecordBuilder.setTimestamp(timestamp, unit);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventBuilder setTimestamp(Instant instant) {
|
||||
this.logRecordBuilder.setTimestamp(instant);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emit() {
|
||||
SdkEventEmitterProvider.addEventNameAndDomain(logRecordBuilder, eventDomain, eventName);
|
||||
logRecordBuilder.emit();
|
||||
}
|
||||
}
|
|
@ -7,9 +7,11 @@ 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;
|
||||
import io.opentelemetry.api.events.EventEmitterProvider;
|
||||
import io.opentelemetry.api.logs.LogRecordBuilder;
|
||||
import io.opentelemetry.api.logs.Logger;
|
||||
import io.opentelemetry.api.logs.LoggerBuilder;
|
||||
import io.opentelemetry.api.logs.LoggerProvider;
|
||||
|
@ -24,7 +26,10 @@ import java.util.concurrent.TimeUnit;
|
|||
*/
|
||||
public final class SdkEventEmitterProvider implements EventEmitterProvider {
|
||||
|
||||
private static final String DEFAULT_EVENT_DOMAIN = "unknown";
|
||||
static final AttributeKey<String> EVENT_DOMAIN = AttributeKey.stringKey("event.domain");
|
||||
static final AttributeKey<String> EVENT_NAME = AttributeKey.stringKey("event.name");
|
||||
|
||||
static final String DEFAULT_EVENT_DOMAIN = "unknown";
|
||||
|
||||
private final LoggerProvider delegateLoggerProvider;
|
||||
private final Clock clock;
|
||||
|
@ -98,9 +103,6 @@ public final class SdkEventEmitterProvider implements EventEmitterProvider {
|
|||
|
||||
private static class SdkEventEmitter implements EventEmitter {
|
||||
|
||||
private static final AttributeKey<String> EVENT_DOMAIN = AttributeKey.stringKey("event.domain");
|
||||
private static final AttributeKey<String> EVENT_NAME = AttributeKey.stringKey("event.name");
|
||||
|
||||
private final Clock clock;
|
||||
private final Logger delegateLogger;
|
||||
private final String eventDomain;
|
||||
|
@ -111,15 +113,31 @@ public final class SdkEventEmitterProvider implements EventEmitterProvider {
|
|||
this.eventDomain = eventDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventBuilder builder(String eventName, Attributes attributes) {
|
||||
return new SdkEventBuilder(
|
||||
delegateLogger
|
||||
.logRecordBuilder()
|
||||
.setTimestamp(clock.now(), TimeUnit.NANOSECONDS)
|
||||
.setAllAttributes(attributes),
|
||||
eventDomain,
|
||||
eventName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emit(String eventName, Attributes attributes) {
|
||||
delegateLogger
|
||||
.logRecordBuilder()
|
||||
.setTimestamp(clock.now(), TimeUnit.NANOSECONDS)
|
||||
.setAllAttributes(attributes)
|
||||
.setAttribute(EVENT_DOMAIN, eventDomain)
|
||||
.setAttribute(EVENT_NAME, eventName)
|
||||
.emit();
|
||||
LogRecordBuilder logRecordBuilder =
|
||||
delegateLogger
|
||||
.logRecordBuilder()
|
||||
.setTimestamp(clock.now(), TimeUnit.NANOSECONDS)
|
||||
.setAllAttributes(attributes);
|
||||
addEventNameAndDomain(logRecordBuilder, eventDomain, eventName);
|
||||
logRecordBuilder.emit();
|
||||
}
|
||||
}
|
||||
|
||||
static void addEventNameAndDomain(
|
||||
LogRecordBuilder logRecordBuilder, String eventDomain, String eventName) {
|
||||
logRecordBuilder.setAttribute(EVENT_DOMAIN, eventDomain).setAttribute(EVENT_NAME, eventName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.sdk.logs.internal;
|
||||
|
||||
import static io.opentelemetry.api.common.AttributeKey.stringKey;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import io.opentelemetry.api.logs.LogRecordBuilder;
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class SdkEventBuilderTest {
|
||||
|
||||
@Test
|
||||
void emit() {
|
||||
String eventDomain = "mydomain";
|
||||
String eventName = "banana";
|
||||
|
||||
LogRecordBuilder logRecordBuilder = mock(LogRecordBuilder.class);
|
||||
when(logRecordBuilder.setTimestamp(anyLong(), any())).thenReturn(logRecordBuilder);
|
||||
when(logRecordBuilder.setAttribute(any(), any())).thenReturn(logRecordBuilder);
|
||||
|
||||
Instant instant = Instant.now();
|
||||
new SdkEventBuilder(logRecordBuilder, eventDomain, eventName)
|
||||
.setTimestamp(123456L, TimeUnit.NANOSECONDS)
|
||||
.setTimestamp(instant)
|
||||
.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).emit();
|
||||
}
|
||||
}
|
|
@ -5,16 +5,19 @@
|
|||
|
||||
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.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.resources.Resource;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
@ -91,4 +94,27 @@ class SdkEventEmitterProviderTest {
|
|||
.put("event.name", "event-name")
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void builder() {
|
||||
long yesterday = System.nanoTime() - TimeUnit.DAYS.toNanos(1);
|
||||
Attributes attributes = Attributes.of(stringKey("foo"), "bar");
|
||||
|
||||
EventEmitter emitter = eventEmitterProvider.eventEmitterBuilder("test-scope").build();
|
||||
|
||||
emitter.builder("testing", attributes).setTimestamp(yesterday, TimeUnit.NANOSECONDS).emit();
|
||||
verifySeen(yesterday, attributes);
|
||||
}
|
||||
|
||||
private void verifySeen(long timestamp, Attributes attributes) {
|
||||
assertThat(seenLog.get().toLogRecordData())
|
||||
.hasResource(RESOURCE)
|
||||
.hasInstrumentationScope(InstrumentationScopeInfo.create("test-scope"))
|
||||
.hasTimestamp(timestamp)
|
||||
.hasAttributes(
|
||||
attributes.toBuilder()
|
||||
.put("event.domain", "unknown")
|
||||
.put("event.name", "testing")
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue