diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/configuration/Configuration.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/configuration/Configuration.java index 3fbdfedc7f1..5e9819d6f58 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/configuration/Configuration.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/configuration/Configuration.java @@ -317,6 +317,8 @@ public static class PreviewConfiguration { // "% Processor Time Normalized" public boolean useNormalizedValueForNonNormalizedCpuPercentage = true; + public List customInstrumentation = new ArrayList<>(); + private static final Set VALID_ADDITIONAL_PROPAGATORS = new HashSet<>(asList("b3", "b3multi")); @@ -493,6 +495,11 @@ public void validate() { } } + public static class CustomInstrumentation { + public String className; + public String methodName; + } + public static class EnabledByDefaultInstrumentation { public boolean enabled = true; } diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/AiConfigCustomizer.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/AiConfigCustomizer.java index dcf3019cc67..2a218567a4f 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/AiConfigCustomizer.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/AiConfigCustomizer.java @@ -91,6 +91,22 @@ public Map defaultProperties() { // enable log4j 1.x MDC properties.put("otel.instrumentation.log4j-appender.experimental.capture-mdc-attributes", "*"); + // custom instrumentation + if (!config.preview.customInstrumentation.isEmpty()) { + StringBuilder sb = new StringBuilder(); + for (Configuration.CustomInstrumentation customInstrumentation : + config.preview.customInstrumentation) { + if (sb.length() > 0) { + sb.append(';'); + } + sb.append(customInstrumentation.className); + sb.append('['); + sb.append(customInstrumentation.methodName); + sb.append(']'); + } + properties.put("otel.instrumentation.methods.include", sb.toString()); + } + properties.put("otel.propagators", DelegatingPropagatorProvider.NAME); properties.put("otel.traces.sampler", DelegatingSamplerProvider.NAME); @@ -143,11 +159,6 @@ private static void enableInstrumentations(Configuration config, Map rdList = testing.mockedIngestion.waitForItems("RequestData", 2); + + Envelope rdEnvelope1 = getRequestEnvelope(rdList, "GET /test"); + Envelope rdEnvelope2 = getRequestEnvelope(rdList, "TestController.run"); + + RequestData rd1 = (RequestData) ((Data) rdEnvelope1.getData()).getBaseData(); + + assertThat(rd1.getName()).isEqualTo("GET /test"); + assertThat(rd1.getResponseCode()).isEqualTo("200"); + assertThat(rd1.getProperties()).isEmpty(); + assertThat(rd1.getSuccess()).isTrue(); + + RequestData rd2 = (RequestData) ((Data) rdEnvelope2.getData()).getBaseData(); + + assertThat(rd2.getName()).isEqualTo("TestController.run"); + assertThat(rd2.getResponseCode()).isEqualTo("0"); + assertThat(rd2.getProperties()).isEmpty(); + assertThat(rd2.getSuccess()).isTrue(); + + String operationId = rdEnvelope2.getTags().get("ai.operation.id"); + List mdList = testing.mockedIngestion.waitForMessageItemsInRequest(1, operationId); + + Envelope mdEnvelope = mdList.get(0); + MessageData md = (MessageData) ((Data) mdEnvelope.getData()).getBaseData(); + + assertThat(md.getMessage()).isEqualTo("hello"); + assertThat(md.getSeverityLevel()).isEqualTo(SeverityLevel.INFORMATION); + assertThat(md.getProperties()).containsEntry("SourceType", "Logger"); + assertThat(md.getProperties()).containsEntry("LoggerName", "smoketestapp"); + assertThat(md.getProperties()).containsKey("ThreadName"); + assertThat(md.getProperties()).hasSize(3); + } + + private static Envelope getRequestEnvelope(List envelopes, String name) { + for (Envelope envelope : envelopes) { + RequestData rd = (RequestData) ((Data) envelope.getData()).getBaseData(); + if (rd.getName().equals(name)) { + return envelope; + } + } + throw new IllegalStateException("Could not find request with name: " + name); + } + + @Environment(JAVA_8) + static class Java8Test extends CustomInstrumentationTest {} + + @Environment(JAVA_11) + static class Java11Test extends CustomInstrumentationTest {} + + @Environment(JAVA_17) + static class Java17Test extends CustomInstrumentationTest {} +} diff --git a/smoke-tests/apps/CustomInstrumentation/src/smokeTest/resources/applicationinsights.json b/smoke-tests/apps/CustomInstrumentation/src/smokeTest/resources/applicationinsights.json new file mode 100644 index 00000000000..8ac2a331504 --- /dev/null +++ b/smoke-tests/apps/CustomInstrumentation/src/smokeTest/resources/applicationinsights.json @@ -0,0 +1,10 @@ +{ + "preview": { + "customInstrumentation": [ + { + "className": "com.microsoft.applicationinsights.smoketestapp.TestController", + "methodName": "run" + } + ] + } +} diff --git a/smoke-tests/apps/CustomInstrumentation/src/smokeTest/resources/logback-test.xml b/smoke-tests/apps/CustomInstrumentation/src/smokeTest/resources/logback-test.xml new file mode 100644 index 00000000000..0cbbecd57ce --- /dev/null +++ b/smoke-tests/apps/CustomInstrumentation/src/smokeTest/resources/logback-test.xml @@ -0,0 +1,11 @@ + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger{36} - %msg%n + + + + + +