Add event API (#4781)
* Add event API * Log when emitting event without domain, add javadoc example to Logger
This commit is contained in:
parent
29fe7caffe
commit
01a07b51a1
|
@ -6,20 +6,37 @@
|
|||
package io.opentelemetry.api.logs;
|
||||
|
||||
import io.opentelemetry.api.common.AttributeKey;
|
||||
import io.opentelemetry.api.internal.ValidationUtil;
|
||||
import io.opentelemetry.context.Context;
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
|
||||
class DefaultLogger implements Logger {
|
||||
|
||||
private static final Logger INSTANCE = new DefaultLogger();
|
||||
private static final Logger INSTANCE_WITH_DOMAIN = new DefaultLogger(/* hasDomain= */ true);
|
||||
private static final Logger INSTANCE_NO_DOMAIN = new DefaultLogger(/* hasDomain= */ false);
|
||||
|
||||
private static final LogRecordBuilder NOOP_LOG_RECORD_BUILDER = new NoopLogRecordBuilder();
|
||||
private static final EventBuilder NOOP_LOG_RECORD_BUILDER = new NoopLogRecordBuilder();
|
||||
|
||||
private DefaultLogger() {}
|
||||
private final boolean hasDomain;
|
||||
|
||||
static Logger getInstance() {
|
||||
return INSTANCE;
|
||||
private DefaultLogger(boolean hasDomain) {
|
||||
this.hasDomain = hasDomain;
|
||||
}
|
||||
|
||||
static Logger getInstance(boolean hasDomain) {
|
||||
return hasDomain ? INSTANCE_WITH_DOMAIN : INSTANCE_NO_DOMAIN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventBuilder eventBuilder(String eventName) {
|
||||
if (!hasDomain) {
|
||||
ValidationUtil.log(
|
||||
"Cannot emit event from Logger without event domain. Please use LoggerBuilder#setEventDomain(String) when obtaining Logger.",
|
||||
Level.WARNING);
|
||||
}
|
||||
return NOOP_LOG_RECORD_BUILDER;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -27,7 +44,7 @@ class DefaultLogger implements Logger {
|
|||
return NOOP_LOG_RECORD_BUILDER;
|
||||
}
|
||||
|
||||
private static final class NoopLogRecordBuilder implements LogRecordBuilder {
|
||||
private static final class NoopLogRecordBuilder implements EventBuilder {
|
||||
|
||||
private NoopLogRecordBuilder() {}
|
||||
|
||||
|
|
|
@ -8,7 +8,10 @@ package io.opentelemetry.api.logs;
|
|||
class DefaultLoggerProvider implements LoggerProvider {
|
||||
|
||||
private static final LoggerProvider INSTANCE = new DefaultLoggerProvider();
|
||||
private static final LoggerBuilder NOOP_BUILDER = new NoopLoggerBuilder();
|
||||
private static final LoggerBuilder NOOP_BUILDER_WITH_DOMAIN =
|
||||
new NoopLoggerBuilder(/* hasDomain= */ true);
|
||||
private static final LoggerBuilder NOOP_BUILDER_NO_DOMAIN =
|
||||
new NoopLoggerBuilder(/* hasDomain= */ false);
|
||||
|
||||
private DefaultLoggerProvider() {}
|
||||
|
||||
|
@ -18,12 +21,22 @@ class DefaultLoggerProvider implements LoggerProvider {
|
|||
|
||||
@Override
|
||||
public LoggerBuilder loggerBuilder(String instrumentationScopeName) {
|
||||
return NOOP_BUILDER;
|
||||
return NOOP_BUILDER_NO_DOMAIN;
|
||||
}
|
||||
|
||||
private static class NoopLoggerBuilder implements LoggerBuilder {
|
||||
|
||||
private NoopLoggerBuilder() {}
|
||||
private final boolean hasDomain;
|
||||
|
||||
private NoopLoggerBuilder(boolean hasDomain) {
|
||||
this.hasDomain = hasDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("BuilderReturnThis")
|
||||
public LoggerBuilder setEventDomain(String eventDomain) {
|
||||
return eventDomain == null ? NOOP_BUILDER_NO_DOMAIN : NOOP_BUILDER_WITH_DOMAIN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoggerBuilder setSchemaUrl(String schemaUrl) {
|
||||
|
@ -37,7 +50,7 @@ class DefaultLoggerProvider implements LoggerProvider {
|
|||
|
||||
@Override
|
||||
public Logger build() {
|
||||
return DefaultLogger.getInstance();
|
||||
return DefaultLogger.getInstance(hasDomain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.api.logs;
|
||||
|
||||
/**
|
||||
* Used to construct an emit events from a {@link Logger}.
|
||||
*
|
||||
* <p>An event is a log record with attributes for {@code event.domain} and {@code event.name}.
|
||||
*
|
||||
* <p>Obtain a {@link Logger#eventBuilder(String)}, add properties using the setters, and emit the
|
||||
* log record by calling {@link #emit()}.
|
||||
*/
|
||||
public interface EventBuilder extends LogRecordBuilder {}
|
|
@ -10,12 +10,47 @@ import javax.annotation.concurrent.ThreadSafe;
|
|||
/**
|
||||
* A {@link Logger} is the entry point into a log pipeline.
|
||||
*
|
||||
* <p>Obtain a {@link #logRecordBuilder()}, add properties using the setters, and emit it via {@link
|
||||
* LogRecordBuilder#emit()}.
|
||||
* <p>Obtain a {@link EventBuilder} or {@link #logRecordBuilder()}, add properties using the
|
||||
* setters, and emit it via {@link LogRecordBuilder#emit()}.
|
||||
*
|
||||
* <p>Example usage emitting events:
|
||||
*
|
||||
* <pre>{@code
|
||||
* class MyClass {
|
||||
* private final Logger eventLogger = openTelemetryLoggerProvider.loggerBuilder("instrumentation-library-name")
|
||||
* .setInstrumentationVersion("1.0.0")
|
||||
* .setEventDomain("acme.observability")
|
||||
* .build();
|
||||
*
|
||||
* void doWork() {
|
||||
* eventLogger.eventBuilder("my-event")
|
||||
* .setAllAttributes(Attributes.builder()
|
||||
* .put("key1", "value1")
|
||||
* .put("key2", "value2")
|
||||
* .build())
|
||||
* .emit();
|
||||
* // do work
|
||||
* }
|
||||
* }
|
||||
* }</pre>
|
||||
*/
|
||||
@ThreadSafe
|
||||
public interface Logger {
|
||||
|
||||
/**
|
||||
* Return a {@link EventBuilder} to emit an event.
|
||||
*
|
||||
* <p><b>NOTE:</b> this API MUST only be called on {@link Logger}s which have been assigned an
|
||||
* {@link LoggerBuilder#setEventDomain(String) event domain}.
|
||||
*
|
||||
* <p>Build the event using the {@link EventBuilder} setters, and emit via {@link
|
||||
* EventBuilder#emit()}.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
EventBuilder eventBuilder(String eventName);
|
||||
|
||||
/**
|
||||
* Return a {@link LogRecordBuilder} to emit a log record.
|
||||
*
|
||||
|
|
|
@ -8,6 +8,20 @@ package io.opentelemetry.api.logs;
|
|||
/** Builder class for creating {@link Logger} instances. */
|
||||
public interface LoggerBuilder {
|
||||
|
||||
/**
|
||||
* Set the event domain of the resulting {@link Logger}.
|
||||
*
|
||||
* <p><b>NOTE:</b> Event domain is required to use {@link Logger#eventBuilder(String)}.
|
||||
*
|
||||
* <p>The event domain will be included in the {@code event.domain} attribute of every event
|
||||
* produced by the resulting {@link Logger}.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
LoggerBuilder setEventDomain(String eventDomain);
|
||||
|
||||
/**
|
||||
* Assign an OpenTelemetry schema URL to the resulting {@link Logger}.
|
||||
*
|
||||
|
|
|
@ -14,12 +14,13 @@ import javax.annotation.concurrent.ThreadSafe;
|
|||
* <p>The OpenTelemetry logging API exists to satisfy two use cases:
|
||||
*
|
||||
* <ol>
|
||||
* <li>Enable emitting structured <a
|
||||
* href="https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/semantic_conventions/events.md">events</a>
|
||||
* via {@link Logger#eventBuilder(String)}. Requires assigning an {@link
|
||||
* LoggerBuilder#setEventDomain(String) event domain} to the {@link Logger}.
|
||||
* <li>Enable the creation of log appenders, which bridge logs from other log frameworks (e.g.
|
||||
* SLF4J, Log4j, JUL, Logback, etc) into OpenTelemetry via {@link Logger#logRecordBuilder()}.
|
||||
* It is <b>NOT</b> a replacement log framework.
|
||||
* <li>Enable emitting structured <a
|
||||
* href="https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/semantic_conventions/events.md">events</a>.
|
||||
* TODO: add link when event API is added.
|
||||
* </ol>
|
||||
*
|
||||
* @see Logger
|
||||
|
|
|
@ -26,6 +26,26 @@ class DefaultLoggerProviderTest {
|
|||
.setSchemaUrl("http://schema.com")
|
||||
.build())
|
||||
.doesNotThrowAnyException();
|
||||
;
|
||||
|
||||
assertThatCode(() -> provider.loggerBuilder("scope-name").build().logRecordBuilder())
|
||||
.doesNotThrowAnyException();
|
||||
assertThatCode(() -> provider.loggerBuilder("scope-name").build().eventBuilder("event-name"))
|
||||
.doesNotThrowAnyException();
|
||||
assertThatCode(
|
||||
() ->
|
||||
provider
|
||||
.loggerBuilder("scope-name")
|
||||
.setEventDomain("event-domain")
|
||||
.build()
|
||||
.logRecordBuilder())
|
||||
.doesNotThrowAnyException();
|
||||
assertThatCode(
|
||||
() ->
|
||||
provider
|
||||
.loggerBuilder("scope-name")
|
||||
.setEventDomain("event-domain")
|
||||
.build()
|
||||
.eventBuilder("event-name"))
|
||||
.doesNotThrowAnyException();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,24 +5,31 @@
|
|||
|
||||
package io.opentelemetry.api.logs;
|
||||
|
||||
import static io.opentelemetry.api.internal.ValidationUtil.API_USAGE_LOGGER_NAME;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
|
||||
import io.github.netmikey.logunit.api.LogCapturer;
|
||||
import io.opentelemetry.api.common.AttributeKey;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.context.Context;
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.slf4j.event.LoggingEvent;
|
||||
|
||||
class DefaultLoggerTest {
|
||||
|
||||
private static final Logger logger = DefaultLogger.getInstance();
|
||||
@RegisterExtension
|
||||
LogCapturer apiUsageLogs = LogCapturer.create().captureForLogger(API_USAGE_LOGGER_NAME);
|
||||
|
||||
@Test
|
||||
void buildAndEmit() {
|
||||
// Logger with no event.domain
|
||||
assertThatCode(
|
||||
() ->
|
||||
logger
|
||||
DefaultLogger.getInstance(true)
|
||||
.logRecordBuilder()
|
||||
.setEpoch(100, TimeUnit.SECONDS)
|
||||
.setEpoch(Instant.now())
|
||||
|
@ -34,5 +41,57 @@ class DefaultLoggerTest {
|
|||
.setAllAttributes(Attributes.builder().put("key2", "value2").build())
|
||||
.emit())
|
||||
.doesNotThrowAnyException();
|
||||
assertThatCode(
|
||||
() ->
|
||||
DefaultLogger.getInstance(true)
|
||||
.eventBuilder("event-name")
|
||||
.setEpoch(100, TimeUnit.SECONDS)
|
||||
.setEpoch(Instant.now())
|
||||
.setContext(Context.root())
|
||||
.setSeverity(Severity.DEBUG)
|
||||
.setSeverityText("debug")
|
||||
.setBody("body")
|
||||
.setAttribute(AttributeKey.stringKey("key1"), "value1")
|
||||
.setAllAttributes(Attributes.builder().put("key2", "value2").build())
|
||||
.emit())
|
||||
.doesNotThrowAnyException();
|
||||
assertThat(apiUsageLogs.getEvents()).isEmpty();
|
||||
|
||||
// Logger with event.domain
|
||||
assertThatCode(
|
||||
() ->
|
||||
DefaultLogger.getInstance(false)
|
||||
.logRecordBuilder()
|
||||
.setEpoch(100, TimeUnit.SECONDS)
|
||||
.setEpoch(Instant.now())
|
||||
.setContext(Context.root())
|
||||
.setSeverity(Severity.DEBUG)
|
||||
.setSeverityText("debug")
|
||||
.setBody("body")
|
||||
.setAttribute(AttributeKey.stringKey("key1"), "value1")
|
||||
.setAllAttributes(Attributes.builder().put("key2", "value2").build())
|
||||
.emit())
|
||||
.doesNotThrowAnyException();
|
||||
assertThatCode(
|
||||
() ->
|
||||
DefaultLogger.getInstance(false)
|
||||
.eventBuilder("event-name")
|
||||
.setEpoch(100, TimeUnit.SECONDS)
|
||||
.setEpoch(Instant.now())
|
||||
.setContext(Context.root())
|
||||
.setSeverity(Severity.DEBUG)
|
||||
.setSeverityText("debug")
|
||||
.setBody("body")
|
||||
.setAttribute(AttributeKey.stringKey("key1"), "value1")
|
||||
.setAllAttributes(Attributes.builder().put("key2", "value2").build())
|
||||
.emit())
|
||||
.doesNotThrowAnyException();
|
||||
assertThat(apiUsageLogs.getEvents())
|
||||
.hasSize(1)
|
||||
.extracting(LoggingEvent::getMessage)
|
||||
.allMatch(
|
||||
log ->
|
||||
log.equals(
|
||||
"Cannot emit event from Logger without event domain. Please use LoggerBuilder#setEventDomain(String) when obtaining Logger."));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
package io.opentelemetry.sdk.logs;
|
||||
|
||||
import io.opentelemetry.api.common.AttributeKey;
|
||||
import io.opentelemetry.api.logs.EventBuilder;
|
||||
import io.opentelemetry.api.logs.LogRecordBuilder;
|
||||
import io.opentelemetry.api.logs.Severity;
|
||||
import io.opentelemetry.api.trace.Span;
|
||||
|
@ -18,8 +19,8 @@ import java.time.Instant;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** SDK implementation of {@link LogRecordBuilder}. */
|
||||
final class SdkLogRecordBuilder implements LogRecordBuilder {
|
||||
/** SDK implementation of {@link EventBuilder} and {@link LogRecordBuilder}. */
|
||||
final class SdkLogRecordBuilder implements EventBuilder {
|
||||
|
||||
private final LoggerSharedState loggerSharedState;
|
||||
private final LogLimits logLimits;
|
||||
|
@ -40,43 +41,43 @@ final class SdkLogRecordBuilder implements LogRecordBuilder {
|
|||
}
|
||||
|
||||
@Override
|
||||
public LogRecordBuilder setEpoch(long timestamp, TimeUnit unit) {
|
||||
public SdkLogRecordBuilder setEpoch(long timestamp, TimeUnit unit) {
|
||||
this.epochNanos = unit.toNanos(timestamp);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LogRecordBuilder setEpoch(Instant instant) {
|
||||
public SdkLogRecordBuilder setEpoch(Instant instant) {
|
||||
this.epochNanos = TimeUnit.SECONDS.toNanos(instant.getEpochSecond()) + instant.getNano();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LogRecordBuilder setContext(Context context) {
|
||||
public SdkLogRecordBuilder setContext(Context context) {
|
||||
this.spanContext = Span.fromContext(context).getSpanContext();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LogRecordBuilder setSeverity(Severity severity) {
|
||||
public SdkLogRecordBuilder setSeverity(Severity severity) {
|
||||
this.severity = severity;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LogRecordBuilder setSeverityText(String severityText) {
|
||||
public SdkLogRecordBuilder setSeverityText(String severityText) {
|
||||
this.severityText = severityText;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LogRecordBuilder setBody(String body) {
|
||||
public SdkLogRecordBuilder setBody(String body) {
|
||||
this.body = Body.string(body);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> LogRecordBuilder setAttribute(AttributeKey<T> key, T value) {
|
||||
public <T> SdkLogRecordBuilder setAttribute(AttributeKey<T> key, T value) {
|
||||
if (key == null || key.getKey().isEmpty() || value == null) {
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -5,20 +5,64 @@
|
|||
|
||||
package io.opentelemetry.sdk.logs;
|
||||
|
||||
import io.opentelemetry.api.common.AttributeKey;
|
||||
import io.opentelemetry.api.internal.ValidationUtil;
|
||||
import io.opentelemetry.api.logs.EventBuilder;
|
||||
import io.opentelemetry.api.logs.LogRecordBuilder;
|
||||
import io.opentelemetry.api.logs.Logger;
|
||||
import io.opentelemetry.api.logs.LoggerProvider;
|
||||
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
|
||||
import java.util.logging.Level;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** SDK implementation of {@link Logger}. */
|
||||
final class SdkLogger implements Logger {
|
||||
|
||||
// Obtain a noop logger with the domain set so that we can obtain noop EventBuilder without
|
||||
// generating additional warning logs
|
||||
private static final Logger NOOP_LOGGER_WITH_DOMAIN =
|
||||
LoggerProvider.noop().loggerBuilder("unused").setEventDomain("unused").build();
|
||||
|
||||
private final LoggerSharedState loggerSharedState;
|
||||
private final InstrumentationScopeInfo instrumentationScopeInfo;
|
||||
@Nullable private final String eventDomain;
|
||||
|
||||
SdkLogger(
|
||||
LoggerSharedState loggerSharedState, InstrumentationScopeInfo instrumentationScopeInfo) {
|
||||
this(loggerSharedState, instrumentationScopeInfo, null);
|
||||
}
|
||||
|
||||
SdkLogger(
|
||||
LoggerSharedState loggerSharedState,
|
||||
InstrumentationScopeInfo instrumentationScopeInfo,
|
||||
@Nullable String eventDomain) {
|
||||
this.loggerSharedState = loggerSharedState;
|
||||
this.instrumentationScopeInfo = instrumentationScopeInfo;
|
||||
this.eventDomain = eventDomain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a logger identical to {@code this} ensuring the {@link #eventDomain} is equal to {@code
|
||||
* eventDomain}. If {@link #eventDomain} is not equal, creates a new instance.
|
||||
*/
|
||||
SdkLogger withEventDomain(String eventDomain) {
|
||||
if (!eventDomain.equals(this.eventDomain)) {
|
||||
return new SdkLogger(loggerSharedState, instrumentationScopeInfo, eventDomain);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventBuilder eventBuilder(String eventName) {
|
||||
if (eventDomain == null) {
|
||||
ValidationUtil.log(
|
||||
"Cannot emit event from Logger without event domain. Please use LoggerBuilder#setEventDomain(String) when obtaining Logger.",
|
||||
Level.WARNING);
|
||||
return NOOP_LOGGER_WITH_DOMAIN.eventBuilder(eventName);
|
||||
}
|
||||
return new SdkLogRecordBuilder(loggerSharedState, instrumentationScopeInfo)
|
||||
.setAttribute(AttributeKey.stringKey("event.domain"), eventDomain)
|
||||
.setAttribute(AttributeKey.stringKey("event.name"), eventName);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -9,17 +9,25 @@ import io.opentelemetry.api.logs.LoggerBuilder;
|
|||
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
|
||||
import io.opentelemetry.sdk.common.InstrumentationScopeInfoBuilder;
|
||||
import io.opentelemetry.sdk.internal.ComponentRegistry;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
final class SdkLoggerBuilder implements LoggerBuilder {
|
||||
|
||||
private final ComponentRegistry<SdkLogger> registry;
|
||||
private final InstrumentationScopeInfoBuilder scopeBuilder;
|
||||
@Nullable private String eventDomain;
|
||||
|
||||
SdkLoggerBuilder(ComponentRegistry<SdkLogger> registry, String instrumentationScopeName) {
|
||||
this.registry = registry;
|
||||
this.scopeBuilder = InstrumentationScopeInfo.builder(instrumentationScopeName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoggerBuilder setEventDomain(String eventDomain) {
|
||||
this.eventDomain = eventDomain;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SdkLoggerBuilder setSchemaUrl(String schemaUrl) {
|
||||
scopeBuilder.setSchemaUrl(schemaUrl);
|
||||
|
@ -34,6 +42,7 @@ final class SdkLoggerBuilder implements LoggerBuilder {
|
|||
|
||||
@Override
|
||||
public SdkLogger build() {
|
||||
return registry.get(scopeBuilder.build());
|
||||
SdkLogger logger = registry.get(scopeBuilder.build());
|
||||
return eventDomain == null ? logger : logger.withEventDomain(eventDomain);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import static io.opentelemetry.api.common.AttributeKey.booleanArrayKey;
|
|||
import static io.opentelemetry.api.common.AttributeKey.doubleArrayKey;
|
||||
import static io.opentelemetry.api.common.AttributeKey.longArrayKey;
|
||||
import static io.opentelemetry.api.common.AttributeKey.stringArrayKey;
|
||||
import static io.opentelemetry.api.internal.ValidationUtil.API_USAGE_LOGGER_NAME;
|
||||
import static io.opentelemetry.sdk.testing.assertj.LogAssertions.assertThat;
|
||||
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
|
@ -17,6 +18,7 @@ import static org.mockito.Mockito.never;
|
|||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import io.github.netmikey.logunit.api.LogCapturer;
|
||||
import io.opentelemetry.api.common.AttributeKey;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.common.AttributesBuilder;
|
||||
|
@ -30,9 +32,14 @@ import java.util.Arrays;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.slf4j.event.LoggingEvent;
|
||||
|
||||
class SdkLoggerTest {
|
||||
|
||||
@RegisterExtension
|
||||
LogCapturer apiUsageLogs = LogCapturer.create().captureForLogger(API_USAGE_LOGGER_NAME);
|
||||
|
||||
@Test
|
||||
void logRecordBuilder() {
|
||||
LoggerSharedState state = mock(LoggerSharedState.class);
|
||||
|
@ -134,4 +141,40 @@ class SdkLoggerTest {
|
|||
|
||||
verify(logRecordProcessor, never()).onEmit(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void eventBuilder() {
|
||||
AtomicReference<ReadWriteLogRecord> seenLog = new AtomicReference<>();
|
||||
SdkLoggerProvider loggerProvider =
|
||||
SdkLoggerProvider.builder().addLogRecordProcessor(seenLog::set).build();
|
||||
|
||||
// Emit event from logger with name and add event domain
|
||||
loggerProvider
|
||||
.loggerBuilder("test")
|
||||
.setEventDomain("event-domain")
|
||||
.build()
|
||||
.eventBuilder("event-name")
|
||||
.emit();
|
||||
|
||||
assertThat(seenLog.get().toLogRecordData())
|
||||
.hasAttributes(
|
||||
Attributes.builder()
|
||||
.put("event.domain", "event-domain")
|
||||
.put("event.name", "event-name")
|
||||
.build());
|
||||
|
||||
assertThat(apiUsageLogs.getEvents()).isEmpty();
|
||||
seenLog.set(null);
|
||||
|
||||
// Emit event from logger with name and no event domain
|
||||
loggerProvider.get("test").eventBuilder("event-name");
|
||||
|
||||
assertThat(apiUsageLogs.getEvents())
|
||||
.hasSize(1)
|
||||
.extracting(LoggingEvent::getMessage)
|
||||
.allMatch(
|
||||
log ->
|
||||
log.equals(
|
||||
"Cannot emit event from Logger without event domain. Please use LoggerBuilder#setEventDomain(String) when obtaining Logger."));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue