Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add disable all instrumentations option #471

Merged
merged 2 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,14 @@
*/
public class DynamicInstrumentation {

private static final Logger logger = Logger.getLogger(DynamicInstrumentation.class.getName());
public static final String INSTRUMENTATION_NAME_PREPEND = "io.opentelemetry.";
public static final String ALL_INSTRUMENTATION = "_ALL_";
// note the option can't be an env because no OSes support changing envs while the program runs
public static final String INSTRUMENTATION_DISABLE_OPTION =
"elastic.otel.java.disable_instrumentations";
private static final String ALL_INSTRUMENTATION_FULL_NAME =
INSTRUMENTATION_NAME_PREPEND + ALL_INSTRUMENTATION;
private static final Logger logger = Logger.getLogger(DynamicInstrumentation.class.getName());

private static Object getField(String fieldname, Object target) {
try {
Expand Down Expand Up @@ -186,6 +189,14 @@ public static void disableTracesFor(String instrumentationName) {
updateTracerConfigurations(GlobalOpenTelemetry.getTracerProvider());
}

public static void disableAllTraces() {
disableTracesFor(ALL_INSTRUMENTATION);
}

public static void stopDisablingAllTraces() {
reenableTracesFor(ALL_INSTRUMENTATION);
}

public static class UpdatableConfigurator implements ScopeConfigurator<TracerConfig> {
public static final UpdatableConfigurator INSTANCE = new UpdatableConfigurator();
private final ConcurrentMap<String, TracerConfig> map = new ConcurrentHashMap<>();
Expand All @@ -194,6 +205,11 @@ private UpdatableConfigurator() {}

@Override
public TracerConfig apply(InstrumentationScopeInfo scopeInfo) {
// If key "_ALL_" is set to disabled, then always return disabled
// otherwise fallback to the individual instrumentation
if (!map.getOrDefault(ALL_INSTRUMENTATION_FULL_NAME, TracerConfig.enabled()).isEnabled()) {
return TracerConfig.disabled();
}
return map.getOrDefault(scopeInfo.getName(), TracerConfig.defaultConfig());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import io.opentelemetry.proto.trace.v1.Span;
import java.util.List;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

Expand All @@ -36,7 +37,7 @@ public static void start() {
(container) -> {
container.addEnv(
"OTEL_INSTRUMENTATION_METHODS_INCLUDE",
"co.elastic.otel.test.DynamicInstrumentationController[flipMethods]");
"co.elastic.otel.test.DynamicInstrumentationController[flipMethods,flipAll]");
container.addEnv("ELASTIC_OTEL_JAVA_DISABLE_INSTRUMENTATIONS_CHECKER", "true");
container.addEnv("OTEL_JAVAAGENT_DEBUG", "true");
});
Expand All @@ -47,28 +48,53 @@ public static void end() {
stopApp();
}

@AfterEach
public void endTest() throws InterruptedException {
doRequest(getUrl("/dynamic/reset"), okResponseBody("reset"));
Thread.sleep(2000L); // give the reset time to be applied
}

@Test
public void flipMethodInstrumentation() throws InterruptedException {
doRequest(getUrl("/dynamic"), okResponseBody("enabled"));
dynamicFlipInstrumentation("Methods", 1);
}

@Test
public void flipAllInstrumentation() throws InterruptedException {
dynamicFlipInstrumentation("All", 0);
}

private void dynamicFlipInstrumentation(String extensionName, int SpanCountWhenDisabled)
throws InterruptedException {
doRequest(getUrl("/dynamic/flip" + extensionName), okResponseBody("enabled"));
List<ExportTraceServiceRequest> traces = waitForTraces();
List<Span> spans = getSpans(traces).toList();
assertThat(spans)
.hasSize(2)
.extracting("name")
.containsOnly("GET /dynamic", "DynamicInstrumentationController.flipMethods");
.containsOnly(
"GET /dynamic/flip" + extensionName,
"DynamicInstrumentationController.flip" + extensionName);
ByteString firstTraceID = spans.get(0).getTraceId();

Thread.sleep(2000L); // give the flip time to be applied

doRequest(getUrl("/dynamic"), okResponseBody("disabled"));
doRequest(getUrl("/dynamic/flip" + extensionName), okResponseBody("disabled"));
traces = waitForTraces();
spans = getSpans(traces).dropWhile(span -> span.getTraceId().equals(firstTraceID)).toList();
assertThat(spans).hasSize(1).extracting("name").containsOnly("GET /dynamic");
ByteString secondTraceID = spans.get(0).getTraceId();
if (SpanCountWhenDisabled > 0) {
assertThat(spans)
.hasSize(SpanCountWhenDisabled)
.extracting("name")
.containsOnly("GET /dynamic/flip" + extensionName);
} else {
assertThat(spans).hasSize(0);
}
ByteString secondTraceID = SpanCountWhenDisabled > 0 ? spans.get(0).getTraceId() : firstTraceID;

Thread.sleep(2000L); // give the flip time to be applied

doRequest(getUrl("/dynamic"), okResponseBody("enabled"));
doRequest(getUrl("/dynamic/flip" + extensionName), okResponseBody("enabled"));
traces = waitForTraces();
spans =
getSpans(traces)
Expand All @@ -80,6 +106,8 @@ public void flipMethodInstrumentation() throws InterruptedException {
assertThat(spans)
.hasSize(2)
.extracting("name")
.containsOnly("GET /dynamic", "DynamicInstrumentationController.flipMethods");
.containsOnly(
"GET /dynamic/flip" + extensionName,
"DynamicInstrumentationController.flip" + extensionName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,33 @@ public class DynamicInstrumentationController {
"elastic.otel.java.disable_instrumentations";

// note synchronized to make enable/disable faster with DynamicInstrumentation
@GetMapping
@GetMapping("/flipMethods")
public synchronized String flipMethods() {
String old = System.getProperty(INSTRUMENTATION_DISABLE_OPTION, "");
if (old.isEmpty()) {
System.setProperty(INSTRUMENTATION_DISABLE_OPTION, "methods");
return "enabled";
} else {
System.setProperty(INSTRUMENTATION_DISABLE_OPTION, "");
return "disabled";
}
return old.isEmpty() ? "enabled" : "disabled";
}

@RequestMapping("/flipAll")
public synchronized String flipAll() {
String old = System.getProperty(INSTRUMENTATION_DISABLE_OPTION, "");
if (old.isEmpty()) {
System.setProperty(INSTRUMENTATION_DISABLE_OPTION, "_ALL_");
return "enabled";
} else {
System.setProperty(INSTRUMENTATION_DISABLE_OPTION, "");
return "disabled";
}
}

@RequestMapping("/reset")
public synchronized String reset() {
System.setProperty(INSTRUMENTATION_DISABLE_OPTION, "");
return "reset";
}
}
Loading