Add `setLoggerConfigurator` support to `LoggerProvider` (#7332)
This commit is contained in:
parent
58acb531c5
commit
983133fd0d
|
@ -13,19 +13,17 @@ import io.opentelemetry.sdk.logs.internal.LoggerConfig;
|
|||
/** SDK implementation of {@link ExtendedLogger}. */
|
||||
final class ExtendedSdkLogger extends SdkLogger implements ExtendedLogger {
|
||||
|
||||
private final boolean loggerEnabled;
|
||||
|
||||
ExtendedSdkLogger(
|
||||
LoggerSharedState loggerSharedState,
|
||||
InstrumentationScopeInfo instrumentationScopeInfo,
|
||||
LoggerConfig loggerConfig) {
|
||||
super(loggerSharedState, instrumentationScopeInfo, loggerConfig);
|
||||
this.loggerEnabled = loggerConfig.isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("RedundantOverride")
|
||||
public boolean isEnabled() {
|
||||
return loggerEnabled;
|
||||
return super.isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -30,7 +30,10 @@ class SdkLogger implements Logger {
|
|||
|
||||
private final LoggerSharedState loggerSharedState;
|
||||
private final InstrumentationScopeInfo instrumentationScopeInfo;
|
||||
private final boolean loggerEnabled;
|
||||
|
||||
// deliberately not volatile because of performance concerns
|
||||
// - which means its eventually consistent
|
||||
protected boolean loggerEnabled;
|
||||
|
||||
SdkLogger(
|
||||
LoggerSharedState loggerSharedState,
|
||||
|
@ -65,4 +68,12 @@ class SdkLogger implements Logger {
|
|||
InstrumentationScopeInfo getInstrumentationScopeInfo() {
|
||||
return instrumentationScopeInfo;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return loggerEnabled;
|
||||
}
|
||||
|
||||
void updateLoggerConfig(LoggerConfig loggerConfig) {
|
||||
loggerEnabled = loggerConfig.isEnabled();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,9 +36,12 @@ public final class SdkLoggerProvider implements LoggerProvider, Closeable {
|
|||
|
||||
private final LoggerSharedState sharedState;
|
||||
private final ComponentRegistry<SdkLogger> loggerComponentRegistry;
|
||||
private final ScopeConfigurator<LoggerConfig> loggerConfigurator;
|
||||
private final boolean isNoopLogRecordProcessor;
|
||||
|
||||
// deliberately not volatile because of performance concerns
|
||||
// - which means its eventually consistent
|
||||
private ScopeConfigurator<LoggerConfig> loggerConfigurator;
|
||||
|
||||
/**
|
||||
* Returns a new {@link SdkLoggerProviderBuilder} for {@link SdkLoggerProvider}.
|
||||
*
|
||||
|
@ -96,6 +99,26 @@ public final class SdkLoggerProvider implements LoggerProvider, Closeable {
|
|||
return instrumentationScopeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the logger configurator, which computes {@link LoggerConfig} for each {@link
|
||||
* InstrumentationScopeInfo}.
|
||||
*
|
||||
* <p>This method is experimental so not public. You may reflectively call it using {@link
|
||||
* io.opentelemetry.sdk.logs.internal.SdkLoggerProviderUtil#setLoggerConfigurator(SdkLoggerProvider,
|
||||
* ScopeConfigurator)}.
|
||||
*
|
||||
* @see LoggerConfig#configuratorBuilder()
|
||||
*/
|
||||
void setLoggerConfigurator(ScopeConfigurator<LoggerConfig> loggerConfigurator) {
|
||||
this.loggerConfigurator = loggerConfigurator;
|
||||
this.loggerComponentRegistry
|
||||
.getComponents()
|
||||
.forEach(
|
||||
sdkLogger ->
|
||||
sdkLogger.updateLoggerConfig(
|
||||
getLoggerConfig(sdkLogger.getInstrumentationScopeInfo())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Request the active log processor to process all logs that have not yet been processed.
|
||||
*
|
||||
|
|
|
@ -7,6 +7,7 @@ package io.opentelemetry.sdk.logs.internal;
|
|||
|
||||
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
|
||||
import io.opentelemetry.sdk.internal.ScopeConfigurator;
|
||||
import io.opentelemetry.sdk.logs.SdkLoggerProvider;
|
||||
import io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
@ -23,6 +24,21 @@ public final class SdkLoggerProviderUtil {
|
|||
|
||||
private SdkLoggerProviderUtil() {}
|
||||
|
||||
/** Reflectively set the {@link ScopeConfigurator} to the {@link SdkLoggerProvider}. */
|
||||
public static void setLoggerConfigurator(
|
||||
SdkLoggerProvider sdkLoggerProvider, ScopeConfigurator<LoggerConfig> scopeConfigurator) {
|
||||
try {
|
||||
Method method =
|
||||
SdkLoggerProvider.class.getDeclaredMethod(
|
||||
"setLoggerConfigurator", ScopeConfigurator.class);
|
||||
method.setAccessible(true);
|
||||
method.invoke(sdkLoggerProvider, scopeConfigurator);
|
||||
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
|
||||
throw new IllegalStateException(
|
||||
"Error calling setLoggerConfigurator on SdkLoggerProvider", e);
|
||||
}
|
||||
}
|
||||
|
||||
/** Reflectively set the {@link ScopeConfigurator} to the {@link SdkLoggerProviderBuilder}. */
|
||||
public static SdkLoggerProviderBuilder setLoggerConfigurator(
|
||||
SdkLoggerProviderBuilder sdkLoggerProviderBuilder,
|
||||
|
|
|
@ -28,7 +28,10 @@ import io.opentelemetry.internal.testing.slf4j.SuppressLogger;
|
|||
import io.opentelemetry.sdk.common.Clock;
|
||||
import io.opentelemetry.sdk.common.CompletableResultCode;
|
||||
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
|
||||
import io.opentelemetry.sdk.internal.ScopeConfigurator;
|
||||
import io.opentelemetry.sdk.logs.data.LogRecordData;
|
||||
import io.opentelemetry.sdk.logs.internal.LoggerConfig;
|
||||
import io.opentelemetry.sdk.logs.internal.SdkLoggerProviderUtil;
|
||||
import io.opentelemetry.sdk.resources.Resource;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -350,4 +353,28 @@ class SdkLoggerProviderTest {
|
|||
+ "loggerConfigurator=ScopeConfiguratorImpl{conditions=[]}"
|
||||
+ "}");
|
||||
}
|
||||
|
||||
private static ScopeConfigurator<LoggerConfig> flipConfigurator(boolean enabled) {
|
||||
return scopeInfo -> enabled ? LoggerConfig.disabled() : LoggerConfig.enabled();
|
||||
}
|
||||
|
||||
@Test
|
||||
void propagatesEnablementToLoggerDirectly() {
|
||||
SdkLogger logger = (SdkLogger) sdkLoggerProvider.get("test");
|
||||
boolean isEnabled = logger.isEnabled();
|
||||
|
||||
sdkLoggerProvider.setLoggerConfigurator(flipConfigurator(isEnabled));
|
||||
|
||||
assertThat(logger.isEnabled()).isEqualTo(!isEnabled);
|
||||
}
|
||||
|
||||
@Test
|
||||
void propagatesEnablementToLoggerByUtil() {
|
||||
SdkLogger logger = (SdkLogger) sdkLoggerProvider.get("test");
|
||||
boolean isEnabled = logger.isEnabled();
|
||||
|
||||
SdkLoggerProviderUtil.setLoggerConfigurator(sdkLoggerProvider, flipConfigurator(isEnabled));
|
||||
|
||||
assertThat(logger.isEnabled()).isEqualTo(!isEnabled);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -133,4 +133,17 @@ class SdkLoggerTest {
|
|||
|
||||
verify(logRecordProcessor, never()).onEmit(any(), any());
|
||||
}
|
||||
|
||||
@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()).isFalse();
|
||||
logger.updateLoggerConfig(LoggerConfig.enabled());
|
||||
assertThat(logger.isEnabled()).isTrue();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ package io.opentelemetry.sdk.logs;
|
|||
import static io.opentelemetry.sdk.internal.ScopeConfiguratorBuilder.nameEquals;
|
||||
import static io.opentelemetry.sdk.internal.ScopeConfiguratorBuilder.nameMatchesGlob;
|
||||
import static io.opentelemetry.sdk.logs.internal.LoggerConfig.defaultConfig;
|
||||
import static io.opentelemetry.sdk.logs.internal.LoggerConfig.disabled;
|
||||
import static io.opentelemetry.sdk.logs.internal.LoggerConfig.enabled;
|
||||
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
|
||||
|
||||
|
@ -37,7 +38,7 @@ class LoggerConfigTest {
|
|||
SdkLoggerProvider.builder()
|
||||
// Disable loggerB. Since loggers are enabled by default, loggerA and loggerC are
|
||||
// enabled.
|
||||
.addLoggerConfiguratorCondition(nameEquals("loggerB"), LoggerConfig.disabled())
|
||||
.addLoggerConfiguratorCondition(nameEquals("loggerB"), disabled())
|
||||
.addLogRecordProcessor(SimpleLogRecordProcessor.create(exporter))
|
||||
.build();
|
||||
|
||||
|
@ -86,25 +87,23 @@ class LoggerConfigTest {
|
|||
LoggerConfig.configuratorBuilder().build();
|
||||
ScopeConfigurator<LoggerConfig> disableCat =
|
||||
LoggerConfig.configuratorBuilder()
|
||||
.addCondition(nameEquals("cat"), LoggerConfig.disabled())
|
||||
.addCondition(nameEquals("cat"), disabled())
|
||||
// Second matching rule for cat should be ignored
|
||||
.addCondition(nameEquals("cat"), enabled())
|
||||
.build();
|
||||
ScopeConfigurator<LoggerConfig> disableStartsWithD =
|
||||
LoggerConfig.configuratorBuilder()
|
||||
.addCondition(nameMatchesGlob("d*"), LoggerConfig.disabled())
|
||||
.build();
|
||||
LoggerConfig.configuratorBuilder().addCondition(nameMatchesGlob("d*"), disabled()).build();
|
||||
ScopeConfigurator<LoggerConfig> enableCat =
|
||||
LoggerConfig.configuratorBuilder()
|
||||
.setDefault(LoggerConfig.disabled())
|
||||
.setDefault(disabled())
|
||||
.addCondition(nameEquals("cat"), enabled())
|
||||
// Second matching rule for cat should be ignored
|
||||
.addCondition(nameEquals("cat"), LoggerConfig.disabled())
|
||||
.addCondition(nameEquals("cat"), disabled())
|
||||
.build();
|
||||
ScopeConfigurator<LoggerConfig> enableStartsWithD =
|
||||
LoggerConfig.configuratorBuilder()
|
||||
.setDefault(LoggerConfig.disabled())
|
||||
.addCondition(nameMatchesGlob("d*"), LoggerConfig.enabled())
|
||||
.setDefault(disabled())
|
||||
.addCondition(nameMatchesGlob("d*"), enabled())
|
||||
.build();
|
||||
|
||||
return Stream.of(
|
||||
|
@ -113,20 +112,83 @@ class LoggerConfigTest {
|
|||
Arguments.of(defaultConfigurator, scopeDog, defaultConfig()),
|
||||
Arguments.of(defaultConfigurator, scopeDuck, defaultConfig()),
|
||||
// default enabled, disable cat
|
||||
Arguments.of(disableCat, scopeCat, LoggerConfig.disabled()),
|
||||
Arguments.of(disableCat, scopeCat, disabled()),
|
||||
Arguments.of(disableCat, scopeDog, enabled()),
|
||||
Arguments.of(disableCat, scopeDuck, enabled()),
|
||||
// default enabled, disable pattern
|
||||
Arguments.of(disableStartsWithD, scopeCat, enabled()),
|
||||
Arguments.of(disableStartsWithD, scopeDog, LoggerConfig.disabled()),
|
||||
Arguments.of(disableStartsWithD, scopeDuck, LoggerConfig.disabled()),
|
||||
Arguments.of(disableStartsWithD, scopeDog, disabled()),
|
||||
Arguments.of(disableStartsWithD, scopeDuck, disabled()),
|
||||
// default disabled, enable cat
|
||||
Arguments.of(enableCat, scopeCat, enabled()),
|
||||
Arguments.of(enableCat, scopeDog, LoggerConfig.disabled()),
|
||||
Arguments.of(enableCat, scopeDuck, LoggerConfig.disabled()),
|
||||
Arguments.of(enableCat, scopeDog, disabled()),
|
||||
Arguments.of(enableCat, scopeDuck, disabled()),
|
||||
// default disabled, enable pattern
|
||||
Arguments.of(enableStartsWithD, scopeCat, LoggerConfig.disabled()),
|
||||
Arguments.of(enableStartsWithD, scopeCat, disabled()),
|
||||
Arguments.of(enableStartsWithD, scopeDog, enabled()),
|
||||
Arguments.of(enableStartsWithD, scopeDuck, enabled()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void setScopeConfigurator() {
|
||||
// 1. Initially, configure all loggers to be enabled except loggerB
|
||||
InMemoryLogRecordExporter exporter = InMemoryLogRecordExporter.create();
|
||||
SdkLoggerProvider loggerProvider =
|
||||
SdkLoggerProvider.builder()
|
||||
.addLoggerConfiguratorCondition(nameEquals("loggerB"), disabled())
|
||||
.addLogRecordProcessor(SimpleLogRecordProcessor.create(exporter))
|
||||
.build();
|
||||
|
||||
ExtendedSdkLogger loggerA = (ExtendedSdkLogger) loggerProvider.get("loggerA");
|
||||
ExtendedSdkLogger loggerB = (ExtendedSdkLogger) loggerProvider.get("loggerB");
|
||||
ExtendedSdkLogger loggerC = (ExtendedSdkLogger) loggerProvider.get("loggerC");
|
||||
|
||||
// verify isEnabled()
|
||||
assertThat(loggerA.isEnabled()).isTrue();
|
||||
assertThat(loggerB.isEnabled()).isFalse();
|
||||
assertThat(loggerC.isEnabled()).isTrue();
|
||||
|
||||
// verify logs are emitted as expected
|
||||
loggerA.logRecordBuilder().setBody("logA").emit();
|
||||
loggerB.logRecordBuilder().setBody("logB").emit();
|
||||
loggerC.logRecordBuilder().setBody("logC").emit();
|
||||
assertThat(exporter.getFinishedLogRecordItems())
|
||||
.satisfiesExactlyInAnyOrder(
|
||||
log -> assertThat(log).hasBody("logA"), log -> assertThat(log).hasBody("logC"));
|
||||
exporter.reset();
|
||||
|
||||
// 2. Update config to disable all loggers
|
||||
loggerProvider.setLoggerConfigurator(
|
||||
ScopeConfigurator.<LoggerConfig>builder().setDefault(disabled()).build());
|
||||
|
||||
// verify isEnabled()
|
||||
assertThat(loggerA.isEnabled()).isFalse();
|
||||
assertThat(loggerB.isEnabled()).isFalse();
|
||||
assertThat(loggerC.isEnabled()).isFalse();
|
||||
|
||||
// verify logs are emitted as expected
|
||||
loggerA.logRecordBuilder().setBody("logA").emit();
|
||||
loggerB.logRecordBuilder().setBody("logB").emit();
|
||||
loggerC.logRecordBuilder().setBody("logC").emit();
|
||||
assertThat(exporter.getFinishedLogRecordItems()).isEmpty();
|
||||
|
||||
// 3. Update config to restore original
|
||||
loggerProvider.setLoggerConfigurator(
|
||||
ScopeConfigurator.<LoggerConfig>builder()
|
||||
.addCondition(nameEquals("loggerB"), disabled())
|
||||
.build());
|
||||
|
||||
// verify isEnabled()
|
||||
assertThat(loggerA.isEnabled()).isTrue();
|
||||
assertThat(loggerB.isEnabled()).isFalse();
|
||||
assertThat(loggerC.isEnabled()).isTrue();
|
||||
|
||||
// verify logs are emitted as expected
|
||||
loggerA.logRecordBuilder().setBody("logA").emit();
|
||||
loggerB.logRecordBuilder().setBody("logB").emit();
|
||||
loggerC.logRecordBuilder().setBody("logC").emit();
|
||||
assertThat(exporter.getFinishedLogRecordItems())
|
||||
.satisfiesExactly(
|
||||
log -> assertThat(log).hasBody("logA"), log -> assertThat(log).hasBody("logC"));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue