Skip to content

Commit 80e15ee

Browse files
committed
implement spans debug logging
1 parent c52479c commit 80e15ee

File tree

4 files changed

+80
-4
lines changed

4 files changed

+80
-4
lines changed

custom/src/main/java/co/elastic/otel/ElasticAutoConfigurationCustomizerProvider.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import co.elastic.otel.dynamicconfig.BlockableMetricExporter;
2323
import co.elastic.otel.dynamicconfig.BlockableSpanExporter;
2424
import co.elastic.otel.dynamicconfig.CentralConfig;
25+
import co.elastic.otel.logging.AgentLog;
2526
import com.google.auto.service.AutoService;
2627
import io.opentelemetry.api.common.AttributeKey;
2728
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer;
@@ -72,6 +73,7 @@ public void customize(AutoConfigurationCustomizer autoConfiguration) {
7273
autoConfiguration.addTracerProviderCustomizer(
7374
(providerBuilder, properties) -> {
7475
CentralConfig.init(providerBuilder, properties);
76+
AgentLog.addSpanLoggingIfRequired(providerBuilder, properties);
7577
return providerBuilder;
7678
});
7779
}

internal-logging/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ dependencies {
1010

1111
compileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-tooling")
1212
compileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-bootstrap")
13+
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi")
14+
implementation("io.opentelemetry:opentelemetry-exporter-logging")
1315
compileOnly(libs.slf4j.api)
1416
implementation(libs.bundles.log4j2) {
1517
// Workaround for https://github.com/apache/logging-log4j2/issues/3754

internal-logging/src/main/java/co/elastic/otel/logging/AgentLog.java

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,17 @@
1818
*/
1919
package co.elastic.otel.logging;
2020

21+
import static java.util.Collections.emptyList;
22+
23+
import io.opentelemetry.exporter.logging.LoggingSpanExporter;
24+
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
25+
import io.opentelemetry.sdk.common.CompletableResultCode;
26+
import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;
27+
import io.opentelemetry.sdk.trace.data.SpanData;
28+
import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
29+
import io.opentelemetry.sdk.trace.export.SpanExporter;
30+
import java.util.Collection;
31+
import java.util.concurrent.atomic.AtomicBoolean;
2132
import org.apache.logging.log4j.Level;
2233
import org.apache.logging.log4j.core.config.Configurator;
2334
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
@@ -26,11 +37,21 @@
2637

2738
public class AgentLog {
2839

40+
/** Upstream instrumentation debug boolean option */
41+
public static final String OTEL_JAVAAGENT_DEBUG = "otel.javaagent.debug";
42+
2943
private static final String PATTERN = "%d{DEFAULT} [%t] %-5level %logger{36} - %msg{nolookups}%n";
3044

31-
// logger is an empty string
45+
/** root logger is an empty string */
3246
private static final String ROOT_LOGGER_NAME = "";
3347

48+
/**
49+
* debug span logging exporter that can be controlled at runtime, only used when logging span
50+
* exporter has not been explicitly configured.
51+
*/
52+
private static final DebugLogSpanExporter debugLogSpanExporter =
53+
new DebugLogSpanExporter(LoggingSpanExporter.create());
54+
3455
private AgentLog() {}
3556

3657
public static void init() {
@@ -47,6 +68,22 @@ public static void init() {
4768
Configurator.initialize(conf.build(false));
4869
}
4970

71+
public static void addSpanLoggingIfRequired(
72+
SdkTracerProviderBuilder providerBuilder, ConfigProperties config) {
73+
74+
boolean otelDebug = config.getBoolean(OTEL_JAVAAGENT_DEBUG, false);
75+
76+
// Replicate behavior of upstream agent: span logging exporter is automatically added
77+
// when not already present when debugging.
78+
// When logging exporter has been explicitly configured, spans logging will be done by the
79+
// explicitly configured logging exporter instance
80+
boolean loggingExporterNotAlreadyConfigured =
81+
!config.getList("otel.traces.exporter", emptyList()).contains("logging");
82+
if (otelDebug && loggingExporterNotAlreadyConfigured) {
83+
providerBuilder.addSpanProcessor(SimpleSpanProcessor.create(debugLogSpanExporter));
84+
}
85+
}
86+
5087
public static void setLevel(String level) {
5188
switch (level) {
5289
case "trace":
@@ -87,11 +124,46 @@ public static void setLevel(Level level) {
87124

88125
Configurator.setAllLevels(ROOT_LOGGER_NAME, level);
89126

90-
// when debugging we should avoid very chatty http client debug messages
127+
boolean isDebug = level.intLevel() >= Level.DEBUG.intLevel();
128+
129+
// When debugging, we should avoid very chatty http client debug messages
91130
// this behavior is replicated from the upstream distribution.
92-
if (level.intLevel() >= Level.DEBUG.intLevel()) {
131+
if (isDebug) {
93132
Configurator.setLevel("okhttp3.internal.http2", Level.INFO);
94133
Configurator.setLevel("okhttp3.internal.concurrent.TaskRunner", Level.INFO);
95134
}
135+
136+
// when debugging the upstream otel agent configures an extra debug exporter
137+
debugLogSpanExporter.setEnabled(isDebug);
138+
}
139+
140+
private static class DebugLogSpanExporter implements SpanExporter {
141+
142+
private final SpanExporter delegate;
143+
private final AtomicBoolean enabled;
144+
145+
DebugLogSpanExporter(SpanExporter delegate) {
146+
this.delegate = delegate;
147+
this.enabled = new AtomicBoolean(false);
148+
}
149+
150+
void setEnabled(boolean value) {
151+
enabled.set(value);
152+
}
153+
154+
@Override
155+
public CompletableResultCode export(Collection<SpanData> spans) {
156+
return enabled.get() ? delegate.export(spans) : CompletableResultCode.ofSuccess();
157+
}
158+
159+
@Override
160+
public CompletableResultCode flush() {
161+
return enabled.get() ? delegate.flush() : CompletableResultCode.ofSuccess();
162+
}
163+
164+
@Override
165+
public CompletableResultCode shutdown() {
166+
return enabled.get() ? delegate.shutdown() : CompletableResultCode.ofSuccess();
167+
}
96168
}
97169
}

internal-logging/src/main/java/co/elastic/otel/logging/ElasticLoggingCustomizer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public void init(EarlyInitAgentConfig earlyConfig) {
4646
AgentLog.init();
4747

4848
Level level = null;
49-
if (earlyConfig.getBoolean("otel.javaagent.debug", false)) {
49+
if (earlyConfig.getBoolean(AgentLog.OTEL_JAVAAGENT_DEBUG, false)) {
5050
// set debug logging when enabled through configuration to behave like the upstream
5151
// distribution
5252
level = Level.DEBUG;

0 commit comments

Comments
 (0)