From 6d538c32c57e6aa4edc415371a17be407dba6525 Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Tue, 5 Aug 2025 16:43:04 -0700 Subject: [PATCH 1/6] Add minimum severity and trace-based logger configuration --- .../sdk/logs/ExtendedSdkLogRecordBuilder.java | 11 +- .../sdk/logs/IncubatingUtil.java | 6 +- .../sdk/logs/SdkLogRecordBuilder.java | 9 +- .../io/opentelemetry/sdk/logs/SdkLogger.java | 30 +++- .../sdk/logs/internal/LoggerConfig.java | 91 +++++++++++- .../sdk/logs/SdkLogRecordBuilderTest.java | 76 ++++++++++- .../opentelemetry/sdk/logs/SdkLoggerTest.java | 129 ++++++++++++++++++ .../sdk/logs/LoggerConfigTest.java | 23 ++++ 8 files changed, 364 insertions(+), 11 deletions(-) diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/ExtendedSdkLogRecordBuilder.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/ExtendedSdkLogRecordBuilder.java index 41596afa3da..45879497259 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/ExtendedSdkLogRecordBuilder.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/ExtendedSdkLogRecordBuilder.java @@ -25,8 +25,10 @@ final class ExtendedSdkLogRecordBuilder extends SdkLogRecordBuilder @Nullable private ExtendedAttributesMap extendedAttributes; ExtendedSdkLogRecordBuilder( - LoggerSharedState loggerSharedState, InstrumentationScopeInfo instrumentationScopeInfo) { - super(loggerSharedState, instrumentationScopeInfo); + LoggerSharedState loggerSharedState, + InstrumentationScopeInfo instrumentationScopeInfo, + SdkLogger logger) { + super(loggerSharedState, instrumentationScopeInfo, logger); } @Override @@ -132,7 +134,12 @@ public void emit() { if (loggerSharedState.hasBeenShutdown()) { return; } + Context context = this.context == null ? Context.current() : this.context; + if (!logger.isEnabled(severity, context)) { + return; + } + long observedTimestampEpochNanos = this.observedTimestampEpochNanos == 0 ? this.loggerSharedState.getClock().now() diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/IncubatingUtil.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/IncubatingUtil.java index fd7582644be..8d1278e741c 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/IncubatingUtil.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/IncubatingUtil.java @@ -25,7 +25,9 @@ static SdkLogger createExtendedLogger( } static SdkLogRecordBuilder createExtendedLogRecordBuilder( - LoggerSharedState loggerSharedState, InstrumentationScopeInfo instrumentationScopeInfo) { - return new ExtendedSdkLogRecordBuilder(loggerSharedState, instrumentationScopeInfo); + LoggerSharedState loggerSharedState, + InstrumentationScopeInfo instrumentationScopeInfo, + SdkLogger logger) { + return new ExtendedSdkLogRecordBuilder(loggerSharedState, instrumentationScopeInfo, logger); } } diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilder.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilder.java index 1fa78926396..359b7331fb5 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilder.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilder.java @@ -22,6 +22,7 @@ class SdkLogRecordBuilder implements LogRecordBuilder { protected final LoggerSharedState loggerSharedState; protected final LogLimits logLimits; + protected final SdkLogger logger; protected final InstrumentationScopeInfo instrumentationScopeInfo; protected long timestampEpochNanos; @@ -34,10 +35,13 @@ class SdkLogRecordBuilder implements LogRecordBuilder { @Nullable private AttributesMap attributes; SdkLogRecordBuilder( - LoggerSharedState loggerSharedState, InstrumentationScopeInfo instrumentationScopeInfo) { + LoggerSharedState loggerSharedState, + InstrumentationScopeInfo instrumentationScopeInfo, + SdkLogger logger) { this.loggerSharedState = loggerSharedState; this.logLimits = loggerSharedState.getLogLimits(); this.instrumentationScopeInfo = instrumentationScopeInfo; + this.logger = logger; } @Override @@ -121,6 +125,9 @@ public void emit() { return; } Context context = this.context == null ? Context.current() : this.context; + if (!logger.isEnabled(severity, context)) { + return; + } long observedTimestampEpochNanos = this.observedTimestampEpochNanos == 0 ? this.loggerSharedState.getClock().now() diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java index ccb234d7d77..ab1724f3bbe 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java @@ -9,6 +9,8 @@ import io.opentelemetry.api.logs.Logger; import io.opentelemetry.api.logs.LoggerProvider; import io.opentelemetry.api.logs.Severity; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.context.Context; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.logs.internal.LoggerConfig; @@ -34,6 +36,8 @@ class SdkLogger implements Logger { private final InstrumentationScopeInfo instrumentationScopeInfo; protected volatile boolean loggerEnabled; + protected volatile int minimumSeverity; + protected volatile boolean traceBased; SdkLogger( LoggerSharedState loggerSharedState, @@ -42,6 +46,8 @@ class SdkLogger implements Logger { this.loggerSharedState = loggerSharedState; this.instrumentationScopeInfo = instrumentationScopeInfo; this.loggerEnabled = loggerConfig.isEnabled(); + this.minimumSeverity = loggerConfig.getMinimumSeverity(); + this.traceBased = loggerConfig.isTraceBased(); } static SdkLogger create( @@ -58,8 +64,8 @@ public LogRecordBuilder logRecordBuilder() { if (loggerEnabled) { return INCUBATOR_AVAILABLE ? IncubatingUtil.createExtendedLogRecordBuilder( - loggerSharedState, instrumentationScopeInfo) - : new SdkLogRecordBuilder(loggerSharedState, instrumentationScopeInfo); + loggerSharedState, instrumentationScopeInfo, this) + : new SdkLogRecordBuilder(loggerSharedState, instrumentationScopeInfo, this); } return NOOP_LOGGER.logRecordBuilder(); } @@ -71,10 +77,28 @@ InstrumentationScopeInfo getInstrumentationScopeInfo() { // Visible for testing public boolean isEnabled(Severity severity, Context context) { - return loggerEnabled; + if (!loggerEnabled) { + return false; + } + + if (severity != Severity.UNDEFINED_SEVERITY_NUMBER + && severity.getSeverityNumber() < minimumSeverity) { + return false; + } + + if (traceBased) { + SpanContext spanContext = Span.fromContext(context).getSpanContext(); + if (spanContext.isValid() && !spanContext.getTraceFlags().isSampled()) { + return false; + } + } + + return true; } void updateLoggerConfig(LoggerConfig loggerConfig) { loggerEnabled = loggerConfig.isEnabled(); + minimumSeverity = loggerConfig.getMinimumSeverity(); + traceBased = loggerConfig.isTraceBased(); } } diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/LoggerConfig.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/LoggerConfig.java index 00ffdc86b41..db23bfc65f5 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/LoggerConfig.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/LoggerConfig.java @@ -30,9 +30,11 @@ public abstract class LoggerConfig { private static final LoggerConfig DEFAULT_CONFIG = - new AutoValue_LoggerConfig(/* enabled= */ true); + new AutoValue_LoggerConfig( + /* enabled= */ true, /* minimumSeverity= */ 0, /* traceBased= */ false); private static final LoggerConfig DISABLED_CONFIG = - new AutoValue_LoggerConfig(/* enabled= */ false); + new AutoValue_LoggerConfig( + /* enabled= */ false, /* minimumSeverity= */ 0, /* traceBased= */ false); /** Returns a disabled {@link LoggerConfig}. */ public static LoggerConfig disabled() { @@ -44,6 +46,11 @@ public static LoggerConfig enabled() { return DEFAULT_CONFIG; } + /** Returns a new {@link Builder} for creating a {@link LoggerConfig}. */ + public static Builder builder() { + return new Builder(); + } + /** * Returns the default {@link LoggerConfig}, which is used when no configurator is set or when the * logger configurator returns {@code null} for a {@link InstrumentationScopeInfo}. @@ -62,6 +69,86 @@ public static ScopeConfiguratorBuilder configuratorBuilder() { LoggerConfig() {} + /** + * Builder for {@link LoggerConfig}. + * + *

This class is internal and experimental. Its APIs are unstable and can change at any time. + * Its APIs (or a version of them) may be promoted to the public stable API in the future, but no + * guarantees are made. + */ + public static final class Builder { + private boolean enabled = true; + private int minimumSeverity = 0; + private boolean traceBased = false; + + private Builder() {} + + /** + * Sets whether the logger is enabled. + * + * @param enabled whether the logger is enabled + * @return this builder + */ + public Builder setEnabled(boolean enabled) { + this.enabled = enabled; + return this; + } + + /** + * Sets the minimum severity level for log records to be processed. + * + *

Log records with a severity number less than this value will be dropped. Log records + * without a specified severity are not affected by this setting. + * + * @param minimumSeverity minimum severity level for log records to be processed + * @return this builder + */ + public Builder setMinimumSeverity(int minimumSeverity) { + this.minimumSeverity = minimumSeverity; + return this; + } + + /** + * Sets whether to only process log records from traces when the trace is sampled. + * + *

When enabled, log records from unsampled traces will be dropped. Log records that are not + * associated with a trace context are unaffected. + * + * @param traceBased whether to only process log records from traces when the trace is sampled + * @return this builder + */ + public Builder setTraceBased(boolean traceBased) { + this.traceBased = traceBased; + return this; + } + + /** Builds and returns a {@link LoggerConfig}. */ + public LoggerConfig build() { + return new AutoValue_LoggerConfig(enabled, minimumSeverity, traceBased); + } + } + /** Returns {@code true} if this logger is enabled. Defaults to {@code true}. */ public abstract boolean isEnabled(); + + /** + * Returns the minimum severity level for log records to be processed. + * + *

Log records with a severity number less than this value will be dropped. Log records without + * a specified severity are not affected by this setting. + * + *

Defaults to {@code 0}. + */ + public abstract int getMinimumSeverity(); + + /** + * Returns {@code true} if this logger should only process log records from traces when the trace + * is sampled. + * + *

When enabled, log records from unsampled traces will be dropped. Log records that are not + * associated with a trace context are unaffected. + * + *

Defaults to {@code false}. + */ + public abstract boolean isTraceBased(); } diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilderTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilderTest.java index 7d067cef49f..0caf35c03d9 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilderTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilderTest.java @@ -24,6 +24,7 @@ import io.opentelemetry.context.Context; import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.logs.internal.LoggerConfig; import io.opentelemetry.sdk.resources.Resource; import java.time.Instant; import java.util.concurrent.TimeUnit; @@ -57,7 +58,8 @@ void setup() { when(loggerSharedState.getResource()).thenReturn(RESOURCE); when(loggerSharedState.getClock()).thenReturn(clock); - builder = new SdkLogRecordBuilder(loggerSharedState, SCOPE_INFO); + SdkLogger logger = new SdkLogger(loggerSharedState, SCOPE_INFO, LoggerConfig.enabled()); + builder = new SdkLogRecordBuilder(loggerSharedState, SCOPE_INFO, logger); } @Test @@ -121,6 +123,78 @@ void emit_NoFields() { .hasSeverity(Severity.UNDEFINED_SEVERITY_NUMBER); } + @Test + void emit_WithMinimumSeverityConfiguration() { + LoggerConfig config = + LoggerConfig.builder().setMinimumSeverity(Severity.INFO.getSeverityNumber()).build(); + SdkLogger logger = new SdkLogger(loggerSharedState, SCOPE_INFO, config); + builder = new SdkLogRecordBuilder(loggerSharedState, SCOPE_INFO, logger); + + builder.setBody("too-low").setSeverity(Severity.DEBUG).emit(); + assertThat(emittedLog.get()).isNull(); + + builder.setBody("allowed").setSeverity(Severity.INFO).emit(); + assertThat(emittedLog.get().toLogRecordData()).hasBody("allowed"); + } + + @Test + void emit_DropsUnsampledTraceWhenTraceBased() { + LoggerConfig config = LoggerConfig.builder().setTraceBased(true).build(); + SdkLogger logger = new SdkLogger(loggerSharedState, SCOPE_INFO, config); + builder = new SdkLogRecordBuilder(loggerSharedState, SCOPE_INFO, logger); + + SpanContext unsampledSpanContext = + SpanContext.create( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bbbbbbbbbbbbbbbb", + TraceFlags.getDefault(), + TraceState.getDefault()); + builder + .setBody("unsampled") + .setContext(Span.wrap(unsampledSpanContext).storeInContext(Context.root())) + .emit(); + assertThat(emittedLog.get()).isNull(); + + SpanContext sampledSpanContext = + SpanContext.create( + "cccccccccccccccccccccccccccccccc", + "dddddddddddddddd", + TraceFlags.getSampled(), + TraceState.getDefault()); + builder + .setBody("sampled") + .setContext(Span.wrap(sampledSpanContext).storeInContext(Context.root())) + .emit(); + assertThat(emittedLog.get().toLogRecordData()) + .hasSpanContext(sampledSpanContext) + .hasBody("sampled"); + } + + @Test + void emit_AllowsUndefinedSeverityWithMinimumSeverity() { + LoggerConfig config = + LoggerConfig.builder().setMinimumSeverity(Severity.WARN.getSeverityNumber()).build(); + SdkLogger logger = new SdkLogger(loggerSharedState, SCOPE_INFO, config); + builder = new SdkLogRecordBuilder(loggerSharedState, SCOPE_INFO, logger); + + // Undefined severity should bypass the minimum severity filter + builder.setBody("undefined-severity").setSeverity(Severity.UNDEFINED_SEVERITY_NUMBER).emit(); + assertThat(emittedLog.get().toLogRecordData()) + .hasBody("undefined-severity") + .hasSeverity(Severity.UNDEFINED_SEVERITY_NUMBER); + } + + @Test + void emit_AllowsNoTraceContextWithTraceBased() { + LoggerConfig config = LoggerConfig.builder().setTraceBased(true).build(); + SdkLogger logger = new SdkLogger(loggerSharedState, SCOPE_INFO, config); + builder = new SdkLogRecordBuilder(loggerSharedState, SCOPE_INFO, logger); + + // No trace context should bypass the trace-based filter + builder.setBody("no-trace-context").emit(); + assertThat(emittedLog.get().toLogRecordData()).hasBody("no-trace-context"); + } + @Test void testConvenienceAttributeMethods() { builder diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java index 1f1415adf2a..6a502fbdc04 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java @@ -22,6 +22,10 @@ import io.opentelemetry.api.internal.StringUtils; import io.opentelemetry.api.logs.LogRecordBuilder; import io.opentelemetry.api.logs.Severity; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.TraceFlags; +import io.opentelemetry.api.trace.TraceState; import io.opentelemetry.context.Context; import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.CompletableResultCode; @@ -148,4 +152,129 @@ void updateEnabled() { logger.updateLoggerConfig(LoggerConfig.enabled()); assertThat(logger.isEnabled(Severity.UNDEFINED_SEVERITY_NUMBER, Context.current())).isTrue(); } + + @Test + void updateLoggerConfig_UpdatesAllFields() { + LogRecordProcessor logRecordProcessor = mock(LogRecordProcessor.class); + SdkLoggerProvider loggerProvider = + SdkLoggerProvider.builder().addLogRecordProcessor(logRecordProcessor).build(); + SdkLogger logger = (SdkLogger) loggerProvider.get("test"); + + // Start with default config + assertThat(logger.loggerEnabled).isTrue(); + assertThat(logger.minimumSeverity).isEqualTo(0); + assertThat(logger.traceBased).isFalse(); + + // Update to custom config + LoggerConfig config = + LoggerConfig.builder() + .setEnabled(false) + .setMinimumSeverity(Severity.WARN.getSeverityNumber()) + .setTraceBased(true) + .build(); + logger.updateLoggerConfig(config); + + assertThat(logger.loggerEnabled).isFalse(); + assertThat(logger.minimumSeverity).isEqualTo(Severity.WARN.getSeverityNumber()); + assertThat(logger.traceBased).isTrue(); + } + + @Test + void isEnabled_MinimumSeverity() { + LogRecordProcessor logRecordProcessor = mock(LogRecordProcessor.class); + SdkLoggerProvider loggerProvider = + SdkLoggerProvider.builder().addLogRecordProcessor(logRecordProcessor).build(); + SdkLogger logger = (SdkLogger) loggerProvider.get("test"); + + LoggerConfig config = + LoggerConfig.builder().setMinimumSeverity(Severity.WARN.getSeverityNumber()).build(); + logger.updateLoggerConfig(config); + + // Below minimum severity - should be disabled + assertThat(logger.isEnabled(Severity.INFO, Context.current())).isFalse(); + assertThat(logger.isEnabled(Severity.DEBUG, Context.current())).isFalse(); + + // At or above minimum severity - should be enabled + assertThat(logger.isEnabled(Severity.WARN, Context.current())).isTrue(); + assertThat(logger.isEnabled(Severity.ERROR, Context.current())).isTrue(); + + // Undefined severity - should be enabled (bypasses minimum severity filter) + assertThat(logger.isEnabled(Severity.UNDEFINED_SEVERITY_NUMBER, Context.current())).isTrue(); + } + + @Test + void isEnabled_TraceBased() { + LogRecordProcessor logRecordProcessor = mock(LogRecordProcessor.class); + SdkLoggerProvider loggerProvider = + SdkLoggerProvider.builder().addLogRecordProcessor(logRecordProcessor).build(); + SdkLogger logger = (SdkLogger) loggerProvider.get("test"); + + LoggerConfig config = LoggerConfig.builder().setTraceBased(true).build(); + logger.updateLoggerConfig(config); + + // No trace context - should be enabled + assertThat(logger.isEnabled(Severity.INFO, Context.current())).isTrue(); + + // Sampled trace - should be enabled + SpanContext sampledSpanContext = + SpanContext.create( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bbbbbbbbbbbbbbbb", + TraceFlags.getSampled(), + TraceState.getDefault()); + Context sampledContext = Span.wrap(sampledSpanContext).storeInContext(Context.root()); + assertThat(logger.isEnabled(Severity.INFO, sampledContext)).isTrue(); + + // Unsampled trace - should be disabled + SpanContext unsampledSpanContext = + SpanContext.create( + "cccccccccccccccccccccccccccccccc", + "dddddddddddddddd", + TraceFlags.getDefault(), + TraceState.getDefault()); + Context unsampledContext = Span.wrap(unsampledSpanContext).storeInContext(Context.root()); + assertThat(logger.isEnabled(Severity.INFO, unsampledContext)).isFalse(); + } + + @Test + void isEnabled_MinimumSeverityAndTraceBased() { + LogRecordProcessor logRecordProcessor = mock(LogRecordProcessor.class); + SdkLoggerProvider loggerProvider = + SdkLoggerProvider.builder().addLogRecordProcessor(logRecordProcessor).build(); + SdkLogger logger = (SdkLogger) loggerProvider.get("test"); + + LoggerConfig config = + LoggerConfig.builder() + .setMinimumSeverity(Severity.WARN.getSeverityNumber()) + .setTraceBased(true) + .build(); + logger.updateLoggerConfig(config); + + SpanContext sampledSpanContext = + SpanContext.create( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bbbbbbbbbbbbbbbb", + TraceFlags.getSampled(), + TraceState.getDefault()); + Context sampledContext = Span.wrap(sampledSpanContext).storeInContext(Context.root()); + + SpanContext unsampledSpanContext = + SpanContext.create( + "cccccccccccccccccccccccccccccccc", + "dddddddddddddddd", + TraceFlags.getDefault(), + TraceState.getDefault()); + Context unsampledContext = Span.wrap(unsampledSpanContext).storeInContext(Context.root()); + + // Below minimum severity in sampled trace - should be disabled + assertThat(logger.isEnabled(Severity.INFO, sampledContext)).isFalse(); + + // At or above minimum severity in sampled trace - should be enabled + assertThat(logger.isEnabled(Severity.WARN, sampledContext)).isTrue(); + assertThat(logger.isEnabled(Severity.ERROR, sampledContext)).isTrue(); + + // At or above minimum severity in unsampled trace - should be disabled + assertThat(logger.isEnabled(Severity.WARN, unsampledContext)).isFalse(); + assertThat(logger.isEnabled(Severity.ERROR, unsampledContext)).isFalse(); + } } diff --git a/sdk/logs/src/testIncubating/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java b/sdk/logs/src/testIncubating/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java index 699f9be4c4d..57f1d14a781 100644 --- a/sdk/logs/src/testIncubating/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java +++ b/sdk/logs/src/testIncubating/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java @@ -33,6 +33,29 @@ class LoggerConfigTest { + @Test + void builder_AllFields() { + LoggerConfig config = + LoggerConfig.builder() + .setEnabled(false) + .setMinimumSeverity(Severity.WARN.getSeverityNumber()) + .setTraceBased(true) + .build(); + + assertThat(config.isEnabled()).isFalse(); + assertThat(config.getMinimumSeverity()).isEqualTo(Severity.WARN.getSeverityNumber()); + assertThat(config.isTraceBased()).isTrue(); + } + + @Test + void builder_Defaults() { + LoggerConfig config = LoggerConfig.builder().build(); + + assertThat(config.isEnabled()).isTrue(); + assertThat(config.getMinimumSeverity()).isEqualTo(0); + assertThat(config.isTraceBased()).isFalse(); + } + @Test void disableScopes() { InMemoryLogRecordExporter exporter = InMemoryLogRecordExporter.create(); From 2ad2e1992e0405c3516ca4f7ca17a601c41c5eba Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Wed, 22 Oct 2025 11:02:56 -0700 Subject: [PATCH 2/6] share --- .../sdk/logs/ExtendedSdkLogRecordBuilder.java | 43 ++++++------------- .../sdk/logs/SdkLogRecordBuilder.java | 30 +++++++------ 2 files changed, 29 insertions(+), 44 deletions(-) diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/ExtendedSdkLogRecordBuilder.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/ExtendedSdkLogRecordBuilder.java index 45879497259..07444ba738a 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/ExtendedSdkLogRecordBuilder.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/ExtendedSdkLogRecordBuilder.java @@ -130,35 +130,18 @@ public ExtendedSdkLogRecordBuilder setAttribute(AttributeKey key, @Nullab } @Override - public void emit() { - if (loggerSharedState.hasBeenShutdown()) { - return; - } - - Context context = this.context == null ? Context.current() : this.context; - if (!logger.isEnabled(severity, context)) { - return; - } - - long observedTimestampEpochNanos = - this.observedTimestampEpochNanos == 0 - ? this.loggerSharedState.getClock().now() - : this.observedTimestampEpochNanos; - loggerSharedState - .getLogRecordProcessor() - .onEmit( - context, - ExtendedSdkReadWriteLogRecord.create( - loggerSharedState.getLogLimits(), - loggerSharedState.getResource(), - instrumentationScopeInfo, - eventName, - timestampEpochNanos, - observedTimestampEpochNanos, - Span.fromContext(context).getSpanContext(), - severity, - severityText, - body, - extendedAttributes)); + protected ReadWriteLogRecord createLogRecord(Context context, long observedTimestampEpochNanos) { + return ExtendedSdkReadWriteLogRecord.create( + loggerSharedState.getLogLimits(), + loggerSharedState.getResource(), + instrumentationScopeInfo, + eventName, + timestampEpochNanos, + observedTimestampEpochNanos, + Span.fromContext(context).getSpanContext(), + severity, + severityText, + body, + extendedAttributes); } } diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilder.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilder.java index 359b7331fb5..35c29a20025 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilder.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilder.java @@ -134,19 +134,21 @@ public void emit() { : this.observedTimestampEpochNanos; loggerSharedState .getLogRecordProcessor() - .onEmit( - context, - SdkReadWriteLogRecord.create( - loggerSharedState.getLogLimits(), - loggerSharedState.getResource(), - instrumentationScopeInfo, - timestampEpochNanos, - observedTimestampEpochNanos, - Span.fromContext(context).getSpanContext(), - severity, - severityText, - body, - attributes, - eventName)); + .onEmit(context, createLogRecord(context, observedTimestampEpochNanos)); + } + + protected ReadWriteLogRecord createLogRecord(Context context, long observedTimestampEpochNanos) { + return SdkReadWriteLogRecord.create( + loggerSharedState.getLogLimits(), + loggerSharedState.getResource(), + instrumentationScopeInfo, + timestampEpochNanos, + observedTimestampEpochNanos, + Span.fromContext(context).getSpanContext(), + severity, + severityText, + body, + attributes, + eventName); } } From a88392eb88629966876f8dd4d25143c4d5be8839 Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Wed, 22 Oct 2025 12:01:09 -0700 Subject: [PATCH 3/6] refine tests --- .../sdk/logs/SdkLogRecordBuilderTest.java | 77 ++++--------------- .../opentelemetry/sdk/logs/SdkLoggerTest.java | 57 +------------- 2 files changed, 15 insertions(+), 119 deletions(-) diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilderTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilderTest.java index 0caf35c03d9..0d54efdec42 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilderTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilderTest.java @@ -11,6 +11,9 @@ import static io.opentelemetry.api.common.AttributeKey.stringKey; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import io.opentelemetry.api.common.AttributeKey; @@ -124,75 +127,23 @@ void emit_NoFields() { } @Test - void emit_WithMinimumSeverityConfiguration() { - LoggerConfig config = - LoggerConfig.builder().setMinimumSeverity(Severity.INFO.getSeverityNumber()).build(); - SdkLogger logger = new SdkLogger(loggerSharedState, SCOPE_INFO, config); + void emit_ChecksLoggerIsEnabled() { + SdkLogger logger = mock(SdkLogger.class); builder = new SdkLogRecordBuilder(loggerSharedState, SCOPE_INFO, logger); - builder.setBody("too-low").setSeverity(Severity.DEBUG).emit(); - assertThat(emittedLog.get()).isNull(); - - builder.setBody("allowed").setSeverity(Severity.INFO).emit(); - assertThat(emittedLog.get().toLogRecordData()).hasBody("allowed"); - } - - @Test - void emit_DropsUnsampledTraceWhenTraceBased() { - LoggerConfig config = LoggerConfig.builder().setTraceBased(true).build(); - SdkLogger logger = new SdkLogger(loggerSharedState, SCOPE_INFO, config); - builder = new SdkLogRecordBuilder(loggerSharedState, SCOPE_INFO, logger); - - SpanContext unsampledSpanContext = - SpanContext.create( - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "bbbbbbbbbbbbbbbb", - TraceFlags.getDefault(), - TraceState.getDefault()); - builder - .setBody("unsampled") - .setContext(Span.wrap(unsampledSpanContext).storeInContext(Context.root())) - .emit(); - assertThat(emittedLog.get()).isNull(); - - SpanContext sampledSpanContext = - SpanContext.create( - "cccccccccccccccccccccccccccccccc", - "dddddddddddddddd", - TraceFlags.getSampled(), - TraceState.getDefault()); - builder - .setBody("sampled") - .setContext(Span.wrap(sampledSpanContext).storeInContext(Context.root())) - .emit(); - assertThat(emittedLog.get().toLogRecordData()) - .hasSpanContext(sampledSpanContext) - .hasBody("sampled"); - } + Severity severity = Severity.WARN; + Context context = Context.current(); - @Test - void emit_AllowsUndefinedSeverityWithMinimumSeverity() { - LoggerConfig config = - LoggerConfig.builder().setMinimumSeverity(Severity.WARN.getSeverityNumber()).build(); - SdkLogger logger = new SdkLogger(loggerSharedState, SCOPE_INFO, config); - builder = new SdkLogRecordBuilder(loggerSharedState, SCOPE_INFO, logger); + // Configure mock to return false (disabled) + when(logger.isEnabled(severity, context)).thenReturn(false); - // Undefined severity should bypass the minimum severity filter - builder.setBody("undefined-severity").setSeverity(Severity.UNDEFINED_SEVERITY_NUMBER).emit(); - assertThat(emittedLog.get().toLogRecordData()) - .hasBody("undefined-severity") - .hasSeverity(Severity.UNDEFINED_SEVERITY_NUMBER); - } + builder.setSeverity(severity).setContext(context).emit(); - @Test - void emit_AllowsNoTraceContextWithTraceBased() { - LoggerConfig config = LoggerConfig.builder().setTraceBased(true).build(); - SdkLogger logger = new SdkLogger(loggerSharedState, SCOPE_INFO, config); - builder = new SdkLogRecordBuilder(loggerSharedState, SCOPE_INFO, logger); + // Verify isEnabled was called with correct parameters + verify(logger).isEnabled(eq(severity), eq(context)); - // No trace context should bypass the trace-based filter - builder.setBody("no-trace-context").emit(); - assertThat(emittedLog.get().toLogRecordData()).hasBody("no-trace-context"); + // Verify log was not processed (because isEnabled returned false) + assertThat(emittedLog.get()).isNull(); } @Test diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java index 6a502fbdc04..29ec0b00a43 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java @@ -141,20 +141,7 @@ void logRecordBuilder_AfterShutdown() { } @Test - void updateEnabled() { - LogRecordProcessor logRecordProcessor = mock(LogRecordProcessor.class); - SdkLoggerProvider loggerProvider = - SdkLoggerProvider.builder().addLogRecordProcessor(logRecordProcessor).build(); - SdkLogger logger = (SdkLogger) loggerProvider.get("test"); - - logger.updateLoggerConfig(LoggerConfig.disabled()); - assertThat(logger.isEnabled(Severity.UNDEFINED_SEVERITY_NUMBER, Context.current())).isFalse(); - logger.updateLoggerConfig(LoggerConfig.enabled()); - assertThat(logger.isEnabled(Severity.UNDEFINED_SEVERITY_NUMBER, Context.current())).isTrue(); - } - - @Test - void updateLoggerConfig_UpdatesAllFields() { + void updateLoggerConfig() { LogRecordProcessor logRecordProcessor = mock(LogRecordProcessor.class); SdkLoggerProvider loggerProvider = SdkLoggerProvider.builder().addLogRecordProcessor(logRecordProcessor).build(); @@ -235,46 +222,4 @@ void isEnabled_TraceBased() { Context unsampledContext = Span.wrap(unsampledSpanContext).storeInContext(Context.root()); assertThat(logger.isEnabled(Severity.INFO, unsampledContext)).isFalse(); } - - @Test - void isEnabled_MinimumSeverityAndTraceBased() { - LogRecordProcessor logRecordProcessor = mock(LogRecordProcessor.class); - SdkLoggerProvider loggerProvider = - SdkLoggerProvider.builder().addLogRecordProcessor(logRecordProcessor).build(); - SdkLogger logger = (SdkLogger) loggerProvider.get("test"); - - LoggerConfig config = - LoggerConfig.builder() - .setMinimumSeverity(Severity.WARN.getSeverityNumber()) - .setTraceBased(true) - .build(); - logger.updateLoggerConfig(config); - - SpanContext sampledSpanContext = - SpanContext.create( - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "bbbbbbbbbbbbbbbb", - TraceFlags.getSampled(), - TraceState.getDefault()); - Context sampledContext = Span.wrap(sampledSpanContext).storeInContext(Context.root()); - - SpanContext unsampledSpanContext = - SpanContext.create( - "cccccccccccccccccccccccccccccccc", - "dddddddddddddddd", - TraceFlags.getDefault(), - TraceState.getDefault()); - Context unsampledContext = Span.wrap(unsampledSpanContext).storeInContext(Context.root()); - - // Below minimum severity in sampled trace - should be disabled - assertThat(logger.isEnabled(Severity.INFO, sampledContext)).isFalse(); - - // At or above minimum severity in sampled trace - should be enabled - assertThat(logger.isEnabled(Severity.WARN, sampledContext)).isTrue(); - assertThat(logger.isEnabled(Severity.ERROR, sampledContext)).isTrue(); - - // At or above minimum severity in unsampled trace - should be disabled - assertThat(logger.isEnabled(Severity.WARN, unsampledContext)).isFalse(); - assertThat(logger.isEnabled(Severity.ERROR, unsampledContext)).isFalse(); - } } From bc4e9683aa1651661f1271e2f46ca3feb24eff10 Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Thu, 6 Nov 2025 12:59:18 -0800 Subject: [PATCH 4/6] top-level builder --- .../sdk/logs/internal/LoggerConfig.java | 65 +------------------ 1 file changed, 3 insertions(+), 62 deletions(-) diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/LoggerConfig.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/LoggerConfig.java index db23bfc65f5..a535c09582b 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/LoggerConfig.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/LoggerConfig.java @@ -46,9 +46,9 @@ public static LoggerConfig enabled() { return DEFAULT_CONFIG; } - /** Returns a new {@link Builder} for creating a {@link LoggerConfig}. */ - public static Builder builder() { - return new Builder(); + /** Returns a new {@link LoggerConfigBuilder} for creating a {@link LoggerConfig}. */ + public static LoggerConfigBuilder builder() { + return new LoggerConfigBuilder(); } /** @@ -69,65 +69,6 @@ public static ScopeConfiguratorBuilder configuratorBuilder() { LoggerConfig() {} - /** - * Builder for {@link LoggerConfig}. - * - *

This class is internal and experimental. Its APIs are unstable and can change at any time. - * Its APIs (or a version of them) may be promoted to the public stable API in the future, but no - * guarantees are made. - */ - public static final class Builder { - private boolean enabled = true; - private int minimumSeverity = 0; - private boolean traceBased = false; - - private Builder() {} - - /** - * Sets whether the logger is enabled. - * - * @param enabled whether the logger is enabled - * @return this builder - */ - public Builder setEnabled(boolean enabled) { - this.enabled = enabled; - return this; - } - - /** - * Sets the minimum severity level for log records to be processed. - * - *

Log records with a severity number less than this value will be dropped. Log records - * without a specified severity are not affected by this setting. - * - * @param minimumSeverity minimum severity level for log records to be processed - * @return this builder - */ - public Builder setMinimumSeverity(int minimumSeverity) { - this.minimumSeverity = minimumSeverity; - return this; - } - - /** - * Sets whether to only process log records from traces when the trace is sampled. - * - *

When enabled, log records from unsampled traces will be dropped. Log records that are not - * associated with a trace context are unaffected. - * - * @param traceBased whether to only process log records from traces when the trace is sampled - * @return this builder - */ - public Builder setTraceBased(boolean traceBased) { - this.traceBased = traceBased; - return this; - } - - /** Builds and returns a {@link LoggerConfig}. */ - public LoggerConfig build() { - return new AutoValue_LoggerConfig(enabled, minimumSeverity, traceBased); - } - } - /** Returns {@code true} if this logger is enabled. Defaults to {@code true}. */ public abstract boolean isEnabled(); From 77dcc3ed223b25177b7f4d8939938338b7e9b58a Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Thu, 6 Nov 2025 13:09:49 -0800 Subject: [PATCH 5/6] int to Severity --- .../io/opentelemetry/sdk/logs/SdkLogger.java | 4 ++-- .../sdk/logs/internal/LoggerConfig.java | 17 +++++++++++++---- .../opentelemetry/sdk/logs/SdkLoggerTest.java | 8 ++++---- .../sdk/logs/LoggerConfigTest.java | 6 +++--- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java index ab1724f3bbe..0fa97771d1f 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java @@ -36,7 +36,7 @@ class SdkLogger implements Logger { private final InstrumentationScopeInfo instrumentationScopeInfo; protected volatile boolean loggerEnabled; - protected volatile int minimumSeverity; + protected volatile Severity minimumSeverity; protected volatile boolean traceBased; SdkLogger( @@ -82,7 +82,7 @@ public boolean isEnabled(Severity severity, Context context) { } if (severity != Severity.UNDEFINED_SEVERITY_NUMBER - && severity.getSeverityNumber() < minimumSeverity) { + && severity.getSeverityNumber() < minimumSeverity.getSeverityNumber()) { return false; } diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/LoggerConfig.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/LoggerConfig.java index a535c09582b..462dd16e650 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/LoggerConfig.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/LoggerConfig.java @@ -7,6 +7,7 @@ import com.google.auto.value.AutoValue; import io.opentelemetry.api.logs.Logger; +import io.opentelemetry.api.logs.Severity; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.internal.ScopeConfigurator; import io.opentelemetry.sdk.internal.ScopeConfiguratorBuilder; @@ -31,10 +32,14 @@ public abstract class LoggerConfig { private static final LoggerConfig DEFAULT_CONFIG = new AutoValue_LoggerConfig( - /* enabled= */ true, /* minimumSeverity= */ 0, /* traceBased= */ false); + /* enabled= */ true, + /* minimumSeverity= */ Severity.UNDEFINED_SEVERITY_NUMBER, + /* traceBased= */ false); private static final LoggerConfig DISABLED_CONFIG = new AutoValue_LoggerConfig( - /* enabled= */ false, /* minimumSeverity= */ 0, /* traceBased= */ false); + /* enabled= */ false, + /* minimumSeverity= */ Severity.UNDEFINED_SEVERITY_NUMBER, + /* traceBased= */ false); /** Returns a disabled {@link LoggerConfig}. */ public static LoggerConfig disabled() { @@ -69,6 +74,10 @@ public static ScopeConfiguratorBuilder configuratorBuilder() { LoggerConfig() {} + static LoggerConfig create(boolean enabled, Severity minimumSeverity, boolean traceBased) { + return new AutoValue_LoggerConfig(enabled, minimumSeverity, traceBased); + } + /** Returns {@code true} if this logger is enabled. Defaults to {@code true}. */ public abstract boolean isEnabled(); @@ -78,9 +87,9 @@ public static ScopeConfiguratorBuilder configuratorBuilder() { *

Log records with a severity number less than this value will be dropped. Log records without * a specified severity are not affected by this setting. * - *

Defaults to {@code 0}. + *

Defaults to {@link Severity#UNDEFINED_SEVERITY_NUMBER}. */ - public abstract int getMinimumSeverity(); + public abstract Severity getMinimumSeverity(); /** * Returns {@code true} if this logger should only process log records from traces when the trace diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java index 29ec0b00a43..a2fc305e9d8 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java @@ -149,20 +149,20 @@ void updateLoggerConfig() { // Start with default config assertThat(logger.loggerEnabled).isTrue(); - assertThat(logger.minimumSeverity).isEqualTo(0); + assertThat(logger.minimumSeverity).isEqualTo(Severity.UNDEFINED_SEVERITY_NUMBER); assertThat(logger.traceBased).isFalse(); // Update to custom config LoggerConfig config = LoggerConfig.builder() .setEnabled(false) - .setMinimumSeverity(Severity.WARN.getSeverityNumber()) + .setMinimumSeverity(Severity.WARN) .setTraceBased(true) .build(); logger.updateLoggerConfig(config); assertThat(logger.loggerEnabled).isFalse(); - assertThat(logger.minimumSeverity).isEqualTo(Severity.WARN.getSeverityNumber()); + assertThat(logger.minimumSeverity).isEqualTo(Severity.WARN); assertThat(logger.traceBased).isTrue(); } @@ -174,7 +174,7 @@ void isEnabled_MinimumSeverity() { SdkLogger logger = (SdkLogger) loggerProvider.get("test"); LoggerConfig config = - LoggerConfig.builder().setMinimumSeverity(Severity.WARN.getSeverityNumber()).build(); + LoggerConfig.builder().setMinimumSeverity(Severity.WARN).build(); logger.updateLoggerConfig(config); // Below minimum severity - should be disabled diff --git a/sdk/logs/src/testIncubating/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java b/sdk/logs/src/testIncubating/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java index 57f1d14a781..145d4a5b050 100644 --- a/sdk/logs/src/testIncubating/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java +++ b/sdk/logs/src/testIncubating/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java @@ -38,12 +38,12 @@ void builder_AllFields() { LoggerConfig config = LoggerConfig.builder() .setEnabled(false) - .setMinimumSeverity(Severity.WARN.getSeverityNumber()) + .setMinimumSeverity(Severity.WARN) .setTraceBased(true) .build(); assertThat(config.isEnabled()).isFalse(); - assertThat(config.getMinimumSeverity()).isEqualTo(Severity.WARN.getSeverityNumber()); + assertThat(config.getMinimumSeverity()).isEqualTo(Severity.WARN); assertThat(config.isTraceBased()).isTrue(); } @@ -52,7 +52,7 @@ void builder_Defaults() { LoggerConfig config = LoggerConfig.builder().build(); assertThat(config.isEnabled()).isTrue(); - assertThat(config.getMinimumSeverity()).isEqualTo(0); + assertThat(config.getMinimumSeverity()).isEqualTo(Severity.UNDEFINED_SEVERITY_NUMBER); assertThat(config.isTraceBased()).isFalse(); } From 7aa2b8d32bd4a982e149a48576b6c1d407253178 Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Thu, 6 Nov 2025 13:12:40 -0800 Subject: [PATCH 6/6] oops --- .../logs/internal/LoggerConfigBuilder.java | 67 +++++++++++++++++++ .../opentelemetry/sdk/logs/SdkLoggerTest.java | 3 +- 2 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/LoggerConfigBuilder.java diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/LoggerConfigBuilder.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/LoggerConfigBuilder.java new file mode 100644 index 00000000000..af77cce7c9c --- /dev/null +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/LoggerConfigBuilder.java @@ -0,0 +1,67 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.logs.internal; + +import io.opentelemetry.api.logs.Severity; + +/** + * Builder for {@link LoggerConfig}. + * + *

This class is internal and experimental. Its APIs are unstable and can change at any time. Its + * APIs (or a version of them) may be promoted to the public stable API in the future, but no + * guarantees are made. + */ +public final class LoggerConfigBuilder { + private boolean enabled = true; + private Severity minimumSeverity = Severity.UNDEFINED_SEVERITY_NUMBER; + private boolean traceBased = false; + + LoggerConfigBuilder() {} + + /** + * Sets whether the logger is enabled. + * + * @param enabled whether the logger is enabled + * @return this builder + */ + public LoggerConfigBuilder setEnabled(boolean enabled) { + this.enabled = enabled; + return this; + } + + /** + * Sets the minimum severity level for log records to be processed. + * + *

Log records with a severity number less than this value will be dropped. Log records without + * a specified severity are not affected by this setting. + * + * @param minimumSeverity minimum severity level for log records to be processed + * @return this builder + */ + public LoggerConfigBuilder setMinimumSeverity(Severity minimumSeverity) { + this.minimumSeverity = minimumSeverity; + return this; + } + + /** + * Sets whether to only process log records from traces when the trace is sampled. + * + *

When enabled, log records from unsampled traces will be dropped. Log records that are not + * associated with a trace context are unaffected. + * + * @param traceBased whether to only process log records from traces when the trace is sampled + * @return this builder + */ + public LoggerConfigBuilder setTraceBased(boolean traceBased) { + this.traceBased = traceBased; + return this; + } + + /** Builds and returns a {@link LoggerConfig}. */ + public LoggerConfig build() { + return LoggerConfig.create(enabled, minimumSeverity, traceBased); + } +} diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java index a2fc305e9d8..4abed011635 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java @@ -173,8 +173,7 @@ void isEnabled_MinimumSeverity() { SdkLoggerProvider.builder().addLogRecordProcessor(logRecordProcessor).build(); SdkLogger logger = (SdkLogger) loggerProvider.get("test"); - LoggerConfig config = - LoggerConfig.builder().setMinimumSeverity(Severity.WARN).build(); + LoggerConfig config = LoggerConfig.builder().setMinimumSeverity(Severity.WARN).build(); logger.updateLoggerConfig(config); // Below minimum severity - should be disabled