Skip to content

Commit 983133f

Browse files
authored
Add setLoggerConfigurator support to LoggerProvider (#7332)
1 parent 58acb53 commit 983133f

File tree

7 files changed

+171
-21
lines changed

7 files changed

+171
-21
lines changed

sdk/logs/src/main/java/io/opentelemetry/sdk/logs/ExtendedSdkLogger.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,17 @@
1313
/** SDK implementation of {@link ExtendedLogger}. */
1414
final class ExtendedSdkLogger extends SdkLogger implements ExtendedLogger {
1515

16-
private final boolean loggerEnabled;
17-
1816
ExtendedSdkLogger(
1917
LoggerSharedState loggerSharedState,
2018
InstrumentationScopeInfo instrumentationScopeInfo,
2119
LoggerConfig loggerConfig) {
2220
super(loggerSharedState, instrumentationScopeInfo, loggerConfig);
23-
this.loggerEnabled = loggerConfig.isEnabled();
2421
}
2522

2623
@Override
24+
@SuppressWarnings("RedundantOverride")
2725
public boolean isEnabled() {
28-
return loggerEnabled;
26+
return super.isEnabled();
2927
}
3028

3129
@Override

sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogger.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ class SdkLogger implements Logger {
3030

3131
private final LoggerSharedState loggerSharedState;
3232
private final InstrumentationScopeInfo instrumentationScopeInfo;
33-
private final boolean loggerEnabled;
33+
34+
// deliberately not volatile because of performance concerns
35+
// - which means its eventually consistent
36+
protected boolean loggerEnabled;
3437

3538
SdkLogger(
3639
LoggerSharedState loggerSharedState,
@@ -65,4 +68,12 @@ public LogRecordBuilder logRecordBuilder() {
6568
InstrumentationScopeInfo getInstrumentationScopeInfo() {
6669
return instrumentationScopeInfo;
6770
}
71+
72+
public boolean isEnabled() {
73+
return loggerEnabled;
74+
}
75+
76+
void updateLoggerConfig(LoggerConfig loggerConfig) {
77+
loggerEnabled = loggerConfig.isEnabled();
78+
}
6879
}

sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLoggerProvider.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,12 @@ public final class SdkLoggerProvider implements LoggerProvider, Closeable {
3636

3737
private final LoggerSharedState sharedState;
3838
private final ComponentRegistry<SdkLogger> loggerComponentRegistry;
39-
private final ScopeConfigurator<LoggerConfig> loggerConfigurator;
4039
private final boolean isNoopLogRecordProcessor;
4140

41+
// deliberately not volatile because of performance concerns
42+
// - which means its eventually consistent
43+
private ScopeConfigurator<LoggerConfig> loggerConfigurator;
44+
4245
/**
4346
* Returns a new {@link SdkLoggerProviderBuilder} for {@link SdkLoggerProvider}.
4447
*
@@ -96,6 +99,26 @@ private static String instrumentationNameOrDefault(@Nullable String instrumentat
9699
return instrumentationScopeName;
97100
}
98101

102+
/**
103+
* Updates the logger configurator, which computes {@link LoggerConfig} for each {@link
104+
* InstrumentationScopeInfo}.
105+
*
106+
* <p>This method is experimental so not public. You may reflectively call it using {@link
107+
* io.opentelemetry.sdk.logs.internal.SdkLoggerProviderUtil#setLoggerConfigurator(SdkLoggerProvider,
108+
* ScopeConfigurator)}.
109+
*
110+
* @see LoggerConfig#configuratorBuilder()
111+
*/
112+
void setLoggerConfigurator(ScopeConfigurator<LoggerConfig> loggerConfigurator) {
113+
this.loggerConfigurator = loggerConfigurator;
114+
this.loggerComponentRegistry
115+
.getComponents()
116+
.forEach(
117+
sdkLogger ->
118+
sdkLogger.updateLoggerConfig(
119+
getLoggerConfig(sdkLogger.getInstrumentationScopeInfo())));
120+
}
121+
99122
/**
100123
* Request the active log processor to process all logs that have not yet been processed.
101124
*

sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/SdkLoggerProviderUtil.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
99
import io.opentelemetry.sdk.internal.ScopeConfigurator;
10+
import io.opentelemetry.sdk.logs.SdkLoggerProvider;
1011
import io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder;
1112
import java.lang.reflect.InvocationTargetException;
1213
import java.lang.reflect.Method;
@@ -23,6 +24,21 @@ public final class SdkLoggerProviderUtil {
2324

2425
private SdkLoggerProviderUtil() {}
2526

27+
/** Reflectively set the {@link ScopeConfigurator} to the {@link SdkLoggerProvider}. */
28+
public static void setLoggerConfigurator(
29+
SdkLoggerProvider sdkLoggerProvider, ScopeConfigurator<LoggerConfig> scopeConfigurator) {
30+
try {
31+
Method method =
32+
SdkLoggerProvider.class.getDeclaredMethod(
33+
"setLoggerConfigurator", ScopeConfigurator.class);
34+
method.setAccessible(true);
35+
method.invoke(sdkLoggerProvider, scopeConfigurator);
36+
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
37+
throw new IllegalStateException(
38+
"Error calling setLoggerConfigurator on SdkLoggerProvider", e);
39+
}
40+
}
41+
2642
/** Reflectively set the {@link ScopeConfigurator} to the {@link SdkLoggerProviderBuilder}. */
2743
public static SdkLoggerProviderBuilder setLoggerConfigurator(
2844
SdkLoggerProviderBuilder sdkLoggerProviderBuilder,

sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerProviderTest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@
2828
import io.opentelemetry.sdk.common.Clock;
2929
import io.opentelemetry.sdk.common.CompletableResultCode;
3030
import io.opentelemetry.sdk.common.InstrumentationScopeInfo;
31+
import io.opentelemetry.sdk.internal.ScopeConfigurator;
3132
import io.opentelemetry.sdk.logs.data.LogRecordData;
33+
import io.opentelemetry.sdk.logs.internal.LoggerConfig;
34+
import io.opentelemetry.sdk.logs.internal.SdkLoggerProviderUtil;
3235
import io.opentelemetry.sdk.resources.Resource;
3336
import java.util.Optional;
3437
import java.util.concurrent.TimeUnit;
@@ -350,4 +353,28 @@ void toString_Valid() {
350353
+ "loggerConfigurator=ScopeConfiguratorImpl{conditions=[]}"
351354
+ "}");
352355
}
356+
357+
private static ScopeConfigurator<LoggerConfig> flipConfigurator(boolean enabled) {
358+
return scopeInfo -> enabled ? LoggerConfig.disabled() : LoggerConfig.enabled();
359+
}
360+
361+
@Test
362+
void propagatesEnablementToLoggerDirectly() {
363+
SdkLogger logger = (SdkLogger) sdkLoggerProvider.get("test");
364+
boolean isEnabled = logger.isEnabled();
365+
366+
sdkLoggerProvider.setLoggerConfigurator(flipConfigurator(isEnabled));
367+
368+
assertThat(logger.isEnabled()).isEqualTo(!isEnabled);
369+
}
370+
371+
@Test
372+
void propagatesEnablementToLoggerByUtil() {
373+
SdkLogger logger = (SdkLogger) sdkLoggerProvider.get("test");
374+
boolean isEnabled = logger.isEnabled();
375+
376+
SdkLoggerProviderUtil.setLoggerConfigurator(sdkLoggerProvider, flipConfigurator(isEnabled));
377+
378+
assertThat(logger.isEnabled()).isEqualTo(!isEnabled);
379+
}
353380
}

sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLoggerTest.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,4 +133,17 @@ void logRecordBuilder_AfterShutdown() {
133133

134134
verify(logRecordProcessor, never()).onEmit(any(), any());
135135
}
136+
137+
@Test
138+
void updateEnabled() {
139+
LogRecordProcessor logRecordProcessor = mock(LogRecordProcessor.class);
140+
SdkLoggerProvider loggerProvider =
141+
SdkLoggerProvider.builder().addLogRecordProcessor(logRecordProcessor).build();
142+
SdkLogger logger = (SdkLogger) loggerProvider.get("test");
143+
144+
logger.updateLoggerConfig(LoggerConfig.disabled());
145+
assertThat(logger.isEnabled()).isFalse();
146+
logger.updateLoggerConfig(LoggerConfig.enabled());
147+
assertThat(logger.isEnabled()).isTrue();
148+
}
136149
}

sdk/logs/src/testIncubating/java/io/opentelemetry/sdk/logs/LoggerConfigTest.java

Lines changed: 77 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import static io.opentelemetry.sdk.internal.ScopeConfiguratorBuilder.nameEquals;
99
import static io.opentelemetry.sdk.internal.ScopeConfiguratorBuilder.nameMatchesGlob;
1010
import static io.opentelemetry.sdk.logs.internal.LoggerConfig.defaultConfig;
11+
import static io.opentelemetry.sdk.logs.internal.LoggerConfig.disabled;
1112
import static io.opentelemetry.sdk.logs.internal.LoggerConfig.enabled;
1213
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
1314

@@ -37,7 +38,7 @@ void disableScopes() {
3738
SdkLoggerProvider.builder()
3839
// Disable loggerB. Since loggers are enabled by default, loggerA and loggerC are
3940
// enabled.
40-
.addLoggerConfiguratorCondition(nameEquals("loggerB"), LoggerConfig.disabled())
41+
.addLoggerConfiguratorCondition(nameEquals("loggerB"), disabled())
4142
.addLogRecordProcessor(SimpleLogRecordProcessor.create(exporter))
4243
.build();
4344

@@ -86,25 +87,23 @@ private static Stream<Arguments> loggerConfiguratorArgs() {
8687
LoggerConfig.configuratorBuilder().build();
8788
ScopeConfigurator<LoggerConfig> disableCat =
8889
LoggerConfig.configuratorBuilder()
89-
.addCondition(nameEquals("cat"), LoggerConfig.disabled())
90+
.addCondition(nameEquals("cat"), disabled())
9091
// Second matching rule for cat should be ignored
9192
.addCondition(nameEquals("cat"), enabled())
9293
.build();
9394
ScopeConfigurator<LoggerConfig> disableStartsWithD =
94-
LoggerConfig.configuratorBuilder()
95-
.addCondition(nameMatchesGlob("d*"), LoggerConfig.disabled())
96-
.build();
95+
LoggerConfig.configuratorBuilder().addCondition(nameMatchesGlob("d*"), disabled()).build();
9796
ScopeConfigurator<LoggerConfig> enableCat =
9897
LoggerConfig.configuratorBuilder()
99-
.setDefault(LoggerConfig.disabled())
98+
.setDefault(disabled())
10099
.addCondition(nameEquals("cat"), enabled())
101100
// Second matching rule for cat should be ignored
102-
.addCondition(nameEquals("cat"), LoggerConfig.disabled())
101+
.addCondition(nameEquals("cat"), disabled())
103102
.build();
104103
ScopeConfigurator<LoggerConfig> enableStartsWithD =
105104
LoggerConfig.configuratorBuilder()
106-
.setDefault(LoggerConfig.disabled())
107-
.addCondition(nameMatchesGlob("d*"), LoggerConfig.enabled())
105+
.setDefault(disabled())
106+
.addCondition(nameMatchesGlob("d*"), enabled())
108107
.build();
109108

110109
return Stream.of(
@@ -113,20 +112,83 @@ private static Stream<Arguments> loggerConfiguratorArgs() {
113112
Arguments.of(defaultConfigurator, scopeDog, defaultConfig()),
114113
Arguments.of(defaultConfigurator, scopeDuck, defaultConfig()),
115114
// default enabled, disable cat
116-
Arguments.of(disableCat, scopeCat, LoggerConfig.disabled()),
115+
Arguments.of(disableCat, scopeCat, disabled()),
117116
Arguments.of(disableCat, scopeDog, enabled()),
118117
Arguments.of(disableCat, scopeDuck, enabled()),
119118
// default enabled, disable pattern
120119
Arguments.of(disableStartsWithD, scopeCat, enabled()),
121-
Arguments.of(disableStartsWithD, scopeDog, LoggerConfig.disabled()),
122-
Arguments.of(disableStartsWithD, scopeDuck, LoggerConfig.disabled()),
120+
Arguments.of(disableStartsWithD, scopeDog, disabled()),
121+
Arguments.of(disableStartsWithD, scopeDuck, disabled()),
123122
// default disabled, enable cat
124123
Arguments.of(enableCat, scopeCat, enabled()),
125-
Arguments.of(enableCat, scopeDog, LoggerConfig.disabled()),
126-
Arguments.of(enableCat, scopeDuck, LoggerConfig.disabled()),
124+
Arguments.of(enableCat, scopeDog, disabled()),
125+
Arguments.of(enableCat, scopeDuck, disabled()),
127126
// default disabled, enable pattern
128-
Arguments.of(enableStartsWithD, scopeCat, LoggerConfig.disabled()),
127+
Arguments.of(enableStartsWithD, scopeCat, disabled()),
129128
Arguments.of(enableStartsWithD, scopeDog, enabled()),
130129
Arguments.of(enableStartsWithD, scopeDuck, enabled()));
131130
}
131+
132+
@Test
133+
void setScopeConfigurator() {
134+
// 1. Initially, configure all loggers to be enabled except loggerB
135+
InMemoryLogRecordExporter exporter = InMemoryLogRecordExporter.create();
136+
SdkLoggerProvider loggerProvider =
137+
SdkLoggerProvider.builder()
138+
.addLoggerConfiguratorCondition(nameEquals("loggerB"), disabled())
139+
.addLogRecordProcessor(SimpleLogRecordProcessor.create(exporter))
140+
.build();
141+
142+
ExtendedSdkLogger loggerA = (ExtendedSdkLogger) loggerProvider.get("loggerA");
143+
ExtendedSdkLogger loggerB = (ExtendedSdkLogger) loggerProvider.get("loggerB");
144+
ExtendedSdkLogger loggerC = (ExtendedSdkLogger) loggerProvider.get("loggerC");
145+
146+
// verify isEnabled()
147+
assertThat(loggerA.isEnabled()).isTrue();
148+
assertThat(loggerB.isEnabled()).isFalse();
149+
assertThat(loggerC.isEnabled()).isTrue();
150+
151+
// verify logs are emitted as expected
152+
loggerA.logRecordBuilder().setBody("logA").emit();
153+
loggerB.logRecordBuilder().setBody("logB").emit();
154+
loggerC.logRecordBuilder().setBody("logC").emit();
155+
assertThat(exporter.getFinishedLogRecordItems())
156+
.satisfiesExactlyInAnyOrder(
157+
log -> assertThat(log).hasBody("logA"), log -> assertThat(log).hasBody("logC"));
158+
exporter.reset();
159+
160+
// 2. Update config to disable all loggers
161+
loggerProvider.setLoggerConfigurator(
162+
ScopeConfigurator.<LoggerConfig>builder().setDefault(disabled()).build());
163+
164+
// verify isEnabled()
165+
assertThat(loggerA.isEnabled()).isFalse();
166+
assertThat(loggerB.isEnabled()).isFalse();
167+
assertThat(loggerC.isEnabled()).isFalse();
168+
169+
// verify logs are emitted as expected
170+
loggerA.logRecordBuilder().setBody("logA").emit();
171+
loggerB.logRecordBuilder().setBody("logB").emit();
172+
loggerC.logRecordBuilder().setBody("logC").emit();
173+
assertThat(exporter.getFinishedLogRecordItems()).isEmpty();
174+
175+
// 3. Update config to restore original
176+
loggerProvider.setLoggerConfigurator(
177+
ScopeConfigurator.<LoggerConfig>builder()
178+
.addCondition(nameEquals("loggerB"), disabled())
179+
.build());
180+
181+
// verify isEnabled()
182+
assertThat(loggerA.isEnabled()).isTrue();
183+
assertThat(loggerB.isEnabled()).isFalse();
184+
assertThat(loggerC.isEnabled()).isTrue();
185+
186+
// verify logs are emitted as expected
187+
loggerA.logRecordBuilder().setBody("logA").emit();
188+
loggerB.logRecordBuilder().setBody("logB").emit();
189+
loggerC.logRecordBuilder().setBody("logC").emit();
190+
assertThat(exporter.getFinishedLogRecordItems())
191+
.satisfiesExactly(
192+
log -> assertThat(log).hasBody("logA"), log -> assertThat(log).hasBody("logC"));
193+
}
132194
}

0 commit comments

Comments
 (0)