diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/exporter/AgentMetricExporter.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/exporter/AgentMetricExporter.java index 5c496c1e38..5233005da0 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/exporter/AgentMetricExporter.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/exporter/AgentMetricExporter.java @@ -7,6 +7,8 @@ import com.azure.monitor.opentelemetry.exporter.implementation.MetricDataMapper; import com.azure.monitor.opentelemetry.exporter.implementation.logging.OperationLogger; +import com.azure.monitor.opentelemetry.exporter.implementation.models.MetricsData; +import com.azure.monitor.opentelemetry.exporter.implementation.models.MonitorDomain; import com.azure.monitor.opentelemetry.exporter.implementation.models.TelemetryItem; import com.azure.monitor.opentelemetry.exporter.implementation.utils.Strings; import com.microsoft.applicationinsights.agent.internal.telemetry.BatchItemProcessor; @@ -22,6 +24,8 @@ import java.util.Collection; import java.util.List; import java.util.function.Consumer; +import java.util.stream.Collectors; +import javax.annotation.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,14 +38,17 @@ public class AgentMetricExporter implements MetricExporter { private final List metricFilters; private final MetricDataMapper mapper; + @Nullable private final String micrometerMetricNamespace; private final Consumer telemetryItemConsumer; public AgentMetricExporter( List metricFilters, MetricDataMapper mapper, - BatchItemProcessor batchItemProcessor) { + BatchItemProcessor batchItemProcessor, + @Nullable String micrometerMetricNamespace) { this.metricFilters = metricFilters; this.mapper = mapper; + this.micrometerMetricNamespace = micrometerMetricNamespace; this.telemetryItemConsumer = telemetryItem -> { TelemetryObservers.INSTANCE @@ -58,13 +65,43 @@ public CompletableResultCode export(Collection metrics) { logger.debug("exporter is not active"); return CompletableResultCode.ofSuccess(); } - for (MetricData metricData : metrics) { + List backCompatMetrics = + metrics.stream() + .map( + metricData -> { + if (metricData + .getInstrumentationScopeInfo() + .getName() + .equals("io.opentelemetry.micrometer-1.5")) { + return new BackCompatMetricData(metricData); + } + return metricData; + }) + .collect(Collectors.toList()); + + for (MetricData metricData : backCompatMetrics) { if (MetricFilter.shouldSkip(metricData.getName(), metricFilters)) { continue; } logger.debug("exporting metric: {}", metricData); try { - mapper.map(metricData, telemetryItemConsumer); + mapper.map( + metricData, + telemetryItem -> { + if (micrometerMetricNamespace != null + && metricData + .getInstrumentationScopeInfo() + .getName() + .equals("io.opentelemetry.micrometer-1.5")) { + MonitorDomain baseData = telemetryItem.getData().getBaseData(); + if (baseData instanceof MetricsData) { + ((MetricsData) baseData) + .getMetrics() + .forEach(md -> md.setNamespace(micrometerMetricNamespace)); + } + } + telemetryItemConsumer.accept(telemetryItem); + }); exportingMetricLogger.recordSuccess(); } catch (Throwable t) { exportingMetricLogger.recordFailure(t.getMessage(), t, EXPORTER_MAPPING_ERROR); diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/exporter/BackCompatMetricData.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/exporter/BackCompatMetricData.java new file mode 100644 index 0000000000..eeba10af0e --- /dev/null +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/exporter/BackCompatMetricData.java @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.applicationinsights.agent.internal.exporter; + +import io.opentelemetry.sdk.common.InstrumentationScopeInfo; +import io.opentelemetry.sdk.metrics.data.Data; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.data.MetricDataType; +import io.opentelemetry.sdk.resources.Resource; +import java.util.Arrays; +import java.util.Objects; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +class BackCompatMetricData implements MetricData { + + private static final Pattern NAME_AND_TAG_KEY_PATTERN = Pattern.compile("[^a-zA-Z0-9\\-]"); + + private final MetricData delegate; + private final String name; + + BackCompatMetricData(MetricData delegate) { + this.delegate = delegate; + this.name = backCompatName(delegate.getName()); + } + + private static String backCompatName(String name) { + return NAME_AND_TAG_KEY_PATTERN.matcher(toSnakeCase(name)).replaceAll("_"); + } + + private static String toSnakeCase(String value) { + // same logic as micrometer's NamingConvention.snakeCase + return Arrays.stream(value.split("\\.")) + .filter(Objects::nonNull) + .collect(Collectors.joining("_")); + } + + @Override + public Resource getResource() { + return delegate.getResource(); + } + + @Override + public InstrumentationScopeInfo getInstrumentationScopeInfo() { + return delegate.getInstrumentationScopeInfo(); + } + + @Override + public String getName() { + return name; + } + + @Override + public String getDescription() { + return delegate.getDescription(); + } + + @Override + public String getUnit() { + return delegate.getUnit(); + } + + @Override + public MetricDataType getType() { + return delegate.getType(); + } + + @Override + public Data getData() { + return delegate.getData(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } +} 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 fe862e8ac3..b386e7b7bd 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 @@ -209,11 +209,13 @@ private static void enableInstrumentations( properties.put("otel.instrumentation.undertow.enabled", "true"); if (config.instrumentation.micrometer.enabled) { - // TODO (heya) replace with below when updating to upstream micrometer + // upstream micrometer instrumentation only supports micrometer 1.5 and later + // so ai micrometer instrumentation is (still) used for micrometer versions prior to 1.5 properties.put("otel.instrumentation.ai-micrometer.enabled", "true"); properties.put("otel.instrumentation.ai-actuator-metrics.enabled", "true"); - // properties.put("otel.instrumentation.micrometer.enabled", "true"); - // properties.put("otel.instrumentation.spring-boot-actuator-autoconfigure.enabled", "true"); + // upstream micrometer instrumentation is used for micrometer versions 1.5+ + properties.put("otel.instrumentation.micrometer.enabled", "true"); + properties.put("otel.instrumentation.spring-boot-actuator-autoconfigure.enabled", "true"); } String namespace = config.instrumentation.micrometer.namespace; if (namespace != null) { diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/SecondEntryPoint.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/SecondEntryPoint.java index de1c794962..90026ee6cb 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/SecondEntryPoint.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/SecondEntryPoint.java @@ -326,7 +326,7 @@ private static MetricExporter buildMetricExporter( new MetricDataMapper( telemetryClient::populateDefaults, configuration.preview.captureHttpServer4xxAsError); return new AgentMetricExporter( - metricFilters, mapper, telemetryClient.getMetricsBatchItemProcessor()); + metricFilters, mapper, telemetryClient.getMetricsBatchItemProcessor(), configuration.instrumentation.micrometer.namespace); } private static LogRecordExporter buildLogRecordExporter( diff --git a/agent/instrumentation/micrometer-1.0/src/main/java/io/opentelemetry/javaagent/instrumentation/micrometer/ai/ActuatorInstrumentationModule.java b/agent/instrumentation/micrometer-1.0/src/main/java/io/opentelemetry/javaagent/instrumentation/micrometer/ai/ActuatorInstrumentationModule.java index 5a3bad3491..53a5fa4117 100644 --- a/agent/instrumentation/micrometer-1.0/src/main/java/io/opentelemetry/javaagent/instrumentation/micrometer/ai/ActuatorInstrumentationModule.java +++ b/agent/instrumentation/micrometer-1.0/src/main/java/io/opentelemetry/javaagent/instrumentation/micrometer/ai/ActuatorInstrumentationModule.java @@ -5,6 +5,7 @@ import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; import static java.util.Collections.singletonList; +import static net.bytebuddy.matcher.ElementMatchers.not; import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.instrumentation.HelperResourceBuilder; @@ -24,7 +25,10 @@ public ActuatorInstrumentationModule() { @Override public ElementMatcher.Junction classLoaderMatcher() { - return hasClassesNamed("io.micrometer.core.instrument.Metrics"); + return hasClassesNamed("io.micrometer.core.instrument.Metrics") + .and( + // added in micrometer 1.5 + not(hasClassesNamed("io.micrometer.core.instrument.config.validate.Validated"))); } @Override diff --git a/agent/instrumentation/micrometer-1.0/src/main/java/io/opentelemetry/javaagent/instrumentation/micrometer/ai/MicrometerInstrumentationModule.java b/agent/instrumentation/micrometer-1.0/src/main/java/io/opentelemetry/javaagent/instrumentation/micrometer/ai/MicrometerInstrumentationModule.java index 69410f2425..5f07b47e1d 100644 --- a/agent/instrumentation/micrometer-1.0/src/main/java/io/opentelemetry/javaagent/instrumentation/micrometer/ai/MicrometerInstrumentationModule.java +++ b/agent/instrumentation/micrometer-1.0/src/main/java/io/opentelemetry/javaagent/instrumentation/micrometer/ai/MicrometerInstrumentationModule.java @@ -3,20 +3,31 @@ package io.opentelemetry.javaagent.instrumentation.micrometer.ai; +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; +import static net.bytebuddy.matcher.ElementMatchers.not; + import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import java.util.Arrays; import java.util.List; +import net.bytebuddy.matcher.ElementMatcher; @AutoService(InstrumentationModule.class) public class MicrometerInstrumentationModule extends InstrumentationModule { - // this instrumentation name is important since it is used to disable micrometer instrumentation + // this instrumentation name is important since it is used when disabling micrometer + // instrumentation public MicrometerInstrumentationModule() { super("ai-micrometer"); } + @Override + public ElementMatcher.Junction classLoaderMatcher() { + // added in 1.5 + return not(hasClassesNamed("io.micrometer.core.instrument.config.validate.Validated")); + } + @Override public List typeInstrumentations() { return Arrays.asList(new MetricsInstrumentation(), new CompositeMeterRegistryInstrumentation()); diff --git a/settings.gradle.kts b/settings.gradle.kts index 79c57a9729..7d7d9f60af 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -121,6 +121,7 @@ hideFromDependabot(":smoke-tests:apps:Log4j1") hideFromDependabot(":smoke-tests:apps:Log4j2") hideFromDependabot(":smoke-tests:apps:Logback") hideFromDependabot(":smoke-tests:apps:Micrometer") +hideFromDependabot(":smoke-tests:apps:MicrometerPriorTo1_5") hideFromDependabot(":smoke-tests:apps:MongoDB") hideFromDependabot(":smoke-tests:apps:NonDaemonThreads") hideFromDependabot(":smoke-tests:apps:OpenTelemetryApiSupport") diff --git a/smoke-tests/apps/ActuatorMetrics/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/ActuatorMetricsTest.java b/smoke-tests/apps/ActuatorMetrics/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/ActuatorMetricsTest.java index ca38415c0d..dae2a6d030 100644 --- a/smoke-tests/apps/ActuatorMetrics/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/ActuatorMetricsTest.java +++ b/smoke-tests/apps/ActuatorMetrics/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/ActuatorMetricsTest.java @@ -47,8 +47,8 @@ void doMostBasicTest() throws Exception { assertThat(point.getCount()).isEqualTo(1); assertThat(point.getName()).isEqualTo("http_server_requests"); - // this isn't desired, but see https://github.com/micrometer-metrics/micrometer/issues/457 - assertThat(point.getMin()).isNull(); + // running with micrometer 1.5+ and so using upstream micrometer instrumentation + assertThat(point.getMin()).isNotNull(); assertThat(point.getMax()).isNotNull(); assertThat(point.getStdDev()).isNull(); diff --git a/smoke-tests/apps/Micrometer/build.gradle.kts b/smoke-tests/apps/Micrometer/build.gradle.kts index edfe5ad3e3..b5555fdc07 100644 --- a/smoke-tests/apps/Micrometer/build.gradle.kts +++ b/smoke-tests/apps/Micrometer/build.gradle.kts @@ -4,5 +4,5 @@ plugins { dependencies { implementation("org.springframework.boot:spring-boot-starter-web:2.5.12") - implementation("io.micrometer:micrometer-core:1.4.1") + implementation("io.micrometer:micrometer-core:1.5.0") } diff --git a/smoke-tests/apps/MicrometerPriorTo1_5/build.gradle.kts b/smoke-tests/apps/MicrometerPriorTo1_5/build.gradle.kts new file mode 100644 index 0000000000..edfe5ad3e3 --- /dev/null +++ b/smoke-tests/apps/MicrometerPriorTo1_5/build.gradle.kts @@ -0,0 +1,8 @@ +plugins { + id("ai.smoke-test-jar") +} + +dependencies { + implementation("org.springframework.boot:spring-boot-starter-web:2.5.12") + implementation("io.micrometer:micrometer-core:1.4.1") +} diff --git a/smoke-tests/apps/MicrometerPriorTo1_5/src/main/java/com/microsoft/applicationinsights/smoketestapp/SpringBootApp.java b/smoke-tests/apps/MicrometerPriorTo1_5/src/main/java/com/microsoft/applicationinsights/smoketestapp/SpringBootApp.java new file mode 100644 index 0000000000..cee97c9799 --- /dev/null +++ b/smoke-tests/apps/MicrometerPriorTo1_5/src/main/java/com/microsoft/applicationinsights/smoketestapp/SpringBootApp.java @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.applicationinsights.smoketestapp; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringBootApp { + + public static void main(String[] args) { + + SpringApplication.run(SpringBootApp.class, args); + } +} diff --git a/smoke-tests/apps/MicrometerPriorTo1_5/src/main/java/com/microsoft/applicationinsights/smoketestapp/TestController.java b/smoke-tests/apps/MicrometerPriorTo1_5/src/main/java/com/microsoft/applicationinsights/smoketestapp/TestController.java new file mode 100644 index 0000000000..9c4963568b --- /dev/null +++ b/smoke-tests/apps/MicrometerPriorTo1_5/src/main/java/com/microsoft/applicationinsights/smoketestapp/TestController.java @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.applicationinsights.smoketestapp; + +import io.micrometer.core.instrument.Counter; +import io.micrometer.core.instrument.Metrics; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class TestController { + + private final Counter counter = Metrics.counter("test.counter", "tag1", "value1"); + private final Counter excludedCounter = Metrics.counter("test.counter.exclude.me"); + private final Counter anotherExcludedCounter = Metrics.counter("exclude.me.test.counter"); + + @GetMapping("/") + public String root() { + return "OK"; + } + + @GetMapping("/test") + public String test() { + excludedCounter.increment(); + anotherExcludedCounter.increment(); + counter.increment(); + return "OK!"; + } +} diff --git a/smoke-tests/apps/MicrometerPriorTo1_5/src/main/resources/application.properties b/smoke-tests/apps/MicrometerPriorTo1_5/src/main/resources/application.properties new file mode 100644 index 0000000000..a33fa65902 --- /dev/null +++ b/smoke-tests/apps/MicrometerPriorTo1_5/src/main/resources/application.properties @@ -0,0 +1 @@ +management.metrics.export.azuremonitor.instrumentation-key=00000000-0000-0000-0000-000000000000 diff --git a/smoke-tests/apps/MicrometerPriorTo1_5/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/MicrometerDisabledTest.java b/smoke-tests/apps/MicrometerPriorTo1_5/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/MicrometerDisabledTest.java new file mode 100644 index 0000000000..7660bc3a22 --- /dev/null +++ b/smoke-tests/apps/MicrometerPriorTo1_5/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/MicrometerDisabledTest.java @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.applicationinsights.smoketest; + +import static com.microsoft.applicationinsights.smoketest.EnvironmentValue.JAVA_8; +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +@Environment(JAVA_8) +@UseAgent("disabled_applicationinsights.json") +class MicrometerDisabledTest { + + @RegisterExtension static final SmokeTestExtension testing = SmokeTestExtension.create(); + + @Test + @TargetUri("/test") + void doMostBasicTest() throws Exception { + Telemetry telemetry = testing.getTelemetry(0); + + assertThat(telemetry.rd.getName()).isEqualTo("GET /test"); + assertThat(telemetry.rd.getSuccess()).isTrue(); + + // sleep a bit and make sure no micrometer metrics are reported + Thread.sleep(10000); + assertThat(testing.mockedIngestion.getItemsEnvelopeDataType("MetricData")) + .noneMatch(MicrometerTest::isMicrometerMetricWithValueOne); + } +} diff --git a/smoke-tests/apps/MicrometerPriorTo1_5/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/MicrometerNamespaceTest.java b/smoke-tests/apps/MicrometerPriorTo1_5/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/MicrometerNamespaceTest.java new file mode 100644 index 0000000000..f2a976f8f9 --- /dev/null +++ b/smoke-tests/apps/MicrometerPriorTo1_5/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/MicrometerNamespaceTest.java @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.applicationinsights.smoketest; + +import static com.microsoft.applicationinsights.smoketest.EnvironmentValue.JAVA_8; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.data.MapEntry.entry; + +import com.microsoft.applicationinsights.smoketest.schemav2.Data; +import com.microsoft.applicationinsights.smoketest.schemav2.DataPoint; +import com.microsoft.applicationinsights.smoketest.schemav2.Envelope; +import com.microsoft.applicationinsights.smoketest.schemav2.MetricData; +import java.util.List; +import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +@Environment(JAVA_8) +@UseAgent("namespace_applicationinsights.json") +class MicrometerNamespaceTest { + + @RegisterExtension static final SmokeTestExtension testing = SmokeTestExtension.create(); + + @Test + @TargetUri("/test") + void doMostBasicTest() throws Exception { + Telemetry telemetry = testing.getTelemetry(0); + + assertThat(telemetry.rd.getName()).isEqualTo("GET /test"); + assertThat(telemetry.rd.getUrl()).matches("http://localhost:[0-9]+/test"); + assertThat(telemetry.rd.getResponseCode()).isEqualTo("200"); + assertThat(telemetry.rd.getSuccess()).isTrue(); + assertThat(telemetry.rd.getProperties()) + .containsExactly(entry("_MS.ProcessedByMetricExtractors", "True")); + assertThat(telemetry.rd.getMeasurements()).isEmpty(); + + List metricItems = + testing.mockedIngestion.waitForItems( + MicrometerTest::isMicrometerMetricWithValueOne, 1, 10, TimeUnit.SECONDS); + + MetricData data = (MetricData) ((Data) metricItems.get(0).getData()).getBaseData(); + List points = data.getMetrics(); + assertThat(points).hasSize(1); + + DataPoint point = points.get(0); + assertThat(point.getMetricNamespace()).isEqualTo("testNamespace"); + } +} diff --git a/smoke-tests/apps/MicrometerPriorTo1_5/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/MicrometerTest.java b/smoke-tests/apps/MicrometerPriorTo1_5/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/MicrometerTest.java new file mode 100644 index 0000000000..1df9c6ebbd --- /dev/null +++ b/smoke-tests/apps/MicrometerPriorTo1_5/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/MicrometerTest.java @@ -0,0 +1,105 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.applicationinsights.smoketest; + +import static com.microsoft.applicationinsights.smoketest.EnvironmentValue.JAVA_11; +import static com.microsoft.applicationinsights.smoketest.EnvironmentValue.JAVA_11_OPENJ9; +import static com.microsoft.applicationinsights.smoketest.EnvironmentValue.JAVA_17; +import static com.microsoft.applicationinsights.smoketest.EnvironmentValue.JAVA_17_OPENJ9; +import static com.microsoft.applicationinsights.smoketest.EnvironmentValue.JAVA_20; +import static com.microsoft.applicationinsights.smoketest.EnvironmentValue.JAVA_20_OPENJ9; +import static com.microsoft.applicationinsights.smoketest.EnvironmentValue.JAVA_8; +import static com.microsoft.applicationinsights.smoketest.EnvironmentValue.JAVA_8_OPENJ9; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.data.MapEntry.entry; + +import com.microsoft.applicationinsights.smoketest.schemav2.Data; +import com.microsoft.applicationinsights.smoketest.schemav2.DataPoint; +import com.microsoft.applicationinsights.smoketest.schemav2.Envelope; +import com.microsoft.applicationinsights.smoketest.schemav2.MetricData; +import java.util.List; +import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +@UseAgent +abstract class MicrometerTest { + + @RegisterExtension static final SmokeTestExtension testing = SmokeTestExtension.create(); + + @Test + @TargetUri("/test") + void doMostBasicTest() throws Exception { + Telemetry telemetry = testing.getTelemetry(0); + + assertThat(telemetry.rd.getName()).isEqualTo("GET /test"); + assertThat(telemetry.rd.getUrl()).matches("http://localhost:[0-9]+/test"); + assertThat(telemetry.rd.getResponseCode()).isEqualTo("200"); + assertThat(telemetry.rd.getSuccess()).isTrue(); + assertThat(telemetry.rd.getSource()).isNull(); + assertThat(telemetry.rd.getProperties()) + .containsExactly(entry("_MS.ProcessedByMetricExtractors", "True")); + assertThat(telemetry.rd.getMeasurements()).isEmpty(); + + List metricItems = + testing.mockedIngestion.waitForItems( + MicrometerTest::isMicrometerMetricWithValueOne, 1, 10, TimeUnit.SECONDS); + + MetricData data = (MetricData) ((Data) metricItems.get(0).getData()).getBaseData(); + List points = data.getMetrics(); + assertThat(points).hasSize(1); + + DataPoint point = points.get(0); + + assertThat(point.getValue()).isEqualTo(1); // (this was verified above in Predicate also) + assertThat(point.getName()).isEqualTo("test_counter"); + assertThat(point.getCount()).isNull(); + assertThat(point.getMin()).isNull(); + assertThat(point.getMax()).isNull(); + assertThat(point.getStdDev()).isNull(); + assertThat(point.getMetricNamespace()).isNull(); + assertThat(data.getProperties()).hasSize(1); + assertThat(data.getProperties()).containsEntry("tag1", "value1"); + } + + static boolean isMicrometerMetricWithValueOne(Envelope input) { + if (!input.getData().getBaseType().equals("MetricData")) { + return false; + } + MetricData data = (MetricData) ((Data) input.getData()).getBaseData(); + for (DataPoint point : data.getMetrics()) { + if (point.getName().contains("test_counter") && point.getValue() == 1) { + return true; + } + } + return false; + } + + @Environment(JAVA_8) + static class Java8Test extends MicrometerTest {} + + @Environment(JAVA_8_OPENJ9) + static class Java8OpenJ9Test extends MicrometerTest {} + + @Environment(JAVA_11) + static class Java11Test extends MicrometerTest {} + + @Environment(JAVA_11_OPENJ9) + static class Java11OpenJ9Test extends MicrometerTest {} + + @Environment(JAVA_17) + static class Java17Test extends MicrometerTest {} + + @Environment(JAVA_17_OPENJ9) + static class Java17OpenJ9Test extends MicrometerTest {} + + @Environment(JAVA_20) + static class Java18Test extends MicrometerTest {} + + @Environment(JAVA_20_OPENJ9) + static class Java18OpenJ9Test extends MicrometerTest {} + + @Environment(JAVA_20) + static class Java19Test extends MicrometerTest {} +} diff --git a/smoke-tests/apps/MicrometerPriorTo1_5/src/smokeTest/resources/applicationinsights.json b/smoke-tests/apps/MicrometerPriorTo1_5/src/smokeTest/resources/applicationinsights.json new file mode 100644 index 0000000000..d1c5f01d8e --- /dev/null +++ b/smoke-tests/apps/MicrometerPriorTo1_5/src/smokeTest/resources/applicationinsights.json @@ -0,0 +1,32 @@ +{ + "role": { + "name": "testrolename", + "instance": "testroleinstance" + }, + "sampling": { + "percentage": 100 + }, + "metricIntervalSeconds": 5, + "preview": { + "processors": [ + { + "type": "metric-filter", + "exclude": { + "matchType": "strict", + "metricNames": [ + "test_counter_exclude_me" + ] + } + }, + { + "type": "metric-filter", + "exclude": { + "matchType": "regexp", + "metricNames": [ + "exclude_me_.*" + ] + } + } + ] + } +} diff --git a/smoke-tests/apps/MicrometerPriorTo1_5/src/smokeTest/resources/disabled_applicationinsights.json b/smoke-tests/apps/MicrometerPriorTo1_5/src/smokeTest/resources/disabled_applicationinsights.json new file mode 100644 index 0000000000..7fef75f953 --- /dev/null +++ b/smoke-tests/apps/MicrometerPriorTo1_5/src/smokeTest/resources/disabled_applicationinsights.json @@ -0,0 +1,15 @@ +{ + "role": { + "name": "testrolename", + "instance": "testroleinstance" + }, + "sampling": { + "percentage": 100 + }, + "instrumentation": { + "micrometer": { + "enabled": false + } + }, + "metricIntervalSeconds": 5 +} diff --git a/smoke-tests/apps/MicrometerPriorTo1_5/src/smokeTest/resources/logback-test.xml b/smoke-tests/apps/MicrometerPriorTo1_5/src/smokeTest/resources/logback-test.xml new file mode 100644 index 0000000000..0cbbecd57c --- /dev/null +++ b/smoke-tests/apps/MicrometerPriorTo1_5/src/smokeTest/resources/logback-test.xml @@ -0,0 +1,11 @@ + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger{36} - %msg%n + + + + + + diff --git a/smoke-tests/apps/MicrometerPriorTo1_5/src/smokeTest/resources/namespace_applicationinsights.json b/smoke-tests/apps/MicrometerPriorTo1_5/src/smokeTest/resources/namespace_applicationinsights.json new file mode 100644 index 0000000000..b2357b641e --- /dev/null +++ b/smoke-tests/apps/MicrometerPriorTo1_5/src/smokeTest/resources/namespace_applicationinsights.json @@ -0,0 +1,15 @@ +{ + "role": { + "name": "testrolename", + "instance": "testroleinstance" + }, + "sampling": { + "percentage": 100 + }, + "instrumentation": { + "micrometer": { + "namespace": "testNamespace" + } + }, + "metricIntervalSeconds": 5 +}