diff --git a/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml b/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml index ce653dd9b5da6..e4dfe75efa705 100755 --- a/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml +++ b/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml @@ -113,7 +113,7 @@ + files="com.azure.monitor.applicationinsights.spring.AzureSpringMonitorAutoConfig.java"/> diff --git a/sdk/spring/spring-cloud-azure-starter-monitor/README.md b/sdk/spring/spring-cloud-azure-starter-monitor/README.md index 370344376f6cd..a9face5ed40a8 100644 --- a/sdk/spring/spring-cloud-azure-starter-monitor/README.md +++ b/sdk/spring/spring-cloud-azure-starter-monitor/README.md @@ -178,7 +178,7 @@ docker run -e APPLICATIONINSIGHTS_CONNECTION_STRING="{CONNECTION_STRING}" {image ``` where you have to replace `{CONNECTION_STRING}` and `{image-name}` by your connection string and the native image name. -## Debug your Spring native application +### Debug If something does not work as expected, you can enable self-diagnostics features at DEBUG level to get some insights. @@ -193,6 +193,10 @@ docker run -e APPLICATIONINSIGHTS_SELF_DIAGNOSTICS_LEVEL=DEBUG {image-name} You have to replace `{image-name}` by your docker image name. +### Disable the monitoring + +You can disable the monitoring by setting the `otel.sdk.disabled` property or the `OTEL_SDK_DISABLED` environment variable to true. + ## Contributing This project welcomes contributions and suggestions. Most contributions require you to agree to a diff --git a/sdk/spring/spring-cloud-azure-starter-monitor/src/main/java/com/azure/monitor/applicationinsights/spring/AzureSpringMonitorActivation.java b/sdk/spring/spring-cloud-azure-starter-monitor/src/main/java/com/azure/monitor/applicationinsights/spring/AzureSpringMonitorActivation.java deleted file mode 100644 index e6c7dd2fe55f6..0000000000000 --- a/sdk/spring/spring-cloud-azure-starter-monitor/src/main/java/com/azure/monitor/applicationinsights/spring/AzureSpringMonitorActivation.java +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.monitor.applicationinsights.spring; - -/** - * Azure Azure Spring Monitor activation - */ -public final class AzureSpringMonitorActivation { - - /** a flag to indicate if Azure Spring Monitor is activated or not. */ - private final boolean activated; - - /** - * Creates an instance of {@link AzureSpringMonitorActivation}. - */ - public AzureSpringMonitorActivation() { - this.activated = true; // We leave the AzureTelemetryActivation class because it could be used to provide the ability - // to disable the starter features - } - - /** - * @return true if it's activated. - */ - public boolean isTrue() { - return activated; - } - -} diff --git a/sdk/spring/spring-cloud-azure-starter-monitor/src/main/java/com/azure/monitor/applicationinsights/spring/AzureSpringMonitorActivationConfig.java b/sdk/spring/spring-cloud-azure-starter-monitor/src/main/java/com/azure/monitor/applicationinsights/spring/AzureSpringMonitorActivationConfig.java deleted file mode 100644 index 5698340ec63be..0000000000000 --- a/sdk/spring/spring-cloud-azure-starter-monitor/src/main/java/com/azure/monitor/applicationinsights/spring/AzureSpringMonitorActivationConfig.java +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.monitor.applicationinsights.spring; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * Config for AzureSpringMonitorActivation - */ -@Configuration(proxyBeanMethods = false) -public class AzureSpringMonitorActivationConfig { - - /** - * Declare an AzureSpringMonitorActivation bean - * @return AzureSpringMonitorActivation - */ - @Bean - public AzureSpringMonitorActivation azureSpringMonitorActivation() { - return new AzureSpringMonitorActivation(); - } - - -} diff --git a/sdk/spring/spring-cloud-azure-starter-monitor/src/main/java/com/azure/monitor/applicationinsights/spring/AzureSpringMonitorAutoConfig.java b/sdk/spring/spring-cloud-azure-starter-monitor/src/main/java/com/azure/monitor/applicationinsights/spring/AzureSpringMonitorAutoConfig.java index 09b465dc81b4d..a7e76611e45f9 100644 --- a/sdk/spring/spring-cloud-azure-starter-monitor/src/main/java/com/azure/monitor/applicationinsights/spring/AzureSpringMonitorAutoConfig.java +++ b/sdk/spring/spring-cloud-azure-starter-monitor/src/main/java/com/azure/monitor/applicationinsights/spring/AzureSpringMonitorAutoConfig.java @@ -3,16 +3,119 @@ package com.azure.monitor.applicationinsights.spring; +import com.azure.core.http.HttpPipeline; +import com.azure.core.util.logging.ClientLogger; +import com.azure.monitor.opentelemetry.exporter.AzureMonitorExporterBuilder; import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration; +import io.opentelemetry.sdk.logs.export.LogRecordExporter; +import io.opentelemetry.sdk.metrics.export.MetricExporter; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.trace.export.SpanExporter; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; + +import java.util.Optional; /** * Auto config for Azure Spring Monitor */ @Configuration(proxyBeanMethods = false) @AutoConfigureBefore(OpenTelemetryAutoConfiguration.class) -@Import({AzureSpringMonitorConfig.class, AzureSpringMonitorActivationConfig.class}) +@ConditionalOnProperty(name = "otel.sdk.disabled", havingValue = "false", matchIfMissing = true) public class AzureSpringMonitorAutoConfig { + + private static final ClientLogger LOGGER = new ClientLogger(AzureSpringMonitorAutoConfig.class); + + private static final String CONNECTION_STRING_ERROR_MESSAGE = "Unable to find the Application Insights connection string."; + + private final Optional azureMonitorExporterBuilderOpt; + + /** + * Create an instance of AzureSpringMonitorConfig + * @param connectionStringSysProp connection string system property + * @param httpPipeline an instance of HttpPipeline + */ + public AzureSpringMonitorAutoConfig(@Value("${applicationinsights.connection.string:}") String connectionStringSysProp, ObjectProvider httpPipeline) { + this.azureMonitorExporterBuilderOpt = createAzureMonitorExporterBuilder(connectionStringSysProp, httpPipeline); + if (!isNativeRuntimeExecution()) { + LOGGER.warning("You are using Application Insights for Spring in a non-native GraalVM runtime environment. We recommend using the Application Insights Java agent."); + } + } + + private static boolean isNativeRuntimeExecution() { + String imageCode = System.getProperty("org.graalvm.nativeimage.imagecode"); + return imageCode != null; + } + + private Optional createAzureMonitorExporterBuilder(String connectionStringSysProp, ObjectProvider httpPipeline) { + Optional connectionString = ConnectionStringRetriever.retrieveConnectionString(connectionStringSysProp); + if (connectionString.isPresent()) { + try { + AzureMonitorExporterBuilder azureMonitorExporterBuilder = new AzureMonitorExporterBuilder().connectionString(connectionString.get()); + HttpPipeline providedHttpPipeline = httpPipeline.getIfAvailable(); + if (providedHttpPipeline != null) { + azureMonitorExporterBuilder = azureMonitorExporterBuilder.httpPipeline(providedHttpPipeline); + } + return Optional.of(azureMonitorExporterBuilder); + } catch (IllegalArgumentException illegalArgumentException) { + String errorMessage = illegalArgumentException.getMessage(); + if (errorMessage.contains("InstrumentationKey")) { + LOGGER.warning(CONNECTION_STRING_ERROR_MESSAGE + " Please check you have not used an instrumentation key instead of a connection string"); + } + } + } else { + LOGGER.warning(CONNECTION_STRING_ERROR_MESSAGE); + } + return Optional.empty(); + } + + /** + * Declare a MetricExporter bean + * @return MetricExporter + */ + @Bean + public MetricExporter azureSpringMonitorMetricExporter() { + if (!azureMonitorExporterBuilderOpt.isPresent()) { + return null; + } + return azureMonitorExporterBuilderOpt.get().buildMetricExporter(); + } + + /** + * Declare a SpanExporter bean + * @return SpanExporter + */ + @Bean + public SpanExporter azureSpringMonitorSpanExporter() { + if (!azureMonitorExporterBuilderOpt.isPresent()) { + return null; + } + return azureMonitorExporterBuilderOpt.get().buildTraceExporter(); + } + + /** + * Declare a LogRecordExporter bean + * @return LogRecordExporter + */ + @Bean + public LogRecordExporter azureSpringMonitorLogRecordExporter() { + if (!azureMonitorExporterBuilderOpt.isPresent()) { + return null; + } + return azureMonitorExporterBuilderOpt.get().buildLogRecordExporter(); + } + + /** + * Declare OpenTelemetryVersionCheckRunner bean to check the OpenTelemetry version + * @param resource An OpenTelemetry resource + * @return OpenTelemetryVersionCheckRunner + */ + @Bean + public OpenTelemetryVersionCheckRunner openTelemetryVersionCheckRunner(Resource resource) { + return new OpenTelemetryVersionCheckRunner(resource); + } } diff --git a/sdk/spring/spring-cloud-azure-starter-monitor/src/main/java/com/azure/monitor/applicationinsights/spring/AzureSpringMonitorConfig.java b/sdk/spring/spring-cloud-azure-starter-monitor/src/main/java/com/azure/monitor/applicationinsights/spring/AzureSpringMonitorConfig.java deleted file mode 100644 index a56090a2bad78..0000000000000 --- a/sdk/spring/spring-cloud-azure-starter-monitor/src/main/java/com/azure/monitor/applicationinsights/spring/AzureSpringMonitorConfig.java +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.monitor.applicationinsights.spring; - -import com.azure.core.http.HttpPipeline; -import com.azure.core.util.logging.ClientLogger; -import com.azure.monitor.opentelemetry.exporter.AzureMonitorExporterBuilder; -import io.opentelemetry.sdk.logs.export.LogRecordExporter; -import io.opentelemetry.sdk.metrics.export.MetricExporter; -import io.opentelemetry.sdk.trace.export.SpanExporter; -import java.util.Optional; -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * Config for Azure Telemetry - */ -@Configuration(proxyBeanMethods = false) -public class AzureSpringMonitorConfig { - - private static final ClientLogger LOGGER = new ClientLogger(AzureSpringMonitorConfig.class); - - private static final String CONNECTION_STRING_ERROR_MESSAGE = "Unable to find the Application Insights connection string."; - - private final Optional azureMonitorExporterBuilderOpt; - - /** - * Create an instance of AzureSpringMonitorConfig - * @param connectionStringSysProp connection string system property - * @param azureSpringMonitorActivation a instance of AzureTelemetryActivation - * @param httpPipeline an instance of HttpPipeline - */ - public AzureSpringMonitorConfig(@Value("${applicationinsights.connection.string:}") String connectionStringSysProp, AzureSpringMonitorActivation azureSpringMonitorActivation, ObjectProvider httpPipeline) { - if (azureSpringMonitorActivation.isTrue()) { - this.azureMonitorExporterBuilderOpt = createAzureMonitorExporterBuilder(connectionStringSysProp, httpPipeline); - if (!isNativeRuntimeExecution()) { - LOGGER.warning("You are using Application Insights for Spring in a non-native GraalVM runtime environment. We recommend using the Application Insights Java agent."); - } - } else { - azureMonitorExporterBuilderOpt = Optional.empty(); - } - - } - - private static boolean isNativeRuntimeExecution() { - String imageCode = System.getProperty("org.graalvm.nativeimage.imagecode"); - return imageCode != null; - } - - private Optional createAzureMonitorExporterBuilder(String connectionStringSysProp, ObjectProvider httpPipeline) { - Optional connectionString = ConnectionStringRetriever.retrieveConnectionString(connectionStringSysProp); - if (connectionString.isPresent()) { - try { - AzureMonitorExporterBuilder azureMonitorExporterBuilder = new AzureMonitorExporterBuilder().connectionString(connectionString.get()); - HttpPipeline providedHttpPipeline = httpPipeline.getIfAvailable(); - if (providedHttpPipeline != null) { - azureMonitorExporterBuilder = azureMonitorExporterBuilder.httpPipeline(providedHttpPipeline); - } - return Optional.of(azureMonitorExporterBuilder); - } catch (IllegalArgumentException illegalArgumentException) { - String errorMessage = illegalArgumentException.getMessage(); - if (errorMessage.contains("InstrumentationKey")) { - LOGGER.warning(CONNECTION_STRING_ERROR_MESSAGE + " Please check you have not used an instrumentation key instead of a connection string"); - } - } - } else { - LOGGER.warning(CONNECTION_STRING_ERROR_MESSAGE); - } - return Optional.empty(); - } - - /** - * Declare a MetricExporter bean - * @return MetricExporter - */ - @Bean - public MetricExporter azureSpringMonitorMetricExporter() { - if (!azureMonitorExporterBuilderOpt.isPresent()) { - return null; - } - return azureMonitorExporterBuilderOpt.get().buildMetricExporter(); - } - - /** - * Declare a SpanExporter bean - * @return SpanExporter - */ - @Bean - public SpanExporter azureSpringMonitorSpanExporter() { - if (!azureMonitorExporterBuilderOpt.isPresent()) { - return null; - } - return azureMonitorExporterBuilderOpt.get().buildTraceExporter(); - } - - /** - * Declare a LogRecordExporter bean - * @return LogRecordExporter - */ - @Bean - public LogRecordExporter azureSpringMonitorLogRecordExporter() { - if (!azureMonitorExporterBuilderOpt.isPresent()) { - return null; - } - return azureMonitorExporterBuilderOpt.get().buildLogRecordExporter(); - } - - -} diff --git a/sdk/spring/spring-cloud-azure-starter-monitor/src/main/java/com/azure/monitor/applicationinsights/spring/JvmMetricsPostProcessor.java b/sdk/spring/spring-cloud-azure-starter-monitor/src/main/java/com/azure/monitor/applicationinsights/spring/JvmMetricsPostProcessor.java deleted file mode 100644 index 1e224456cca44..0000000000000 --- a/sdk/spring/spring-cloud-azure-starter-monitor/src/main/java/com/azure/monitor/applicationinsights/spring/JvmMetricsPostProcessor.java +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.monitor.applicationinsights.spring; - -import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.instrumentation.runtimemetrics.java8.BufferPools; -import io.opentelemetry.instrumentation.runtimemetrics.java8.Classes; -import io.opentelemetry.instrumentation.runtimemetrics.java8.Cpu; -import io.opentelemetry.instrumentation.runtimemetrics.java8.GarbageCollector; -import io.opentelemetry.instrumentation.runtimemetrics.java8.MemoryPools; -import io.opentelemetry.instrumentation.runtimemetrics.java8.Threads; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.core.Ordered; - -/** - * A bean post processor for JVM metrics - */ -// See https://github.com/Azure/azure-sdk-for-java/issues/35725 -public class JvmMetricsPostProcessor implements BeanPostProcessor, Ordered { - - private final AzureSpringMonitorActivation azureSpringMonitorActivation; - - /** - * Create an instance of JvmMetricsPostProcessor - * @param azureSpringMonitorActivation the azure telemetry activation - */ - public JvmMetricsPostProcessor(AzureSpringMonitorActivation azureSpringMonitorActivation) { - this.azureSpringMonitorActivation = azureSpringMonitorActivation; - } - - /** - * Post process after initialization - * @param bean a bean - * @param beanName name of the bean - * @return a bean - * @throws BeansException a bean exception - */ - @Override - public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { - if (azureSpringMonitorActivation.isTrue() && bean instanceof OpenTelemetry) { - OpenTelemetry openTelemetry = (OpenTelemetry) bean; - BufferPools.registerObservers(openTelemetry); - Classes.registerObservers(openTelemetry); - Cpu.registerObservers(openTelemetry); - MemoryPools.registerObservers(openTelemetry); - Threads.registerObservers(openTelemetry); - GarbageCollector.registerObservers(openTelemetry); - } - return bean; - } - - /** - * @return the order - */ - @Override - public int getOrder() { - return Ordered.LOWEST_PRECEDENCE - 1; - } - -} diff --git a/sdk/spring/spring-cloud-azure-starter-monitor/src/main/java/com/azure/monitor/applicationinsights/spring/OpenTelemetryVersionCheckRunner.java b/sdk/spring/spring-cloud-azure-starter-monitor/src/main/java/com/azure/monitor/applicationinsights/spring/OpenTelemetryVersionCheckRunner.java index 13bb5db9a212b..682d1f58e87a2 100644 --- a/sdk/spring/spring-cloud-azure-starter-monitor/src/main/java/com/azure/monitor/applicationinsights/spring/OpenTelemetryVersionCheckRunner.java +++ b/sdk/spring/spring-cloud-azure-starter-monitor/src/main/java/com/azure/monitor/applicationinsights/spring/OpenTelemetryVersionCheckRunner.java @@ -7,13 +7,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.CommandLineRunner; -import org.springframework.stereotype.Component; /** * This component alerts the user to the fact that the OpenTelemetry version used is not compatible * with the starter. One use case is Spring Boot 3 using OpenTelemetry. */ -@Component public class OpenTelemetryVersionCheckRunner implements CommandLineRunner { private static final Logger LOG = LoggerFactory.getLogger(OpenTelemetryVersionCheckRunner.class); diff --git a/sdk/spring/spring-cloud-azure-starter-monitor/src/main/java/com/azure/monitor/applicationinsights/spring/selfdiagnostics/SelfDiagAutoConfig.java b/sdk/spring/spring-cloud-azure-starter-monitor/src/main/java/com/azure/monitor/applicationinsights/spring/selfdiagnostics/SelfDiagAutoConfig.java index c5579960ac5c3..99287b0b9dc14 100644 --- a/sdk/spring/spring-cloud-azure-starter-monitor/src/main/java/com/azure/monitor/applicationinsights/spring/selfdiagnostics/SelfDiagAutoConfig.java +++ b/sdk/spring/spring-cloud-azure-starter-monitor/src/main/java/com/azure/monitor/applicationinsights/spring/selfdiagnostics/SelfDiagAutoConfig.java @@ -5,6 +5,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -16,6 +17,7 @@ Main configuration entry point of the self-diagnostics **/ @Configuration(proxyBeanMethods = false) +@ConditionalOnProperty(name = "otel.sdk.disabled", havingValue = "false", matchIfMissing = true) @Import({DefaultLogConfig.class, LogbackSelfDiagConfig.class, JdbcSelfDiagConfig.class}) public class SelfDiagAutoConfig { private static final Logger LOG = LoggerFactory.getLogger(SelfDiagAutoConfig.class);