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..6cbfab0b9d9 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,20 @@ public void emit() { if (loggerSharedState.hasBeenShutdown()) { return; } + + if (severity != Severity.UNDEFINED_SEVERITY_NUMBER + && severity.getSeverityNumber() < logger.minimumSeverity) { + return; + } + Context context = this.context == null ? Context.current() : this.context; + if (logger.traceBased) { + Span span = Span.fromContext(context); + if (span.getSpanContext().isValid() && !span.getSpanContext().getTraceFlags().isSampled()) { + 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..3fd41423a56 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,7 @@ 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..9f798492360 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 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 7539a5c3b17..4a9cce1237c 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; @@ -36,6 +38,8 @@ class SdkLogger implements Logger { // deliberately not volatile because of performance concerns // - which means its eventually consistent protected boolean loggerEnabled; + protected int minimumSeverity; + protected boolean traceBased; SdkLogger( LoggerSharedState loggerSharedState, @@ -44,6 +48,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( @@ -60,8 +66,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(); } @@ -73,10 +79,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..223d7f22f53 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,9 @@ 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 +44,13 @@ 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,87 @@ 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 sampled traces. + * + *

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 sampled traces + * @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 sampled traces. + * + *

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..515884cc34a 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