From 9bc37111e6024c53cd7bb498112a785865009d15 Mon Sep 17 00:00:00 2001 From: Arthur Gavlyukovskiy Date: Tue, 9 Jan 2018 02:26:34 +0200 Subject: [PATCH 01/43] Added application insights starter for spring boot --- .../build.gradle | 55 +++++ ...pplicationInsightsModuleConfiguration.java | 62 +++++ .../boot/ApplicationInsightsProperties.java | 179 +++++++++++++++ ...ionInsightsTelemetryAutoConfiguration.java | 161 +++++++++++++ ...icationInsightsWebModuleConfiguration.java | 83 +++++++ ...cationInsightsWebMvcAutoConfiguration.java | 80 +++++++ .../ConditionalOnOperatingSystem.java | 44 ++++ .../OnOperationSystemCondition.java | 49 ++++ .../boot/conditional/OperatingSystem.java | 27 +++ .../SpringBootContextInitializer.java | 50 +++++ .../main/resources/META-INF/spring.factories | 22 ++ ...sightsTelemetryAutoConfigurationTests.java | 211 ++++++++++++++++++ ...nInsightsWebMvcAutoConfigurationTests.java | 76 +++++++ settings.gradle | 1 + 14 files changed, 1100 insertions(+) create mode 100644 azure-application-insights-spring-boot-starter/build.gradle create mode 100644 azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java create mode 100644 azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java create mode 100644 azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java create mode 100644 azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java create mode 100644 azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java create mode 100644 azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/ConditionalOnOperatingSystem.java create mode 100644 azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/OnOperationSystemCondition.java create mode 100644 azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/OperatingSystem.java create mode 100644 azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/SpringBootContextInitializer.java create mode 100644 azure-application-insights-spring-boot-starter/src/main/resources/META-INF/spring.factories create mode 100644 azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java create mode 100644 azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfigurationTests.java diff --git a/azure-application-insights-spring-boot-starter/build.gradle b/azure-application-insights-spring-boot-starter/build.gradle new file mode 100644 index 00000000000..ed452796e26 --- /dev/null +++ b/azure-application-insights-spring-boot-starter/build.gradle @@ -0,0 +1,55 @@ +/* + * ApplicationInsights-Java + * Copyright (c) Microsoft Corporation + * All rights reserved. + * + * MIT License + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the ""Software""), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +apply from: "$buildScriptsDir/common-java.gradle" +apply from: "$buildScriptsDir/publishing.gradle" + +archivesBaseName = 'azure-application-insights-spring-boot-starter' + +dependencies { + compile (project(':core')) + compile (project(':web')) + provided('org.springframework.boot:spring-boot:1.5.9.RELEASE') + provided('org.springframework.boot:spring-boot-autoconfigure:1.5.9.RELEASE') + provided('org.springframework.boot:spring-boot-starter-web:1.5.9.RELEASE') + provided('org.springframework.boot:spring-boot-configuration-processor:1.5.9.RELEASE') + + testCompile('org.junit.jupiter:junit-jupiter-api:5.0.2') + testCompile('org.junit.jupiter:junit-jupiter-params:5.0.2') + testCompile('org.junit.jupiter:junit-jupiter-engine:5.0.2') + testCompile('org.springframework.boot:spring-boot-starter-test:1.5.9.RELEASE') + testCompile('org.assertj:assertj-core:3.9.0') +} + +jar { + enabled = false +} + +// region Publishing properties + +projectPomName = project.msftAppInsightsJavaSdk + " Spring Boot starter" +projectPomDescription = "This is the Spring Boot starter of " + project.msftAppInsightsJavaSdk + +whenPomConfigured = { p -> + def agentArtifactId = project(":agent").jar.baseName + p.dependencies = p.dependencies.findAll { dep -> dep.artifactId != agentArtifactId } + writePomToArtifactsDirectory(p, project.name) +} diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java new file mode 100644 index 00000000000..b186e422fa6 --- /dev/null +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java @@ -0,0 +1,62 @@ +/* + * ApplicationInsights-Java + * Copyright (c) Microsoft Corporation + * All rights reserved. + * + * MIT License + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the ""Software""), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package com.microsoft.applicationinsights.boot; + +import com.microsoft.applicationinsights.boot.conditional.ConditionalOnOperatingSystem; +import com.microsoft.applicationinsights.boot.conditional.OperatingSystem; +import com.microsoft.applicationinsights.boot.initializer.SpringBootContextInitializer; +import com.microsoft.applicationinsights.extensibility.initializer.DeviceInfoContextInitializer; +import com.microsoft.applicationinsights.extensibility.initializer.SdkVersionContextInitializer; +import com.microsoft.applicationinsights.internal.perfcounter.ProcessPerformanceCountersModule; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +@Configuration +public class ApplicationInsightsModuleConfiguration { + + @Bean + public SpringBootContextInitializer springBootContextInitializer(Environment environment) { + return new SpringBootContextInitializer(environment); + } + + @Bean + public SdkVersionContextInitializer sdkVersionContextInitializer() { + return new SdkVersionContextInitializer(); + } + + @Bean + public DeviceInfoContextInitializer deviceInfoContextInitializer() { + return new DeviceInfoContextInitializer(); + } + + @Bean + @ConditionalOnOperatingSystem(OperatingSystem.WINDOWS) + public ProcessPerformanceCountersModule processPerformanceCountersModule() { + try { + return new ProcessPerformanceCountersModule(); + } + catch (Exception e) { + throw new IllegalStateException("Could not initialize Windows performance counters module", e); + } + } +} diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java new file mode 100644 index 00000000000..e1674648a80 --- /dev/null +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java @@ -0,0 +1,179 @@ +/* + * ApplicationInsights-Java + * Copyright (c) Microsoft Corporation + * All rights reserved. + * + * MIT License + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the ""Software""), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package com.microsoft.applicationinsights.boot; + +import com.microsoft.applicationinsights.channel.TelemetryChannel; +import com.microsoft.applicationinsights.internal.logger.InternalLogger.LoggerOutputType; +import com.microsoft.applicationinsights.internal.logger.InternalLogger.LoggingLevel; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties("azure.application-insights") +public class ApplicationInsightsProperties { + + private boolean enabled = true; + private String instrumentationKey; + private Channel channel = new Channel(); + private QuickPulse quickPulse = new QuickPulse(); + private Logger logger = new Logger(); + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public String getInstrumentationKey() { + return instrumentationKey; + } + + public void setInstrumentationKey(String instrumentationKey) { + this.instrumentationKey = instrumentationKey; + } + + public Channel getChannel() { + return channel; + } + + public void setChannel(Channel channel) { + this.channel = channel; + } + + public QuickPulse getQuickPulse() { + return quickPulse; + } + + public void setQuickPulse(QuickPulse quickPulse) { + this.quickPulse = quickPulse; + } + + public Logger getLogger() { + return logger; + } + + public void setLogger(Logger logger) { + this.logger = logger; + } + + public static class QuickPulse { + private boolean enabled = true; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + } + + public static class Channel { + private InProcess inProcess = new InProcess(); + + public InProcess getInProcess() { + return inProcess; + } + + public void setInProcess(InProcess inProcess) { + this.inProcess = inProcess; + } + + public static class InProcess { + private boolean developerMode = false; + private String endpointAddress; + private int maxTelemetryBufferCapacity; + private int flushIntervalInSeconds; + private int maxTransmissionStorageFilesCapacityInMb; + private boolean throttling = true; + + public boolean isDeveloperMode() { + return developerMode; + } + + public void setDeveloperMode(boolean developerMode) { + this.developerMode = developerMode; + } + + public String getEndpointAddress() { + return endpointAddress; + } + + public void setEndpointAddress(String endpointAddress) { + this.endpointAddress = endpointAddress; + } + + public int getMaxTelemetryBufferCapacity() { + return maxTelemetryBufferCapacity; + } + + public void setMaxTelemetryBufferCapacity(int maxTelemetryBufferCapacity) { + this.maxTelemetryBufferCapacity = maxTelemetryBufferCapacity; + } + + public int getFlushIntervalInSeconds() { + return flushIntervalInSeconds; + } + + public void setFlushIntervalInSeconds(int flushIntervalInSeconds) { + this.flushIntervalInSeconds = flushIntervalInSeconds; + } + + public int getMaxTransmissionStorageFilesCapacityInMb() { + return maxTransmissionStorageFilesCapacityInMb; + } + + public void setMaxTransmissionStorageFilesCapacityInMb(int maxTransmissionStorageFilesCapacityInMb) { + this.maxTransmissionStorageFilesCapacityInMb = maxTransmissionStorageFilesCapacityInMb; + } + + public boolean isThrottling() { + return throttling; + } + + public void setThrottling(boolean throttling) { + this.throttling = throttling; + } + } + } + + public static class Logger { + private LoggerOutputType type = LoggerOutputType.CONSOLE; + private LoggingLevel level = LoggingLevel.INFO; + + public LoggerOutputType getType() { + return type; + } + + public void setType(LoggerOutputType type) { + this.type = type; + } + + public LoggingLevel getLevel() { + return level; + } + + public void setLevel(LoggingLevel level) { + this.level = level; + } + } +} diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java new file mode 100644 index 00000000000..caf8abac143 --- /dev/null +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java @@ -0,0 +1,161 @@ +/* + * ApplicationInsights-Java + * Copyright (c) Microsoft Corporation + * All rights reserved. + * + * MIT License + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the ""Software""), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package com.microsoft.applicationinsights.boot; + +import com.microsoft.applicationinsights.TelemetryClient; +import com.microsoft.applicationinsights.TelemetryConfiguration; +import com.microsoft.applicationinsights.boot.ApplicationInsightsTelemetryAutoConfiguration.EnabledAndHasInstrumentationKeyCondition; +import com.microsoft.applicationinsights.channel.TelemetryChannel; +import com.microsoft.applicationinsights.channel.TelemetrySampler; +import com.microsoft.applicationinsights.channel.concrete.inprocess.InProcessTelemetryChannel; +import com.microsoft.applicationinsights.extensibility.ContextInitializer; +import com.microsoft.applicationinsights.extensibility.TelemetryInitializer; +import com.microsoft.applicationinsights.extensibility.TelemetryModule; +import com.microsoft.applicationinsights.extensibility.TelemetryProcessor; +import com.microsoft.applicationinsights.internal.channel.sampling.FixedRateTelemetrySampler; +import com.microsoft.applicationinsights.internal.logger.InternalLogger; +import org.slf4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.AllNestedConditions; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.slf4j.LoggerFactory.getLogger; + +@Configuration +@EnableConfigurationProperties(ApplicationInsightsProperties.class) +@Conditional(EnabledAndHasInstrumentationKeyCondition.class) +@ConditionalOnClass(TelemetryConfiguration.class) +@Import({ + ApplicationInsightsModuleConfiguration.class, + ApplicationInsightsWebModuleConfiguration.class +}) +public class ApplicationInsightsTelemetryAutoConfiguration { + + private static final Logger log = getLogger(ApplicationInsightsTelemetryAutoConfiguration.class); + + @Autowired + private ApplicationInsightsProperties applicationInsightsProperties; + + @Autowired(required = false) + private Collection contextInitializers; + @Autowired(required = false) + private Collection telemetryInitializers; + @Autowired(required = false) + private Collection telemetryModules; + @Autowired(required = false) + private Collection telemetryProcessors; + + @Bean + public TelemetryConfiguration telemetryConfiguration(TelemetryChannel telemetryChannel) { + TelemetryConfiguration telemetryConfiguration = TelemetryConfiguration.getActive(); + telemetryConfiguration.setTrackingIsDisabled(!applicationInsightsProperties.isEnabled()); + telemetryConfiguration.setInstrumentationKey(applicationInsightsProperties.getInstrumentationKey()); + if (contextInitializers != null) { + telemetryConfiguration.getContextInitializers().addAll(contextInitializers); + } + if (telemetryInitializers != null) { + telemetryConfiguration.getTelemetryInitializers().addAll(telemetryInitializers); + } + if (telemetryModules != null) { + telemetryConfiguration.getTelemetryModules().addAll(telemetryModules); + } + if (telemetryProcessors != null) { + telemetryConfiguration.getTelemetryProcessors().addAll(telemetryProcessors); + } + telemetryConfiguration.setChannel(telemetryChannel); + initializeComponents(telemetryConfiguration); + return telemetryConfiguration; + } + + // TODO: copy-paste from TelemetryConfigurationFactory, move to TelemetryConfiguration? + private void initializeComponents(TelemetryConfiguration configuration) { + List telemetryModules = configuration.getTelemetryModules(); + + for (TelemetryModule module : telemetryModules) { + try { + module.initialize(configuration); + } + catch (Exception e) { + log.error("Failed to initialized telemetry module " + module.getClass().getSimpleName(), e); + } + } + } + + @Bean + public TelemetryClient telemetryClient(TelemetryConfiguration configuration) { + return new TelemetryClient(configuration); + } + + @Bean + @ConditionalOnMissingBean + public TelemetrySampler telemetrySampler() { + return new FixedRateTelemetrySampler(); + } + + @Bean + @ConditionalOnMissingBean + public TelemetryChannel telemetryChannel(TelemetrySampler telemetrySampler) { + ApplicationInsightsProperties.Channel.InProcess inProcess = applicationInsightsProperties.getChannel().getInProcess(); + InProcessTelemetryChannel telemetryChannel = new InProcessTelemetryChannel(inProcess.getEndpointAddress(), + /*String.valueOf(inProcess.getMaxTransmissionStorageFilesCapacityInMb()),*/ inProcess.isDeveloperMode(), + inProcess.getMaxTelemetryBufferCapacity(), inProcess.getFlushIntervalInSeconds()/*, inProcess.isThrottling()*/); + telemetryChannel.setSampler(telemetrySampler); + return telemetryChannel; + } + + @Bean + public InternalLogger internalLogger() { + Map loggerParameters = new HashMap<>(); + ApplicationInsightsProperties.Logger logger = applicationInsightsProperties.getLogger(); + loggerParameters.put("Level", logger.getLevel().name()); + InternalLogger.INSTANCE.initialize(logger.getType().name(), loggerParameters); + return InternalLogger.INSTANCE; + } + + static class EnabledAndHasInstrumentationKeyCondition extends AllNestedConditions { + + EnabledAndHasInstrumentationKeyCondition() { + super(ConfigurationPhase.REGISTER_BEAN); + } + + @ConditionalOnProperty(value = "azure.application-insights.enabled", matchIfMissing = true) + static class OnEnabled { + } + + + @ConditionalOnProperty(value = "azure.application-insights.instrumentation-key") + static class OnInstrumentationKeySet { + } + } +} diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java new file mode 100644 index 00000000000..ba02a881bc9 --- /dev/null +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java @@ -0,0 +1,83 @@ +/* + * ApplicationInsights-Java + * Copyright (c) Microsoft Corporation + * All rights reserved. + * + * MIT License + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the ""Software""), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package com.microsoft.applicationinsights.boot; + +import com.microsoft.applicationinsights.web.extensibility.initializers.WebOperationIdTelemetryInitializer; +import com.microsoft.applicationinsights.web.extensibility.initializers.WebOperationNameTelemetryInitializer; +import com.microsoft.applicationinsights.web.extensibility.initializers.WebSessionTelemetryInitializer; +import com.microsoft.applicationinsights.web.extensibility.initializers.WebUserAgentTelemetryInitializer; +import com.microsoft.applicationinsights.web.extensibility.initializers.WebUserTelemetryInitializer; +import com.microsoft.applicationinsights.web.extensibility.modules.WebRequestTrackingTelemetryModule; +import com.microsoft.applicationinsights.web.extensibility.modules.WebSessionTrackingTelemetryModule; +import com.microsoft.applicationinsights.web.extensibility.modules.WebUserTrackingTelemetryModule; +import com.microsoft.applicationinsights.web.internal.perfcounter.WebPerformanceCounterModule; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ApplicationInsightsWebModuleConfiguration { + + @Bean + public WebRequestTrackingTelemetryModule webRequestTrackingTelemetryModule() { + return new WebRequestTrackingTelemetryModule(); + } + + @Bean + public WebSessionTrackingTelemetryModule webSessionTrackingTelemetryModule() { + return new WebSessionTrackingTelemetryModule(); + } + + @Bean + public WebUserTrackingTelemetryModule webUserTrackingTelemetryModule() { + return new WebUserTrackingTelemetryModule(); + } + + @Bean + public WebPerformanceCounterModule webPerformanceCounterModule() { + return new WebPerformanceCounterModule(); + } + + @Bean + public WebOperationIdTelemetryInitializer webOperationIdTelemetryInitializer() { + return new WebOperationIdTelemetryInitializer(); + } + + @Bean + public WebOperationNameTelemetryInitializer webOperationNameTelemetryInitializer() { + return new WebOperationNameTelemetryInitializer(); + } + + @Bean + public WebSessionTelemetryInitializer webSessionTelemetryInitializer() { + return new WebSessionTelemetryInitializer(); + } + + @Bean + public WebUserTelemetryInitializer webUserTelemetryInitializer() { + return new WebUserTelemetryInitializer(); + } + + @Bean + public WebUserAgentTelemetryInitializer webUserAgentTelemetryInitializer() { + return new WebUserAgentTelemetryInitializer(); + } +} diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java new file mode 100644 index 00000000000..aa4d2c0d025 --- /dev/null +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java @@ -0,0 +1,80 @@ +/* + * ApplicationInsights-Java + * Copyright (c) Microsoft Corporation + * All rights reserved. + * + * MIT License + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the ""Software""), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package com.microsoft.applicationinsights.boot; + +import com.microsoft.applicationinsights.TelemetryConfiguration; +import com.microsoft.applicationinsights.internal.quickpulse.QuickPulse; +import com.microsoft.applicationinsights.web.internal.WebRequestTrackingFilter; +import com.microsoft.applicationinsights.web.spring.internal.InterceptorRegistry; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.boot.context.embedded.EmbeddedWebApplicationContext; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.core.Ordered; + +@Configuration +@Import(InterceptorRegistry.class) +@AutoConfigureAfter(ApplicationInsightsTelemetryAutoConfiguration.class) +@ConditionalOnBean(TelemetryConfiguration.class) +@ConditionalOnWebApplication +public class ApplicationInsightsWebMvcAutoConfiguration { + + @Bean + public FilterRegistrationBean webRequestTrackingFilterRegistrationBean(WebRequestTrackingFilter webRequestTrackingFilter) { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setFilter(webRequestTrackingFilter); + registration.addUrlPatterns("/*"); + registration.setName("webRequestTrackingFilter"); + registration.setOrder(Ordered.HIGHEST_PRECEDENCE + 10); + return registration; + } + + @Bean + @ConditionalOnMissingBean + public WebRequestTrackingFilter webRequestTrackingFilter( + ApplicationContext applicationContext, + @Value("${spring.application.name:application}") String applicationName) { + // Spring Boot application is running inside embedded container + if (applicationContext instanceof EmbeddedWebApplicationContext) { + return new WebRequestTrackingFilter(applicationName); + } + else { + return new WebRequestTrackingFilter(); + } + } + + @Bean + @ConditionalOnProperty(value = "azure.application-insights.quick-pulse.enabled", havingValue = "true", matchIfMissing = true) + public QuickPulse quickPulse() { + QuickPulse.INSTANCE.initialize(); + return QuickPulse.INSTANCE; + } +} diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/ConditionalOnOperatingSystem.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/ConditionalOnOperatingSystem.java new file mode 100644 index 00000000000..813cb97582f --- /dev/null +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/ConditionalOnOperatingSystem.java @@ -0,0 +1,44 @@ +/* + * ApplicationInsights-Java + * Copyright (c) Microsoft Corporation + * All rights reserved. + * + * MIT License + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the ""Software""), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package com.microsoft.applicationinsights.boot.conditional; + +import org.springframework.context.annotation.Conditional; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Conditional(OnOperationSystemCondition.class) +public @interface ConditionalOnOperatingSystem { + + /** + * The {@link OperatingSystem operating system} that must be active. + * @return the expected operating system + */ + OperatingSystem value(); + +} diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/OnOperationSystemCondition.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/OnOperationSystemCondition.java new file mode 100644 index 00000000000..3fb63ea8bf1 --- /dev/null +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/OnOperationSystemCondition.java @@ -0,0 +1,49 @@ +/* + * ApplicationInsights-Java + * Copyright (c) Microsoft Corporation + * All rights reserved. + * + * MIT License + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the ""Software""), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package com.microsoft.applicationinsights.boot.conditional; + +import com.microsoft.applicationinsights.internal.system.SystemInformation; +import org.springframework.boot.autoconfigure.condition.ConditionMessage; +import org.springframework.boot.autoconfigure.condition.ConditionOutcome; +import org.springframework.boot.autoconfigure.condition.SpringBootCondition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.type.AnnotatedTypeMetadata; + +import java.util.Map; + +public class OnOperationSystemCondition extends SpringBootCondition { + + @Override + public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { + Map attributes = metadata.getAnnotationAttributes(ConditionalOnOperatingSystem.class.getName()); + OperatingSystem operatingSystem = (OperatingSystem) attributes.get("value"); + ConditionMessage.Builder message = ConditionMessage.forCondition(ConditionalOnOperatingSystem.class); + String name = operatingSystem.name(); + if (operatingSystem == OperatingSystem.WINDOWS && SystemInformation.INSTANCE.isWindows()) { + return ConditionOutcome.match(message.foundExactly(name)); + } + if (operatingSystem == OperatingSystem.UNIX && SystemInformation.INSTANCE.isUnix()) { + return ConditionOutcome.match(message.foundExactly(name)); + } + return ConditionOutcome.noMatch(message.didNotFind(name).atAll()); + } +} diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/OperatingSystem.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/OperatingSystem.java new file mode 100644 index 00000000000..12a2c36a922 --- /dev/null +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/OperatingSystem.java @@ -0,0 +1,27 @@ +/* + * ApplicationInsights-Java + * Copyright (c) Microsoft Corporation + * All rights reserved. + * + * MIT License + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the ""Software""), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package com.microsoft.applicationinsights.boot.conditional; + +public enum OperatingSystem { + WINDOWS, + UNIX +} diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/SpringBootContextInitializer.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/SpringBootContextInitializer.java new file mode 100644 index 00000000000..68bafe55362 --- /dev/null +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/SpringBootContextInitializer.java @@ -0,0 +1,50 @@ +/* + * ApplicationInsights-Java + * Copyright (c) Microsoft Corporation + * All rights reserved. + * + * MIT License + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the ""Software""), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package com.microsoft.applicationinsights.boot.initializer; + +import com.microsoft.applicationinsights.extensibility.ContextInitializer; +import com.microsoft.applicationinsights.extensibility.context.ContextTagKeys; +import com.microsoft.applicationinsights.telemetry.TelemetryContext; +import org.springframework.boot.SpringBootVersion; +import org.springframework.boot.bind.RelaxedPropertyResolver; +import org.springframework.core.SpringVersion; +import org.springframework.core.env.Environment; + +public class SpringBootContextInitializer implements ContextInitializer { + private final Environment environment; + + public SpringBootContextInitializer(Environment environment) { + this.environment = environment; + } + + @Override + public void initialize(TelemetryContext telemetryContext) { + RelaxedPropertyResolver relaxedPropertyResolver = new RelaxedPropertyResolver(environment); + telemetryContext.getTags().put("ai.spring-boot.version", SpringBootVersion.getVersion()); + telemetryContext.getTags().put("ai.spring.version", SpringVersion.getVersion()); + String ipAddress = relaxedPropertyResolver.getProperty("spring.cloud.client.ipAddress"); + if (ipAddress != null) { + // if spring-cloud is available we can set ip address + telemetryContext.getTags().put(ContextTagKeys.getKeys().getLocationIP(), ipAddress); + } + } +} diff --git a/azure-application-insights-spring-boot-starter/src/main/resources/META-INF/spring.factories b/azure-application-insights-spring-boot-starter/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000000..bfbc19b901b --- /dev/null +++ b/azure-application-insights-spring-boot-starter/src/main/resources/META-INF/spring.factories @@ -0,0 +1,22 @@ +# ApplicationInsights-Java +# Copyright (c) Microsoft Corporation +# All rights reserved. +# +# MIT License +# Permission is hereby granted, free of charge, to any person obtaining a copy of this +# software and associated documentation files (the ""Software""), to deal in the Software +# without restriction, including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, and to permit +# persons to whom the Software is furnished to do so, subject to the following conditions: +# The above copyright notice and this permission notice shall be included in all copies or +# substantial portions of the Software. +# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +# FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.microsoft.applicationinsights.boot.ApplicationInsightsTelemetryAutoConfiguration,\ +com.microsoft.applicationinsights.boot.ApplicationInsightsWebMvcAutoConfiguration \ No newline at end of file diff --git a/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java b/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java new file mode 100644 index 00000000000..5293c76f3dc --- /dev/null +++ b/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java @@ -0,0 +1,211 @@ +/* + * ApplicationInsights-Java + * Copyright (c) Microsoft Corporation + * All rights reserved. + * + * MIT License + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the ""Software""), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package com.microsoft.applicationinsights.boot; + +import com.microsoft.applicationinsights.TelemetryClient; +import com.microsoft.applicationinsights.TelemetryConfiguration; +import com.microsoft.applicationinsights.channel.TelemetryChannel; +import com.microsoft.applicationinsights.channel.concrete.inprocess.InProcessTelemetryChannel; +import com.microsoft.applicationinsights.extensibility.ContextInitializer; +import com.microsoft.applicationinsights.extensibility.TelemetryInitializer; +import com.microsoft.applicationinsights.extensibility.TelemetryModule; +import com.microsoft.applicationinsights.extensibility.TelemetryProcessor; +import com.microsoft.applicationinsights.telemetry.EventTelemetry; +import com.microsoft.applicationinsights.telemetry.Telemetry; +import com.microsoft.applicationinsights.telemetry.TelemetryContext; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.test.util.EnvironmentTestUtils; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +class ApplicationInsightsTelemetryAutoConfigurationTests { + + private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + + @AfterEach + public void restore() { + context.close(); + } + + @Test + void shouldSetInstrumentationKeyWhenContextLoads() { + EnvironmentTestUtils.addEnvironment(context, + "azure.application-insights.instrumentation-key: 00000000-0000-0000-0000-000000000000"); + context.register(PropertyPlaceholderAutoConfiguration.class, + ApplicationInsightsTelemetryAutoConfiguration.class); + context.refresh(); + + TelemetryClient telemetryClient = context.getBean(TelemetryClient.class); + TelemetryConfiguration telemetryConfiguration = context.getBean(TelemetryConfiguration.class); + + assertThat(telemetryConfiguration).isSameAs(TelemetryConfiguration.getActive()); + assertThat(telemetryConfiguration.getInstrumentationKey()).isEqualTo("00000000-0000-0000-0000-000000000000"); + assertThat(telemetryClient.getContext().getInstrumentationKey()).isEqualTo("00000000-0000-0000-0000-000000000000"); + } + + @Test + void shouldSetInstrumentationKeyFromRelaxedCase() { + EnvironmentTestUtils.addEnvironment(context, + "AZURE.APPLICATION_INSIGHTS.INSTRUMENTATION_KEY: 00000000-0000-0000-0000-000000000000"); + context.register(PropertyPlaceholderAutoConfiguration.class, + ApplicationInsightsTelemetryAutoConfiguration.class); + context.refresh(); + + TelemetryClient telemetryClient = context.getBean(TelemetryClient.class); + TelemetryConfiguration telemetryConfiguration = context.getBean(TelemetryConfiguration.class); + + assertThat(telemetryConfiguration).isSameAs(TelemetryConfiguration.getActive()); + assertThat(telemetryConfiguration.getInstrumentationKey()).isEqualTo("00000000-0000-0000-0000-000000000000"); + assertThat(telemetryClient.getContext().getInstrumentationKey()).isEqualTo("00000000-0000-0000-0000-000000000000"); + } + + @Test + void shouldReloadInstrumentationKeyOnTelemetryClient() { + TelemetryClient myClient = new TelemetryClient(); + + EventTelemetry eventTelemetry1 = new EventTelemetry("test1"); + myClient.trackEvent(eventTelemetry1); + assertThat(eventTelemetry1.getTimestamp()).isNull(); + + EnvironmentTestUtils.addEnvironment(context, + "azure.application-insights.instrumentation-key: 00000000-0000-0000-0000-000000000000"); + context.register(PropertyPlaceholderAutoConfiguration.class, + ApplicationInsightsTelemetryAutoConfiguration.class); + context.refresh(); + + EventTelemetry eventTelemetry2 = new EventTelemetry("test2"); + myClient.trackEvent(eventTelemetry2); + assertThat(eventTelemetry2.getTimestamp()).describedAs("Expecting telemetry event to be sent").isNotNull(); + } + + @Test + void shouldNotFailIfInstrumentationKeyIsNotSet() { + context.register(PropertyPlaceholderAutoConfiguration.class, + ApplicationInsightsTelemetryAutoConfiguration.class); + context.refresh(); + + assertThat(context.getBeansOfType(TelemetryClient.class)).isEmpty(); + assertThat(context.getBeansOfType(TelemetryConfiguration.class)).isEmpty(); + } + + @Test + void shouldNotBeAbleToDisableInstrumentationByProperty() { + EnvironmentTestUtils.addEnvironment(context, + "azure.application-insights.enabled: false", + "azure.application-insights.instrumentation-key: 00000000-0000-0000-0000-000000000000"); + context.register(PropertyPlaceholderAutoConfiguration.class, + ApplicationInsightsTelemetryAutoConfiguration.class); + context.refresh(); + + assertThat(context.getBeansOfType(TelemetryClient.class)).isEmpty(); + assertThat(context.getBeansOfType(TelemetryConfiguration.class)).isEmpty(); + } + + @Test + void shouldBeAbleToConfigureTelemetryChannel() { + EnvironmentTestUtils.addEnvironment(context, + "azure.application-insights.instrumentation-key: 00000000-0000-0000-0000-000000000000", + "azure.application-insights.channel.in-process.developer-mode=false", + "azure.application-insights.channel.in-process.flush-interval-in-seconds=123", + "azure.application-insights.channel.in-process.max-telemetry-buffer-capacity=10"); + context.register(PropertyPlaceholderAutoConfiguration.class, + ApplicationInsightsTelemetryAutoConfiguration.class); + context.refresh(); + + TelemetryConfiguration telemetryConfiguration = context.getBean(TelemetryConfiguration.class); + TelemetryChannel channel = telemetryConfiguration.getChannel(); + + assertThat(channel).isInstanceOf(InProcessTelemetryChannel.class); + assertThat(channel.isDeveloperMode()).isFalse(); + assertThat(channel).extracting("telemetryBuffer").extracting("transmitBufferTimeoutInSeconds").contains(123); + assertThat(channel).extracting("telemetryBuffer").extracting("maxTelemetriesInBatch").contains(10); + } + + @Test + void shouldBeAbleToAddCustomModules() { + EnvironmentTestUtils.addEnvironment(context, + "azure.application-insights.instrumentation-key: 00000000-0000-0000-0000-000000000000"); + context.register(PropertyPlaceholderAutoConfiguration.class, + ApplicationInsightsTelemetryAutoConfiguration.class, + CustomModuleConfiguration.class); + context.refresh(); + + TelemetryConfiguration telemetryConfiguration = context.getBean(TelemetryConfiguration.class); + + ContextInitializer myContextInitializer = context.getBean("myContextInitializer", ContextInitializer.class); + TelemetryInitializer myTelemetryInitializer = context.getBean("myTelemetryInitializer", TelemetryInitializer.class); + TelemetryModule myTelemetryModule = context.getBean("myTelemetryModule", TelemetryModule.class); + TelemetryProcessor myTelemetryProcessor = context.getBean("myTelemetryProcessor", TelemetryProcessor.class); + + assertThat(telemetryConfiguration.getContextInitializers()).contains(myContextInitializer); + assertThat(telemetryConfiguration.getTelemetryInitializers()).contains(myTelemetryInitializer); + assertThat(telemetryConfiguration.getTelemetryModules()).contains(myTelemetryModule); + assertThat(telemetryConfiguration.getTelemetryProcessors()).contains(myTelemetryProcessor); + } + + private static class CustomModuleConfiguration { + + @Bean + public ContextInitializer myContextInitializer() { + return new ContextInitializer() { + @Override + public void initialize(TelemetryContext context) { + } + }; + } + + @Bean + public TelemetryInitializer myTelemetryInitializer() { + return new TelemetryInitializer() { + @Override + public void initialize(Telemetry telemetry) { + } + }; + } + + @Bean + public TelemetryModule myTelemetryModule() { + return new TelemetryModule() { + @Override + public void initialize(TelemetryConfiguration configuration) { + } + }; + } + + @Bean + public TelemetryProcessor myTelemetryProcessor() { + return new TelemetryProcessor() { + @Override + public boolean process(Telemetry telemetry) { + return true; + } + }; + } + } +} \ No newline at end of file diff --git a/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfigurationTests.java b/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfigurationTests.java new file mode 100644 index 00000000000..63398da5c4c --- /dev/null +++ b/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfigurationTests.java @@ -0,0 +1,76 @@ +/* + * ApplicationInsights-Java + * Copyright (c) Microsoft Corporation + * All rights reserved. + * + * MIT License + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the ""Software""), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package com.microsoft.applicationinsights.boot; + +import com.microsoft.applicationinsights.internal.quickpulse.QuickPulse; +import com.microsoft.applicationinsights.web.internal.WebRequestTrackingFilter; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration; +import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration; +import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration; +import org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration; +import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration; +import org.springframework.boot.test.autoconfigure.web.servlet.MockMvcAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest( + properties = { + "spring.test.mockmvc: true", + "spring.application.name: test-application", + "azure.application-insights.instrumentation-key: 00000000-0000-0000-0000-000000000000" + }, + classes = { + EmbeddedServletContainerAutoConfiguration.class, + ServerPropertiesAutoConfiguration.class, + DispatcherServletAutoConfiguration.class, + HttpMessageConvertersAutoConfiguration.class, + WebMvcAutoConfiguration.class, + MockMvcAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class, + ApplicationInsightsTelemetryAutoConfiguration.class, + ApplicationInsightsWebMvcAutoConfiguration.class + }, + webEnvironment = WebEnvironment.RANDOM_PORT +) +@RunWith(SpringRunner.class) +public class ApplicationInsightsWebMvcAutoConfigurationTests { + + @Autowired + private ApplicationContext context; + + @Test + public void shouldRegisterWebRequestTrackingFilter() { + WebRequestTrackingFilter webRequestTrackingFilter = context.getBean(WebRequestTrackingFilter.class); + + assertThat(webRequestTrackingFilter).extracting("appName").contains("test-application"); + assertThat(QuickPulse.INSTANCE).extracting("initialized").contains(true); + } + +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 310829bd557..5a6969b825a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -26,6 +26,7 @@ include 'logging:log4j1_2' include 'logging:log4j2' include 'logging:logback' include 'web' +include 'azure-application-insights-spring-boot-starter' include 'distributions' include 'samples' include 'test:performance' From dd97415de08e7a00f5cb8fc28b5c102bdd8862e5 Mon Sep 17 00:00:00 2001 From: Arthur Gavlyukovskiy Date: Sat, 17 Feb 2018 01:58:15 +0200 Subject: [PATCH 02/43] Added a way to disable default modules, added documentation and readme --- .../README.md | 135 ++++++++++++++++++ .../build.gradle | 4 - ...pplicationInsightsModuleConfiguration.java | 10 ++ .../boot/ApplicationInsightsProperties.java | 124 ++++------------ ...ionInsightsTelemetryAutoConfiguration.java | 31 +--- ...icationInsightsWebModuleConfiguration.java | 18 +++ ...cationInsightsWebMvcAutoConfiguration.java | 20 +-- .../ConditionalOnOperatingSystem.java | 5 + .../OnOperationSystemCondition.java | 6 + .../boot/conditional/OperatingSystem.java | 5 + .../SpringBootContextInitializer.java | 5 + ...itional-spring-configuration-metadata.json | 64 +++++++++ ...sightsTelemetryAutoConfigurationTests.java | 3 + ...nInsightsWebMvcAutoConfigurationTests.java | 3 + 14 files changed, 289 insertions(+), 144 deletions(-) create mode 100644 azure-application-insights-spring-boot-starter/README.md create mode 100644 azure-application-insights-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json diff --git a/azure-application-insights-spring-boot-starter/README.md b/azure-application-insights-spring-boot-starter/README.md new file mode 100644 index 00000000000..9854c188bf0 --- /dev/null +++ b/azure-application-insights-spring-boot-starter/README.md @@ -0,0 +1,135 @@ + +**Application Insights Spring Boot Starter** + +This Starter provides you the minimal and required configuration to use Application Insights in your Spring Boot application. + +**Requirements** +Spring Boot 1.5+ or 2.0+ + +**Quick Start** + +*1. Add dependency* +Gradle: +```groovy +compile "com.microsoft.azure:azure-application-insights-spring-boot-starter:${version}" +``` + +Maven: +```xml + + com.microsoft.azure + azure-application-insights-spring-boot-starter + ${version} + +``` + +*2. Provide Instrumentation Key* + +Add property +``` +azure.application-insights.instrumentation-key= +``` +into your `application.properties` + +*3. Run your application* + +Start your spring boot application as usual and in few minutes you'll start getting events. + +**Additional Configuration** + +Sending custom telemetry: +```java +@RestController +public class TelemetryController { + + @Autowired + private TelemetryClient telemetryClient; + + @RequestMapping("/telemetry") + public void telemetry() { + telemetryClient.trackEvent("my event"); + } +} +``` + +To configure application to send logs to the application insights, follow the instructions from (Spring Boot logging documentation)[https://docs.spring.io/spring-boot/docs/current/reference/html/howto-logging.html] to configure custom logback or log4j2 appender. +`logback-spring.xml` +```xml + + + + + +``` + +`log4j2.xml`: +```xml + + + + + + + + + + +``` + +You can register own telemetry module, processor or initializer by defining it as a bean in your configuration: +```java +@SpringBootApplication +public class MyApplication { + + public static void main(String[] args) { + SpringApplication.run(MyApplication.class, args); + } + + @Bean + public TelemetryModule myTelemetryModule() { + return new MyTelemetryModule(); + } + + @Bean + public TelemetryInitializer myTelemetryInitializer() { + return new MyTelemetryInitializer(); + } + + @Bean + public TelemetryProcessor myTelemetryProcessor() { + return new MyTelemetryProcessor(); + } + + @Bean + public ContextInitializer myContextInitializer() { + return new MyContextInitializer(); + } +} +``` + +Configure more parameters using `application.properties`: +```properties +# Enable/Disable tracking +azure.application-insights.enabled=true + +# Instrumentation key from the Azure Portal +azure.application-insights.instrumentation-key=00000000-0000-0000-0000-000000000000 + +# Logging type [console, file] +azure.application-insights.logger.type=console +# Logging level [all, trace, info, warn, error, off] +azure.application-insights.logger.level=info + +# Enable/Disable default telemetry modules +azure.application-insights.default-modules.ProcessPerformanceCountersModule.enabled=true +azure.application-insights.default-modules.WebRequestTrackingTelemetryModule.enabled=true +azure.application-insights.default-modules.WebSessionTrackingTelemetryModule.enabled=true +azure.application-insights.default-modules.WebUserTrackingTelemetryModule.enabled=true +azure.application-insights.default-modules.WebPerformanceCounterModule.enabled=true +azure.application-insights.default-modules.WebOperationIdTelemetryInitializer.enabled=true +azure.application-insights.default-modules.WebOperationNameTelemetryInitializer.enabled=true +azure.application-insights.default-modules.WebSessionTelemetryInitializer.enabled=true +azure.application-insights.default-modules.WebUserTelemetryInitializer.enabled=true +azure.application-insights.default-modules.WebUserAgentTelemetryInitializer.enabled=true +``` diff --git a/azure-application-insights-spring-boot-starter/build.gradle b/azure-application-insights-spring-boot-starter/build.gradle index ed452796e26..f75570f5923 100644 --- a/azure-application-insights-spring-boot-starter/build.gradle +++ b/azure-application-insights-spring-boot-starter/build.gradle @@ -39,10 +39,6 @@ dependencies { testCompile('org.assertj:assertj-core:3.9.0') } -jar { - enabled = false -} - // region Publishing properties projectPomName = project.msftAppInsightsJavaSdk + " Spring Boot starter" diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java index b186e422fa6..4e60aadee6b 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java @@ -21,17 +21,26 @@ package com.microsoft.applicationinsights.boot; +import com.microsoft.applicationinsights.TelemetryConfiguration; import com.microsoft.applicationinsights.boot.conditional.ConditionalOnOperatingSystem; import com.microsoft.applicationinsights.boot.conditional.OperatingSystem; import com.microsoft.applicationinsights.boot.initializer.SpringBootContextInitializer; import com.microsoft.applicationinsights.extensibility.initializer.DeviceInfoContextInitializer; import com.microsoft.applicationinsights.extensibility.initializer.SdkVersionContextInitializer; import com.microsoft.applicationinsights.internal.perfcounter.ProcessPerformanceCountersModule; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; +/** + * {@link Configuration} for non-web applications. + * + * @author Arthur Gavlyukovskiy + */ @Configuration +@ConditionalOnBean(TelemetryConfiguration.class) public class ApplicationInsightsModuleConfiguration { @Bean @@ -51,6 +60,7 @@ public DeviceInfoContextInitializer deviceInfoContextInitializer() { @Bean @ConditionalOnOperatingSystem(OperatingSystem.WINDOWS) + @ConditionalOnProperty(value = "azure.application-insights.default-modules.ProcessPerformanceCountersModule.enabled", havingValue = "true", matchIfMissing = true) public ProcessPerformanceCountersModule processPerformanceCountersModule() { try { return new ProcessPerformanceCountersModule(); diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java index e1674648a80..f8df40c2242 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java @@ -21,18 +21,33 @@ package com.microsoft.applicationinsights.boot; -import com.microsoft.applicationinsights.channel.TelemetryChannel; +import com.microsoft.applicationinsights.extensibility.TelemetryModule; import com.microsoft.applicationinsights.internal.logger.InternalLogger.LoggerOutputType; import com.microsoft.applicationinsights.internal.logger.InternalLogger.LoggingLevel; import org.springframework.boot.context.properties.ConfigurationProperties; +import java.util.HashMap; +import java.util.Map; + +/** + * {@link ConfigurationProperties} for configuring application insights. + * + * @author Arthur Gavlyukovskiy + */ @ConfigurationProperties("azure.application-insights") public class ApplicationInsightsProperties { + /** + * Enables application insights auto-configuration. + */ private boolean enabled = true; + /** + * Instrumentation key from Azure Portal. + */ private String instrumentationKey; - private Channel channel = new Channel(); - private QuickPulse quickPulse = new QuickPulse(); + /** + * Logger properties. + */ private Logger logger = new Logger(); public boolean isEnabled() { @@ -51,22 +66,6 @@ public void setInstrumentationKey(String instrumentationKey) { this.instrumentationKey = instrumentationKey; } - public Channel getChannel() { - return channel; - } - - public void setChannel(Channel channel) { - this.channel = channel; - } - - public QuickPulse getQuickPulse() { - return quickPulse; - } - - public void setQuickPulse(QuickPulse quickPulse) { - this.quickPulse = quickPulse; - } - public Logger getLogger() { return logger; } @@ -75,89 +74,14 @@ public void setLogger(Logger logger) { this.logger = logger; } - public static class QuickPulse { - private boolean enabled = true; - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - } - - public static class Channel { - private InProcess inProcess = new InProcess(); - - public InProcess getInProcess() { - return inProcess; - } - - public void setInProcess(InProcess inProcess) { - this.inProcess = inProcess; - } - - public static class InProcess { - private boolean developerMode = false; - private String endpointAddress; - private int maxTelemetryBufferCapacity; - private int flushIntervalInSeconds; - private int maxTransmissionStorageFilesCapacityInMb; - private boolean throttling = true; - - public boolean isDeveloperMode() { - return developerMode; - } - - public void setDeveloperMode(boolean developerMode) { - this.developerMode = developerMode; - } - - public String getEndpointAddress() { - return endpointAddress; - } - - public void setEndpointAddress(String endpointAddress) { - this.endpointAddress = endpointAddress; - } - - public int getMaxTelemetryBufferCapacity() { - return maxTelemetryBufferCapacity; - } - - public void setMaxTelemetryBufferCapacity(int maxTelemetryBufferCapacity) { - this.maxTelemetryBufferCapacity = maxTelemetryBufferCapacity; - } - - public int getFlushIntervalInSeconds() { - return flushIntervalInSeconds; - } - - public void setFlushIntervalInSeconds(int flushIntervalInSeconds) { - this.flushIntervalInSeconds = flushIntervalInSeconds; - } - - public int getMaxTransmissionStorageFilesCapacityInMb() { - return maxTransmissionStorageFilesCapacityInMb; - } - - public void setMaxTransmissionStorageFilesCapacityInMb(int maxTransmissionStorageFilesCapacityInMb) { - this.maxTransmissionStorageFilesCapacityInMb = maxTransmissionStorageFilesCapacityInMb; - } - - public boolean isThrottling() { - return throttling; - } - - public void setThrottling(boolean throttling) { - this.throttling = throttling; - } - } - } - public static class Logger { + /** + * Type of application insights logger. + */ private LoggerOutputType type = LoggerOutputType.CONSOLE; + /** + * Minimal level of application insights logger. + */ private LoggingLevel level = LoggingLevel.INFO; public LoggerOutputType getType() { diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java index caf8abac143..1664db83305 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java @@ -23,7 +23,6 @@ import com.microsoft.applicationinsights.TelemetryClient; import com.microsoft.applicationinsights.TelemetryConfiguration; -import com.microsoft.applicationinsights.boot.ApplicationInsightsTelemetryAutoConfiguration.EnabledAndHasInstrumentationKeyCondition; import com.microsoft.applicationinsights.channel.TelemetryChannel; import com.microsoft.applicationinsights.channel.TelemetrySampler; import com.microsoft.applicationinsights.channel.concrete.inprocess.InProcessTelemetryChannel; @@ -35,13 +34,11 @@ import com.microsoft.applicationinsights.internal.logger.InternalLogger; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.AllNestedConditions; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @@ -52,9 +49,14 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Auto-configuration for application insights. Configures {@link TelemetryConfiguration} + * + * @author Arthur Gavlyukovskiy + */ @Configuration +@ConditionalOnProperty(value = "azure.application-insights.instrumentation-key") @EnableConfigurationProperties(ApplicationInsightsProperties.class) -@Conditional(EnabledAndHasInstrumentationKeyCondition.class) @ConditionalOnClass(TelemetryConfiguration.class) @Import({ ApplicationInsightsModuleConfiguration.class, @@ -126,10 +128,7 @@ public TelemetrySampler telemetrySampler() { @Bean @ConditionalOnMissingBean public TelemetryChannel telemetryChannel(TelemetrySampler telemetrySampler) { - ApplicationInsightsProperties.Channel.InProcess inProcess = applicationInsightsProperties.getChannel().getInProcess(); - InProcessTelemetryChannel telemetryChannel = new InProcessTelemetryChannel(inProcess.getEndpointAddress(), - /*String.valueOf(inProcess.getMaxTransmissionStorageFilesCapacityInMb()),*/ inProcess.isDeveloperMode(), - inProcess.getMaxTelemetryBufferCapacity(), inProcess.getFlushIntervalInSeconds()/*, inProcess.isThrottling()*/); + InProcessTelemetryChannel telemetryChannel = new InProcessTelemetryChannel(); telemetryChannel.setSampler(telemetrySampler); return telemetryChannel; } @@ -142,20 +141,4 @@ public InternalLogger internalLogger() { InternalLogger.INSTANCE.initialize(logger.getType().name(), loggerParameters); return InternalLogger.INSTANCE; } - - static class EnabledAndHasInstrumentationKeyCondition extends AllNestedConditions { - - EnabledAndHasInstrumentationKeyCondition() { - super(ConfigurationPhase.REGISTER_BEAN); - } - - @ConditionalOnProperty(value = "azure.application-insights.enabled", matchIfMissing = true) - static class OnEnabled { - } - - - @ConditionalOnProperty(value = "azure.application-insights.instrumentation-key") - static class OnInstrumentationKeySet { - } - } } diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java index ba02a881bc9..1a59e6e9c8c 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java @@ -21,6 +21,7 @@ package com.microsoft.applicationinsights.boot; +import com.microsoft.applicationinsights.TelemetryConfiguration; import com.microsoft.applicationinsights.web.extensibility.initializers.WebOperationIdTelemetryInitializer; import com.microsoft.applicationinsights.web.extensibility.initializers.WebOperationNameTelemetryInitializer; import com.microsoft.applicationinsights.web.extensibility.initializers.WebSessionTelemetryInitializer; @@ -30,53 +31,70 @@ import com.microsoft.applicationinsights.web.extensibility.modules.WebSessionTrackingTelemetryModule; import com.microsoft.applicationinsights.web.extensibility.modules.WebUserTrackingTelemetryModule; import com.microsoft.applicationinsights.web.internal.perfcounter.WebPerformanceCounterModule; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +/** + * {@link Configuration} for web applications. + * + * @author Arthur Gavlyukovskiy + */ @Configuration +@ConditionalOnBean(TelemetryConfiguration.class) public class ApplicationInsightsWebModuleConfiguration { @Bean + @ConditionalOnProperty(value = "azure.application-insights.default-modules.WebRequestTrackingTelemetryModule.enabled", havingValue = "true", matchIfMissing = true) public WebRequestTrackingTelemetryModule webRequestTrackingTelemetryModule() { return new WebRequestTrackingTelemetryModule(); } @Bean + @ConditionalOnProperty(value = "azure.application-insights.default-modules.WebSessionTrackingTelemetryModule.enabled", havingValue = "true", matchIfMissing = true) public WebSessionTrackingTelemetryModule webSessionTrackingTelemetryModule() { return new WebSessionTrackingTelemetryModule(); } @Bean + @ConditionalOnProperty(value = "azure.application-insights.default-modules.WebUserTrackingTelemetryModule.enabled", havingValue = "true", matchIfMissing = true) public WebUserTrackingTelemetryModule webUserTrackingTelemetryModule() { return new WebUserTrackingTelemetryModule(); } @Bean + @ConditionalOnProperty(value = "azure.application-insights.default-modules.WebPerformanceCounterModule.enabled", havingValue = "true", matchIfMissing = true) public WebPerformanceCounterModule webPerformanceCounterModule() { return new WebPerformanceCounterModule(); } @Bean + @ConditionalOnProperty(value = "azure.application-insights.default-modules.WebOperationIdTelemetryInitializer.enabled", havingValue = "true", matchIfMissing = true) public WebOperationIdTelemetryInitializer webOperationIdTelemetryInitializer() { return new WebOperationIdTelemetryInitializer(); } @Bean + @ConditionalOnProperty(value = "azure.application-insights.default-modules.WebOperationNameTelemetryInitializer.enabled", havingValue = "true", matchIfMissing = true) public WebOperationNameTelemetryInitializer webOperationNameTelemetryInitializer() { return new WebOperationNameTelemetryInitializer(); } @Bean + @ConditionalOnProperty(value = "azure.application-insights.default-modules.WebSessionTelemetryInitializer.enabled", havingValue = "true", matchIfMissing = true) public WebSessionTelemetryInitializer webSessionTelemetryInitializer() { return new WebSessionTelemetryInitializer(); } @Bean + @ConditionalOnProperty(value = "azure.application-insights.default-modules.WebUserTelemetryInitializer.enabled", havingValue = "true", matchIfMissing = true) public WebUserTelemetryInitializer webUserTelemetryInitializer() { return new WebUserTelemetryInitializer(); } @Bean + @ConditionalOnProperty(value = "azure.application-insights.default-modules.WebUserAgentTelemetryInitializer.enabled", havingValue = "true", matchIfMissing = true) public WebUserAgentTelemetryInitializer webUserAgentTelemetryInitializer() { return new WebUserAgentTelemetryInitializer(); } diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java index aa4d2c0d025..e5b0ef094d3 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java @@ -25,16 +25,12 @@ import com.microsoft.applicationinsights.internal.quickpulse.QuickPulse; import com.microsoft.applicationinsights.web.internal.WebRequestTrackingFilter; import com.microsoft.applicationinsights.web.spring.internal.InterceptorRegistry; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; -import org.springframework.boot.context.embedded.EmbeddedWebApplicationContext; import org.springframework.boot.web.servlet.FilterRegistrationBean; -import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @@ -42,9 +38,9 @@ @Configuration @Import(InterceptorRegistry.class) -@AutoConfigureAfter(ApplicationInsightsTelemetryAutoConfiguration.class) @ConditionalOnBean(TelemetryConfiguration.class) @ConditionalOnWebApplication +@AutoConfigureAfter(ApplicationInsightsTelemetryAutoConfiguration.class) public class ApplicationInsightsWebMvcAutoConfiguration { @Bean @@ -59,22 +55,14 @@ public FilterRegistrationBean webRequestTrackingFilterRegistrationBean(WebReques @Bean @ConditionalOnMissingBean - public WebRequestTrackingFilter webRequestTrackingFilter( - ApplicationContext applicationContext, - @Value("${spring.application.name:application}") String applicationName) { - // Spring Boot application is running inside embedded container - if (applicationContext instanceof EmbeddedWebApplicationContext) { - return new WebRequestTrackingFilter(applicationName); - } - else { - return new WebRequestTrackingFilter(); - } + public WebRequestTrackingFilter webRequestTrackingFilter(@Value("${spring.application.name:application}") String applicationName) { + return new WebRequestTrackingFilter(applicationName); } @Bean - @ConditionalOnProperty(value = "azure.application-insights.quick-pulse.enabled", havingValue = "true", matchIfMissing = true) public QuickPulse quickPulse() { QuickPulse.INSTANCE.initialize(); return QuickPulse.INSTANCE; } } + diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/ConditionalOnOperatingSystem.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/ConditionalOnOperatingSystem.java index 813cb97582f..ad267fe2332 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/ConditionalOnOperatingSystem.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/ConditionalOnOperatingSystem.java @@ -29,6 +29,11 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * {@link Conditional} that checks if the application is running on specific operating system. + * + * @author Arthur Gavlyukovskiy + */ @Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/OnOperationSystemCondition.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/OnOperationSystemCondition.java index 3fb63ea8bf1..87209a2679d 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/OnOperationSystemCondition.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/OnOperationSystemCondition.java @@ -25,11 +25,17 @@ import org.springframework.boot.autoconfigure.condition.ConditionMessage; import org.springframework.boot.autoconfigure.condition.ConditionOutcome; import org.springframework.boot.autoconfigure.condition.SpringBootCondition; +import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.type.AnnotatedTypeMetadata; import java.util.Map; +/** + * {@link Condition} that checks if the application is running on specific operating system. + * + * @author Arthur Gavlyukovskiy + */ public class OnOperationSystemCondition extends SpringBootCondition { @Override diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/OperatingSystem.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/OperatingSystem.java index 12a2c36a922..dc898443372 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/OperatingSystem.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/OperatingSystem.java @@ -21,6 +21,11 @@ package com.microsoft.applicationinsights.boot.conditional; +/** + * List of available for operating system for condition. + * + * @author Arthur Gavlyukovskiy + */ public enum OperatingSystem { WINDOWS, UNIX diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/SpringBootContextInitializer.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/SpringBootContextInitializer.java index 68bafe55362..72aed517ea3 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/SpringBootContextInitializer.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/SpringBootContextInitializer.java @@ -29,6 +29,11 @@ import org.springframework.core.SpringVersion; import org.springframework.core.env.Environment; +/** + * Context initializer that adds information regarding spring and spring boot version. + * + * @author Arthur Gavlyukovskiy + */ public class SpringBootContextInitializer implements ContextInitializer { private final Environment environment; diff --git a/azure-application-insights-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/azure-application-insights-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 00000000000..6b82884dbd7 --- /dev/null +++ b/azure-application-insights-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,64 @@ +{ + "properties": [ + { + "name": "azure.application-insights.default-modules.ProcessPerformanceCountersModule.enabled", + "type": "java.lang.Boolean", + "description": "Enable ProcessPerformanceCountersModule.", + "defaultValue": "true" + }, + { + "name": "azure.application-insights.default-modules.WebRequestTrackingTelemetryModule.enabled", + "type": "java.lang.Boolean", + "description": "Enable WebRequestTrackingTelemetryModule.", + "defaultValue": "true" + }, + { + "name": "azure.application-insights.default-modules.WebSessionTrackingTelemetryModule.enabled", + "type": "java.lang.Boolean", + "description": "Enable WebSessionTrackingTelemetryModule.", + "defaultValue": "true" + }, + { + "name": "azure.application-insights.default-modules.WebUserTrackingTelemetryModule.enabled", + "type": "java.lang.Boolean", + "description": "Enable WebUserTrackingTelemetryModule.", + "defaultValue": "true" + }, + { + "name": "azure.application-insights.default-modules.WebPerformanceCounterModule.enabled", + "type": "java.lang.Boolean", + "description": "Enable WebPerformanceCounterModule.", + "defaultValue": "true" + }, + { + "name": "azure.application-insights.default-modules.WebOperationIdTelemetryInitializer.enabled", + "type": "java.lang.Boolean", + "description": "Enable WebOperationIdTelemetryInitializer.", + "defaultValue": "true" + }, + { + "name": "azure.application-insights.default-modules.WebOperationNameTelemetryInitializer.enabled", + "type": "java.lang.Boolean", + "description": "Enable WebOperationNameTelemetryInitializer.", + "defaultValue": "true" + }, + { + "name": "azure.application-insights.default-modules.WebSessionTelemetryInitializer.enabled", + "type": "java.lang.Boolean", + "description": "Enable WebSessionTelemetryInitializer.", + "defaultValue": "true" + }, + { + "name": "azure.application-insights.default-modules.WebUserTelemetryInitializer.enabled", + "type": "java.lang.Boolean", + "description": "Enable WebUserTelemetryInitializer.", + "defaultValue": "true" + }, + { + "name": "azure.application-insights.default-modules.WebUserAgentTelemetryInitializer.enabled", + "type": "java.lang.Boolean", + "description": "Enable WebUserAgentTelemetryInitializer.", + "defaultValue": "true" + } + ] +} \ No newline at end of file diff --git a/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java b/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java index 5293c76f3dc..31bb23500f2 100644 --- a/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java +++ b/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java @@ -44,6 +44,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; +/** + * @author Arthur Gavlyukovskiy + */ class ApplicationInsightsTelemetryAutoConfigurationTests { private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); diff --git a/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfigurationTests.java b/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfigurationTests.java index 63398da5c4c..51e30786fd5 100644 --- a/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfigurationTests.java +++ b/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfigurationTests.java @@ -40,6 +40,9 @@ import static org.assertj.core.api.Assertions.assertThat; +/** + * @author Arthur Gavlyukovskiy + */ @SpringBootTest( properties = { "spring.test.mockmvc: true", From cce54ae17287c51740335a02df970e184ccf4aa9 Mon Sep 17 00:00:00 2001 From: Arthur Gavlyukovskiy Date: Sat, 17 Feb 2018 02:08:59 +0200 Subject: [PATCH 03/43] Polish readme --- .../README.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/azure-application-insights-spring-boot-starter/README.md b/azure-application-insights-spring-boot-starter/README.md index 9854c188bf0..259f1160ce9 100644 --- a/azure-application-insights-spring-boot-starter/README.md +++ b/azure-application-insights-spring-boot-starter/README.md @@ -37,7 +37,7 @@ Start your spring boot application as usual and in few minutes you'll start gett **Additional Configuration** -Sending custom telemetry: +#### Sending custom telemetry ```java @RestController public class TelemetryController { @@ -52,8 +52,12 @@ public class TelemetryController { } ``` -To configure application to send logs to the application insights, follow the instructions from (Spring Boot logging documentation)[https://docs.spring.io/spring-boot/docs/current/reference/html/howto-logging.html] to configure custom logback or log4j2 appender. -`logback-spring.xml` + +#### Sending logs to the application insight + +Follow the instructions from [Spring Boot logging documentation](https://docs.spring.io/spring-boot/docs/current/reference/html/howto-logging.html) to configure custom logback or log4j2 appender. + +`logback-spring.xml`: ```xml @@ -77,7 +81,7 @@ To configure application to send logs to the application insights, follow the in ``` -You can register own telemetry module, processor or initializer by defining it as a bean in your configuration: +#### Register own telemetry module, processor or initializer by defining it as a bean in the configuration ```java @SpringBootApplication public class MyApplication { @@ -108,7 +112,8 @@ public class MyApplication { } ``` -Configure more parameters using `application.properties`: + +#### Configure more parameters using `application.properties` ```properties # Enable/Disable tracking azure.application-insights.enabled=true From 946f04a047954a74a6587c52c74a3c92166f8088 Mon Sep 17 00:00:00 2001 From: Arthur Gavlyukovskiy Date: Wed, 21 Feb 2018 00:24:26 +0200 Subject: [PATCH 04/43] Added properties to disable quick pulse integration, all web modules; Clarified all default values in readme; Changed default logging level to error; Added @ConditionalOnWebApplication for web configurations. --- .../README.md | 17 ++-- .../boot/ApplicationInsightsProperties.java | 83 +++++++++++++++++-- ...ionInsightsTelemetryAutoConfiguration.java | 8 ++ ...icationInsightsWebModuleConfiguration.java | 3 + ...cationInsightsWebMvcAutoConfiguration.java | 9 +- 5 files changed, 101 insertions(+), 19 deletions(-) diff --git a/azure-application-insights-spring-boot-starter/README.md b/azure-application-insights-spring-boot-starter/README.md index 259f1160ce9..3484ff65d99 100644 --- a/azure-application-insights-spring-boot-starter/README.md +++ b/azure-application-insights-spring-boot-starter/README.md @@ -115,18 +115,21 @@ public class MyApplication { #### Configure more parameters using `application.properties` ```properties -# Enable/Disable tracking +# Instrumentation key from the Azure Portal. Required. +azure.application-insights.instrumentation-key=00000000-0000-0000-0000-000000000000 + +# Enable/Disable tracking. Default value: true. azure.application-insights.enabled=true -# Instrumentation key from the Azure Portal -azure.application-insights.instrumentation-key=00000000-0000-0000-0000-000000000000 +# Enable/Disable web modules. Default value: true. +azure.application-insights.web.enabled=true -# Logging type [console, file] +# Logging type [console, file]. Default value: console. azure.application-insights.logger.type=console -# Logging level [all, trace, info, warn, error, off] -azure.application-insights.logger.level=info +# Logging level [all, trace, info, warn, error, off]. Default value: error. +azure.application-insights.logger.level=error -# Enable/Disable default telemetry modules +# Enable/Disable default telemetry modules. Default value: true. azure.application-insights.default-modules.ProcessPerformanceCountersModule.enabled=true azure.application-insights.default-modules.WebRequestTrackingTelemetryModule.enabled=true azure.application-insights.default-modules.WebSessionTrackingTelemetryModule.enabled=true diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java index f8df40c2242..1c396e3484f 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java @@ -21,14 +21,19 @@ package com.microsoft.applicationinsights.boot; -import com.microsoft.applicationinsights.extensibility.TelemetryModule; import com.microsoft.applicationinsights.internal.logger.InternalLogger.LoggerOutputType; import com.microsoft.applicationinsights.internal.logger.InternalLogger.LoggingLevel; +import com.microsoft.applicationinsights.web.extensibility.initializers.WebOperationIdTelemetryInitializer; +import com.microsoft.applicationinsights.web.extensibility.initializers.WebOperationNameTelemetryInitializer; +import com.microsoft.applicationinsights.web.extensibility.initializers.WebSessionTelemetryInitializer; +import com.microsoft.applicationinsights.web.extensibility.initializers.WebUserAgentTelemetryInitializer; +import com.microsoft.applicationinsights.web.extensibility.initializers.WebUserTelemetryInitializer; +import com.microsoft.applicationinsights.web.extensibility.modules.WebRequestTrackingTelemetryModule; +import com.microsoft.applicationinsights.web.extensibility.modules.WebSessionTrackingTelemetryModule; +import com.microsoft.applicationinsights.web.extensibility.modules.WebUserTrackingTelemetryModule; +import com.microsoft.applicationinsights.web.internal.perfcounter.WebPerformanceCounterModule; import org.springframework.boot.context.properties.ConfigurationProperties; -import java.util.HashMap; -import java.util.Map; - /** * {@link ConfigurationProperties} for configuring application insights. * @@ -45,6 +50,14 @@ public class ApplicationInsightsProperties { * Instrumentation key from Azure Portal. */ private String instrumentationKey; + /** + * Web plugins settings. + */ + private Web web = new Web(); + /** + * Quick Pulse settings. + */ + private QuickPulse quickPulse = new QuickPulse(); /** * Logger properties. */ @@ -66,6 +79,22 @@ public void setInstrumentationKey(String instrumentationKey) { this.instrumentationKey = instrumentationKey; } + public Web getWeb() { + return web; + } + + public void setWeb(Web web) { + this.web = web; + } + + public QuickPulse getQuickPulse() { + return quickPulse; + } + + public void setQuickPulse(QuickPulse quickPulse) { + this.quickPulse = quickPulse; + } + public Logger getLogger() { return logger; } @@ -74,6 +103,50 @@ public void setLogger(Logger logger) { this.logger = logger; } + public static class Web { + /** + * Enables Web telemetry modules. + * + * Implicitly affects modules: + * - {@link WebRequestTrackingTelemetryModule} + * - {@link WebSessionTrackingTelemetryModule} + * - {@link WebUserTrackingTelemetryModule} + * - {@link WebPerformanceCounterModule} + * - {@link WebOperationIdTelemetryInitializer} + * - {@link WebOperationNameTelemetryInitializer} + * - {@link WebSessionTelemetryInitializer} + * - {@link WebUserTelemetryInitializer} + * - {@link WebUserAgentTelemetryInitializer} + * + * False means that all those modules will be disabled + * regardless of the enabled property of concrete module. + */ + private boolean enabled = true; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + } + + public static class QuickPulse { + /** + * Enables Quick Pulse integration. + */ + private boolean enabled = true; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + } + public static class Logger { /** * Type of application insights logger. @@ -82,7 +155,7 @@ public static class Logger { /** * Minimal level of application insights logger. */ - private LoggingLevel level = LoggingLevel.INFO; + private LoggingLevel level = LoggingLevel.ERROR; public LoggerOutputType getType() { return type; diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java index 1664db83305..b8941ea762c 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java @@ -32,6 +32,7 @@ import com.microsoft.applicationinsights.extensibility.TelemetryProcessor; import com.microsoft.applicationinsights.internal.channel.sampling.FixedRateTelemetrySampler; import com.microsoft.applicationinsights.internal.logger.InternalLogger; +import com.microsoft.applicationinsights.internal.quickpulse.QuickPulse; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -133,6 +134,13 @@ public TelemetryChannel telemetryChannel(TelemetrySampler telemetrySampler) { return telemetryChannel; } + @Bean + @ConditionalOnProperty(value = "azure.application-insights.quick-pulse.enabled", havingValue = "true", matchIfMissing = true) + public QuickPulse quickPulse() { + QuickPulse.INSTANCE.initialize(); + return QuickPulse.INSTANCE; + } + @Bean public InternalLogger internalLogger() { Map loggerParameters = new HashMap<>(); diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java index 1a59e6e9c8c..4413f3d7ecc 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java @@ -33,6 +33,7 @@ import com.microsoft.applicationinsights.web.internal.perfcounter.WebPerformanceCounterModule; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -43,6 +44,8 @@ */ @Configuration @ConditionalOnBean(TelemetryConfiguration.class) +@ConditionalOnProperty(value = "azure.application-insights.enabled", havingValue = "true", matchIfMissing = true) +@ConditionalOnWebApplication public class ApplicationInsightsWebModuleConfiguration { @Bean diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java index e5b0ef094d3..5dee8e6396a 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java @@ -22,13 +22,13 @@ package com.microsoft.applicationinsights.boot; import com.microsoft.applicationinsights.TelemetryConfiguration; -import com.microsoft.applicationinsights.internal.quickpulse.QuickPulse; import com.microsoft.applicationinsights.web.internal.WebRequestTrackingFilter; import com.microsoft.applicationinsights.web.spring.internal.InterceptorRegistry; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; @@ -40,6 +40,7 @@ @Import(InterceptorRegistry.class) @ConditionalOnBean(TelemetryConfiguration.class) @ConditionalOnWebApplication +@ConditionalOnProperty(value = "azure.application-insights.enabled", havingValue = "true", matchIfMissing = true) @AutoConfigureAfter(ApplicationInsightsTelemetryAutoConfiguration.class) public class ApplicationInsightsWebMvcAutoConfiguration { @@ -58,11 +59,5 @@ public FilterRegistrationBean webRequestTrackingFilterRegistrationBean(WebReques public WebRequestTrackingFilter webRequestTrackingFilter(@Value("${spring.application.name:application}") String applicationName) { return new WebRequestTrackingFilter(applicationName); } - - @Bean - public QuickPulse quickPulse() { - QuickPulse.INSTANCE.initialize(); - return QuickPulse.INSTANCE; - } } From 91f112b2f8a28f2d8ace1d200c6e63452a5d2fc4 Mon Sep 17 00:00:00 2001 From: Arthur Gavlyukovskiy Date: Wed, 21 Feb 2018 02:11:58 +0200 Subject: [PATCH 05/43] Fixed bean ordering issue --- .../boot/ApplicationInsightsModuleConfiguration.java | 1 - .../boot/ApplicationInsightsWebModuleConfiguration.java | 1 - .../boot/ApplicationInsightsWebMvcAutoConfiguration.java | 4 +++- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java index 4e60aadee6b..745b0ff0209 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java @@ -40,7 +40,6 @@ * @author Arthur Gavlyukovskiy */ @Configuration -@ConditionalOnBean(TelemetryConfiguration.class) public class ApplicationInsightsModuleConfiguration { @Bean diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java index 4413f3d7ecc..6082f7b33f7 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java @@ -43,7 +43,6 @@ * @author Arthur Gavlyukovskiy */ @Configuration -@ConditionalOnBean(TelemetryConfiguration.class) @ConditionalOnProperty(value = "azure.application-insights.enabled", havingValue = "true", matchIfMissing = true) @ConditionalOnWebApplication public class ApplicationInsightsWebModuleConfiguration { diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java index 5dee8e6396a..0cf60464e64 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java @@ -56,7 +56,9 @@ public FilterRegistrationBean webRequestTrackingFilterRegistrationBean(WebReques @Bean @ConditionalOnMissingBean - public WebRequestTrackingFilter webRequestTrackingFilter(@Value("${spring.application.name:application}") String applicationName) { + public WebRequestTrackingFilter webRequestTrackingFilter(@Value("${spring.application.name:application}") String applicationName, + // we have implicit dependency on configured telemetryConfiguration here + @SuppressWarnings("unused") TelemetryConfiguration telemetryConfiguration) { return new WebRequestTrackingFilter(applicationName); } } From abeff08e9e30e681eae8d0ccfd7ddcb935989a67 Mon Sep 17 00:00:00 2001 From: Arthur Gavlyukovskiy Date: Sun, 25 Feb 2018 03:07:42 +0200 Subject: [PATCH 06/43] Added properties for channel and new sampler, created TelemetryType enum for property auto complete --- ...pplicationInsightsModuleConfiguration.java | 3 +- .../boot/ApplicationInsightsProperties.java | 133 ++++++++++++++++++ ...ionInsightsTelemetryAutoConfiguration.java | 29 +++- .../inprocess/InProcessTelemetryChannel.java | 11 +- .../FixedRateSamplingTelemetryProcessor.java | 52 +++---- .../channel/samplingV2/TelemetryType.java | 19 +++ 6 files changed, 205 insertions(+), 42 deletions(-) create mode 100644 core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/TelemetryType.java diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java index 745b0ff0209..d130ee2e7a8 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java @@ -65,7 +65,8 @@ public ProcessPerformanceCountersModule processPerformanceCountersModule() { return new ProcessPerformanceCountersModule(); } catch (Exception e) { - throw new IllegalStateException("Could not initialize Windows performance counters module", e); + throw new IllegalStateException("Could not initialize Windows performance counters module, " + + "please set property 'azure.application-insights.default-modules.ProcessPerformanceCountersModule.enabled=false' to avoid this error message.", e); } } } diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java index 1c396e3484f..73ba89c6a53 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java @@ -21,8 +21,10 @@ package com.microsoft.applicationinsights.boot; +import com.microsoft.applicationinsights.internal.channel.samplingV2.TelemetryType; import com.microsoft.applicationinsights.internal.logger.InternalLogger.LoggerOutputType; import com.microsoft.applicationinsights.internal.logger.InternalLogger.LoggingLevel; +import com.microsoft.applicationinsights.telemetry.BaseSampleSourceTelemetry; import com.microsoft.applicationinsights.web.extensibility.initializers.WebOperationIdTelemetryInitializer; import com.microsoft.applicationinsights.web.extensibility.initializers.WebOperationNameTelemetryInitializer; import com.microsoft.applicationinsights.web.extensibility.initializers.WebSessionTelemetryInitializer; @@ -34,6 +36,8 @@ import com.microsoft.applicationinsights.web.internal.perfcounter.WebPerformanceCounterModule; import org.springframework.boot.context.properties.ConfigurationProperties; +import java.util.List; + /** * {@link ConfigurationProperties} for configuring application insights. * @@ -50,6 +54,11 @@ public class ApplicationInsightsProperties { * Instrumentation key from Azure Portal. */ private String instrumentationKey; + /** + * Telemetry transmission channel configuration. + */ + private Channel channel = new Channel(); + private Sampling sampling = new Sampling(); /** * Web plugins settings. */ @@ -79,6 +88,22 @@ public void setInstrumentationKey(String instrumentationKey) { this.instrumentationKey = instrumentationKey; } + public Channel getChannel() { + return channel; + } + + public void setChannel(Channel channel) { + this.channel = channel; + } + + public Sampling getSampling() { + return sampling; + } + + public void setSampling(Sampling sampling) { + this.sampling = sampling; + } + public Web getWeb() { return web; } @@ -103,6 +128,114 @@ public void setLogger(Logger logger) { this.logger = logger; } + public static class Channel { + private InProcess inProcess = new InProcess(); + + public InProcess getInProcess() { + return inProcess; + } + + public void setInProcess(InProcess inProcess) { + this.inProcess = inProcess; + } + + public static class InProcess { + private boolean developerMode = false; + private String endpointAddress; + private int maxTelemetryBufferCapacity; + private int flushIntervalInSeconds; + private int maxTransmissionStorageFilesCapacityInMb; + private boolean throttling = true; + + public boolean isDeveloperMode() { + return developerMode; + } + + public void setDeveloperMode(boolean developerMode) { + this.developerMode = developerMode; + } + + public String getEndpointAddress() { + return endpointAddress; + } + + public void setEndpointAddress(String endpointAddress) { + this.endpointAddress = endpointAddress; + } + + public int getMaxTelemetryBufferCapacity() { + return maxTelemetryBufferCapacity; + } + + public void setMaxTelemetryBufferCapacity(int maxTelemetryBufferCapacity) { + this.maxTelemetryBufferCapacity = maxTelemetryBufferCapacity; + } + + public int getFlushIntervalInSeconds() { + return flushIntervalInSeconds; + } + + public void setFlushIntervalInSeconds(int flushIntervalInSeconds) { + this.flushIntervalInSeconds = flushIntervalInSeconds; + } + + public int getMaxTransmissionStorageFilesCapacityInMb() { + return maxTransmissionStorageFilesCapacityInMb; + } + + public void setMaxTransmissionStorageFilesCapacityInMb(int maxTransmissionStorageFilesCapacityInMb) { + this.maxTransmissionStorageFilesCapacityInMb = maxTransmissionStorageFilesCapacityInMb; + } + + public boolean isThrottling() { + return throttling; + } + + public void setThrottling(boolean throttling) { + this.throttling = throttling; + } + } + } + + public static class Sampling { + /** + * Percent of telemetry events that will be sent to Application Insights. + */ + private double percentage; + /** + * If set only telemetry of specified types will be included. + */ + private List include; + /** + * If set telemetry of specified type will be excluded. + */ + private List exclude; + + public double getPercentage() { + return percentage; + } + + public void setPercentage(double percentage) { + this.percentage = percentage; + } + + public List getInclude() { + return include; + } + + public void setInclude(List include) { + this.include = include; + } + + public List getExclude() { + return exclude; + } + + public void setExclude(List exclude) { + this.exclude = exclude; + } + } + public static class Web { /** * Enables Web telemetry modules. diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java index b8941ea762c..2517db4c632 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java @@ -23,6 +23,9 @@ import com.microsoft.applicationinsights.TelemetryClient; import com.microsoft.applicationinsights.TelemetryConfiguration; +import com.microsoft.applicationinsights.boot.ApplicationInsightsProperties.Channel; +import com.microsoft.applicationinsights.boot.ApplicationInsightsProperties.Channel.InProcess; +import com.microsoft.applicationinsights.boot.ApplicationInsightsProperties.Sampling; import com.microsoft.applicationinsights.channel.TelemetryChannel; import com.microsoft.applicationinsights.channel.TelemetrySampler; import com.microsoft.applicationinsights.channel.concrete.inprocess.InProcessTelemetryChannel; @@ -31,8 +34,11 @@ import com.microsoft.applicationinsights.extensibility.TelemetryModule; import com.microsoft.applicationinsights.extensibility.TelemetryProcessor; import com.microsoft.applicationinsights.internal.channel.sampling.FixedRateTelemetrySampler; +import com.microsoft.applicationinsights.internal.channel.samplingV2.FixedRateSamplingTelemetryProcessor; +import com.microsoft.applicationinsights.internal.channel.samplingV2.TelemetryType; import com.microsoft.applicationinsights.internal.logger.InternalLogger; import com.microsoft.applicationinsights.internal.quickpulse.QuickPulse; +import com.microsoft.applicationinsights.telemetry.BaseSampleSourceTelemetry; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -121,17 +127,26 @@ public TelemetryClient telemetryClient(TelemetryConfiguration configuration) { } @Bean - @ConditionalOnMissingBean - public TelemetrySampler telemetrySampler() { - return new FixedRateTelemetrySampler(); + public FixedRateSamplingTelemetryProcessor fixedRateSamplingTelemetryProcessor() { + Sampling sampling = applicationInsightsProperties.getSampling(); + FixedRateSamplingTelemetryProcessor processor = new FixedRateSamplingTelemetryProcessor(); + processor.setSamplingPercentage(String.valueOf(sampling.getPercentage())); + for (TelemetryType include : sampling.getInclude()) { + processor.addToIncludedType(include.name()); + } + for (TelemetryType exclude : sampling.getExclude()) { + processor.addToExcludedType(exclude.name()); + } + return processor; } @Bean @ConditionalOnMissingBean - public TelemetryChannel telemetryChannel(TelemetrySampler telemetrySampler) { - InProcessTelemetryChannel telemetryChannel = new InProcessTelemetryChannel(); - telemetryChannel.setSampler(telemetrySampler); - return telemetryChannel; + public TelemetryChannel telemetryChannel() { + InProcess inProcess = applicationInsightsProperties.getChannel().getInProcess(); + return new InProcessTelemetryChannel(inProcess.getEndpointAddress(), + String.valueOf(inProcess.getMaxTransmissionStorageFilesCapacityInMb()), inProcess.isDeveloperMode(), + inProcess.getMaxTelemetryBufferCapacity(), inProcess.getFlushIntervalInSeconds(), inProcess.isThrottling()); } @Bean diff --git a/core/src/main/java/com/microsoft/applicationinsights/channel/concrete/inprocess/InProcessTelemetryChannel.java b/core/src/main/java/com/microsoft/applicationinsights/channel/concrete/inprocess/InProcessTelemetryChannel.java index 05bac6d1dbb..481e843de0e 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/channel/concrete/inprocess/InProcessTelemetryChannel.java +++ b/core/src/main/java/com/microsoft/applicationinsights/channel/concrete/inprocess/InProcessTelemetryChannel.java @@ -22,7 +22,6 @@ package com.microsoft.applicationinsights.channel.concrete.inprocess; import java.io.IOException; -import java.io.PrintWriter; import java.io.StringWriter; import java.net.URI; import java.util.Map; @@ -38,7 +37,6 @@ import com.microsoft.applicationinsights.internal.util.LocalStringsUtils; import com.microsoft.applicationinsights.internal.util.Sanitizer; import com.microsoft.applicationinsights.telemetry.JsonTelemetryDataSerializer; -import com.microsoft.applicationinsights.telemetry.SupportSampling; import com.microsoft.applicationinsights.telemetry.Telemetry; import com.microsoft.applicationinsights.channel.TelemetryChannel; @@ -126,12 +124,17 @@ public InProcessTelemetryChannel() { * Note, value should be between MIN_MAX_TELEMETRY_BUFFER_CAPACITY and MAX_MAX_TELEMETRY_BUFFER_CAPACITY inclusive */ public InProcessTelemetryChannel(String endpointAddress, boolean developerMode, int maxTelemetryBufferCapacity, int sendIntervalInMillis) { + this(endpointAddress, null, developerMode, maxTelemetryBufferCapacity, sendIntervalInMillis, true); + } + + public InProcessTelemetryChannel(String endpointAddress, String maxTransmissionStorageCapacity, boolean developerMode, + int maxTelemetryBufferCapacity, int sendIntervalInMillis, boolean throttling) { initialize(endpointAddress, - null, + maxTransmissionStorageCapacity, developerMode, createDefaultMaxTelemetryBufferCapacityEnforcer(maxTelemetryBufferCapacity), createDefaultSendIntervalInSecondsEnforcer(sendIntervalInMillis), - true); + throttling); } /** diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/FixedRateSamplingTelemetryProcessor.java b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/FixedRateSamplingTelemetryProcessor.java index 3ddd4fc53e9..d68e0d46c48 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/FixedRateSamplingTelemetryProcessor.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/FixedRateSamplingTelemetryProcessor.java @@ -3,8 +3,14 @@ import com.microsoft.applicationinsights.extensibility.TelemetryProcessor; import com.microsoft.applicationinsights.internal.annotation.BuiltInProcessor; import com.microsoft.applicationinsights.internal.logger.InternalLogger; +import com.microsoft.applicationinsights.telemetry.EventTelemetry; +import com.microsoft.applicationinsights.telemetry.ExceptionTelemetry; +import com.microsoft.applicationinsights.telemetry.PageViewTelemetry; +import com.microsoft.applicationinsights.telemetry.RemoteDependencyTelemetry; +import com.microsoft.applicationinsights.telemetry.RequestTelemetry; import com.microsoft.applicationinsights.telemetry.SupportSampling; import com.microsoft.applicationinsights.telemetry.Telemetry; +import com.microsoft.applicationinsights.telemetry.TraceTelemetry; import org.apache.commons.lang3.exception.ExceptionUtils; import java.util.HashMap; @@ -39,14 +45,16 @@ @BuiltInProcessor("FixedRateSamplingTelemetryProcessor") public final class FixedRateSamplingTelemetryProcessor implements TelemetryProcessor { - private final String dependencyTelemetryName = "Dependency"; - private static final String eventTelemetryName = "Event"; - private static final String exceptionTelemetryName = "Exception"; - private static final String pageViewTelemetryName = "PageView"; - private static final String requestTelemetryName = "Request"; - private static final String traceTelemetryName = "Trace"; + private static Map allowedTypes = new HashMap<>(); - private static Map allowedTypes; + static { + allowedTypes.put(TelemetryType.Dependency, RemoteDependencyTelemetry.class); + allowedTypes.put(TelemetryType.Event, EventTelemetry.class); + allowedTypes.put(TelemetryType.Exception, ExceptionTelemetry.class); + allowedTypes.put(TelemetryType.PageView, PageViewTelemetry.class); + allowedTypes.put(TelemetryType.Request, RequestTelemetry.class); + allowedTypes.put(TelemetryType.Trace, TraceTelemetry.class); + } private Set excludedTypes; @@ -64,20 +72,8 @@ public final class FixedRateSamplingTelemetryProcessor implements TelemetryProce */ public FixedRateSamplingTelemetryProcessor() { this.samplingPercentage = 100.00; - this.includedTypes = new HashSet(); - this.excludedTypes = new HashSet(); - try { - this.allowedTypes = new HashMap() {{ - put(dependencyTelemetryName, Class.forName("com.microsoft.applicationinsights.telemetry.RemoteDependencyTelemetry")); - put(eventTelemetryName, Class.forName("com.microsoft.applicationinsights.telemetry.EventTelemetry")); - put(exceptionTelemetryName, Class.forName("com.microsoft.applicationinsights.telemetry.ExceptionTelemetry")); - put(pageViewTelemetryName, Class.forName("com.microsoft.applicationinsights.telemetry.PageViewTelemetry")); - put(requestTelemetryName, Class.forName("com.microsoft.applicationinsights.telemetry.RequestTelemetry")); - put(traceTelemetryName, Class.forName("com.microsoft.applicationinsights.telemetry.TraceTelemetry")); - }}; - } catch (ClassNotFoundException e) { - InternalLogger.INSTANCE.trace("Unable to locate telemetry classes. stack trace is %s", ExceptionUtils.getStackTrace(e)); - } + this.includedTypes = new HashSet<>(); + this.excludedTypes = new HashSet<>(); } /** @@ -100,16 +96,12 @@ public Set getIncludedTypes() { private void setIncludedOrExcludedTypes(String value, Set typeSet) { - - if (!StringUtils.isEmpty(value)) { - value = value.trim(); - if (!StringUtils.isEmpty(value) && allowedTypes.containsKey(value)) { - typeSet.add(allowedTypes.get(value)); - } else { - InternalLogger.INSTANCE.error("Item is either not allowed to sample or is empty"); - } + value = value.trim(); + TelemetryType telemetryType = TelemetryType.valueOfOrNull(value); + if (telemetryType != null) { + typeSet.add(allowedTypes.get(telemetryType)); } else { - InternalLogger.INSTANCE.error("Empty types cannot be considered"); + InternalLogger.INSTANCE.error("Telemetry type " + value + " is either not allowed to sample or is empty"); } } diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/TelemetryType.java b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/TelemetryType.java new file mode 100644 index 00000000000..8eea6f8daa9 --- /dev/null +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/TelemetryType.java @@ -0,0 +1,19 @@ +package com.microsoft.applicationinsights.internal.channel.samplingV2; + +public enum TelemetryType { + Dependency, + Event, + Exception, + PageView, + Request, + Trace; + + static TelemetryType valueOfOrNull(String name) { + try { + return valueOf(name); + } + catch (IllegalArgumentException e) { + return null; + } + } +} From e8f688fa1a11e2aaadae8bf99f4fc273538e3cc7 Mon Sep 17 00:00:00 2001 From: Arthur Gavlyukovskiy Date: Sun, 25 Feb 2018 03:29:21 +0200 Subject: [PATCH 07/43] Added documentation to added properties, added default values, updated readme. --- .../README.md | 20 ++++++++++++ .../boot/ApplicationInsightsProperties.java | 31 ++++++++++++++++--- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/azure-application-insights-spring-boot-starter/README.md b/azure-application-insights-spring-boot-starter/README.md index 3484ff65d99..3d83978e05b 100644 --- a/azure-application-insights-spring-boot-starter/README.md +++ b/azure-application-insights-spring-boot-starter/README.md @@ -129,6 +129,26 @@ azure.application-insights.logger.type=console # Logging level [all, trace, info, warn, error, off]. Default value: error. azure.application-insights.logger.level=error +# Enable/Disable developer mode, all telemetry will be sent immediately without batching. Significantly affects performance and should be used only in developer environment. Default value: false. +azure.application-insights.channel.in-process.developer-mode=false +# Endpoint address, Default value: none. +azure.application-insights.channel.in-process.endpoint-address= +# Maximum count of telemetries that will be batched before sending. Default value: 500. +azure.application-insights.channel.in-process.max-telemetry-buffer-capacity=500 +# Interval to send telemetry. Default value: 5 seconds. +azure.application-insights.channel.in-process.flush-interval-in-seconds=5 +# Size of disk that we can use. Default value: 10 megabytes. +azure.application-insights.channel.in-process.max-transmission-storage-files-capacity-in-mb=10 +# Enable/Disable throttling on sending telemetry data. Default value: true. +azure.application-insights.channel.in-process.throttling=true + +# Percent of telemetry events that will be sent to Application Insights. Default value: 100% (all telemetry events). +azure.application-insights.sampling.percentage=100 +# If set only telemetry of specified types will be included. Default value: all telemetries are included; +azure.application-insights.sampling.include= +# If set telemetry of specified type will be excluded. Default value: none telemetries are excluded. +azure.application-insights.sampling.exclude= + # Enable/Disable default telemetry modules. Default value: true. azure.application-insights.default-modules.ProcessPerformanceCountersModule.enabled=true azure.application-insights.default-modules.WebRequestTrackingTelemetryModule.enabled=true diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java index 73ba89c6a53..aee79270907 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java @@ -21,6 +21,7 @@ package com.microsoft.applicationinsights.boot; +import com.microsoft.applicationinsights.channel.concrete.inprocess.InProcessTelemetryChannel; import com.microsoft.applicationinsights.internal.channel.samplingV2.TelemetryType; import com.microsoft.applicationinsights.internal.logger.InternalLogger.LoggerOutputType; import com.microsoft.applicationinsights.internal.logger.InternalLogger.LoggingLevel; @@ -129,6 +130,9 @@ public void setLogger(Logger logger) { } public static class Channel { + /** + * Configuration of {@link InProcessTelemetryChannel}. + */ private InProcess inProcess = new InProcess(); public InProcess getInProcess() { @@ -140,11 +144,30 @@ public void setInProcess(InProcess inProcess) { } public static class InProcess { + /** + * Enables developer mode, all telemetry will be sent immediately without batching. + * Significantly affects performance and should be used only in developer environment. + */ private boolean developerMode = false; + /** + * Endpoint address. + */ private String endpointAddress; - private int maxTelemetryBufferCapacity; - private int flushIntervalInSeconds; - private int maxTransmissionStorageFilesCapacityInMb; + /** + * Maximum count of telemetries that will be batched before sending. + */ + private int maxTelemetryBufferCapacity = 500; + /** + * nterval to send telemetry. + */ + private int flushIntervalInSeconds = 5; + /** + * Size of disk that we can use. + */ + private int maxTransmissionStorageFilesCapacityInMb = 10; + /** + * Enables throttling on sending telemetry data. + */ private boolean throttling = true; public boolean isDeveloperMode() { @@ -201,7 +224,7 @@ public static class Sampling { /** * Percent of telemetry events that will be sent to Application Insights. */ - private double percentage; + private double percentage = 100; /** * If set only telemetry of specified types will be included. */ From ed16e55b6f5fb6469d0c99d8487741e57cf561bf Mon Sep 17 00:00:00 2001 From: Arthur Gavlyukovskiy Date: Tue, 27 Feb 2018 22:21:51 +0200 Subject: [PATCH 08/43] Changed sampling configuration, added more tests for autoconfiguration --- .../README.md | 10 +- .../boot/ApplicationInsightsProperties.java | 91 ++++++++++++------- ...ionInsightsTelemetryAutoConfiguration.java | 8 +- ...sightsTelemetryAutoConfigurationTests.java | 55 +++++++++-- .../InProcessTelemetryChannelTest.java | 7 ++ 5 files changed, 119 insertions(+), 52 deletions(-) diff --git a/azure-application-insights-spring-boot-starter/README.md b/azure-application-insights-spring-boot-starter/README.md index 3d83978e05b..e76201c95eb 100644 --- a/azure-application-insights-spring-boot-starter/README.md +++ b/azure-application-insights-spring-boot-starter/README.md @@ -131,8 +131,8 @@ azure.application-insights.logger.level=error # Enable/Disable developer mode, all telemetry will be sent immediately without batching. Significantly affects performance and should be used only in developer environment. Default value: false. azure.application-insights.channel.in-process.developer-mode=false -# Endpoint address, Default value: none. -azure.application-insights.channel.in-process.endpoint-address= +# Endpoint address, Default value: https://dc.services.visualstudio.com/v2/track. +azure.application-insights.channel.in-process.endpoint-address=https://dc.services.visualstudio.com/v2/track # Maximum count of telemetries that will be batched before sending. Default value: 500. azure.application-insights.channel.in-process.max-telemetry-buffer-capacity=500 # Interval to send telemetry. Default value: 5 seconds. @@ -143,11 +143,11 @@ azure.application-insights.channel.in-process.max-transmission-storage-files-cap azure.application-insights.channel.in-process.throttling=true # Percent of telemetry events that will be sent to Application Insights. Default value: 100% (all telemetry events). -azure.application-insights.sampling.percentage=100 +azure.application-insights.telemetry-processor.sampling.percentage=100 # If set only telemetry of specified types will be included. Default value: all telemetries are included; -azure.application-insights.sampling.include= +azure.application-insights.telemetry-processor.sampling.include= # If set telemetry of specified type will be excluded. Default value: none telemetries are excluded. -azure.application-insights.sampling.exclude= +azure.application-insights.telemetry-processor.sampling.exclude= # Enable/Disable default telemetry modules. Default value: true. azure.application-insights.default-modules.ProcessPerformanceCountersModule.enabled=true diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java index aee79270907..700bd39ec6a 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java @@ -22,6 +22,7 @@ package com.microsoft.applicationinsights.boot; import com.microsoft.applicationinsights.channel.concrete.inprocess.InProcessTelemetryChannel; +import com.microsoft.applicationinsights.internal.channel.samplingV2.FixedRateSamplingTelemetryProcessor; import com.microsoft.applicationinsights.internal.channel.samplingV2.TelemetryType; import com.microsoft.applicationinsights.internal.logger.InternalLogger.LoggerOutputType; import com.microsoft.applicationinsights.internal.logger.InternalLogger.LoggingLevel; @@ -37,6 +38,7 @@ import com.microsoft.applicationinsights.web.internal.perfcounter.WebPerformanceCounterModule; import org.springframework.boot.context.properties.ConfigurationProperties; +import java.util.ArrayList; import java.util.List; /** @@ -59,7 +61,10 @@ public class ApplicationInsightsProperties { * Telemetry transmission channel configuration. */ private Channel channel = new Channel(); - private Sampling sampling = new Sampling(); + /** + * Built in telemetry processors configuration. + */ + private TelemetryProcessor telemetryProcessor = new TelemetryProcessor(); /** * Web plugins settings. */ @@ -97,12 +102,12 @@ public void setChannel(Channel channel) { this.channel = channel; } - public Sampling getSampling() { - return sampling; + public TelemetryProcessor getTelemetryProcessor() { + return telemetryProcessor; } - public void setSampling(Sampling sampling) { - this.sampling = sampling; + public void setTelemetryProcessor(TelemetryProcessor telemetryProcessor) { + this.telemetryProcessor = telemetryProcessor; } public Web getWeb() { @@ -129,7 +134,7 @@ public void setLogger(Logger logger) { this.logger = logger; } - public static class Channel { + static class Channel { /** * Configuration of {@link InProcessTelemetryChannel}. */ @@ -143,7 +148,7 @@ public void setInProcess(InProcess inProcess) { this.inProcess = inProcess; } - public static class InProcess { + static class InProcess { /** * Enables developer mode, all telemetry will be sent immediately without batching. * Significantly affects performance and should be used only in developer environment. @@ -220,46 +225,62 @@ public void setThrottling(boolean throttling) { } } - public static class Sampling { - /** - * Percent of telemetry events that will be sent to Application Insights. - */ - private double percentage = 100; - /** - * If set only telemetry of specified types will be included. - */ - private List include; + static class TelemetryProcessor { + /** - * If set telemetry of specified type will be excluded. + * Configuration of {@link FixedRateSamplingTelemetryProcessor}. */ - private List exclude; + private Sampling sampling = new Sampling(); - public double getPercentage() { - return percentage; + public Sampling getSampling() { + return sampling; } - public void setPercentage(double percentage) { - this.percentage = percentage; + public void setSampling(Sampling sampling) { + this.sampling = sampling; } - public List getInclude() { - return include; - } + static class Sampling { + /** + * Percent of telemetry events that will be sent to Application Insights. + */ + private double percentage = 100; + /** + * If set only telemetry of specified types will be included. + */ + private List include = new ArrayList<>(); + /** + * If set telemetry of specified type will be excluded. + */ + private List exclude = new ArrayList<>(); - public void setInclude(List include) { - this.include = include; - } + public double getPercentage() { + return percentage; + } - public List getExclude() { - return exclude; - } + public void setPercentage(double percentage) { + this.percentage = percentage; + } + + public List getInclude() { + return include; + } + + public void setInclude(List include) { + this.include = include; + } - public void setExclude(List exclude) { - this.exclude = exclude; + public List getExclude() { + return exclude; + } + + public void setExclude(List exclude) { + this.exclude = exclude; + } } } - public static class Web { + static class Web { /** * Enables Web telemetry modules. * @@ -303,7 +324,7 @@ public void setEnabled(boolean enabled) { } } - public static class Logger { + static class Logger { /** * Type of application insights logger. */ diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java index 2517db4c632..bda11d798c3 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java @@ -23,22 +23,18 @@ import com.microsoft.applicationinsights.TelemetryClient; import com.microsoft.applicationinsights.TelemetryConfiguration; -import com.microsoft.applicationinsights.boot.ApplicationInsightsProperties.Channel; import com.microsoft.applicationinsights.boot.ApplicationInsightsProperties.Channel.InProcess; -import com.microsoft.applicationinsights.boot.ApplicationInsightsProperties.Sampling; +import com.microsoft.applicationinsights.boot.ApplicationInsightsProperties.TelemetryProcessor.Sampling; import com.microsoft.applicationinsights.channel.TelemetryChannel; -import com.microsoft.applicationinsights.channel.TelemetrySampler; import com.microsoft.applicationinsights.channel.concrete.inprocess.InProcessTelemetryChannel; import com.microsoft.applicationinsights.extensibility.ContextInitializer; import com.microsoft.applicationinsights.extensibility.TelemetryInitializer; import com.microsoft.applicationinsights.extensibility.TelemetryModule; import com.microsoft.applicationinsights.extensibility.TelemetryProcessor; -import com.microsoft.applicationinsights.internal.channel.sampling.FixedRateTelemetrySampler; import com.microsoft.applicationinsights.internal.channel.samplingV2.FixedRateSamplingTelemetryProcessor; import com.microsoft.applicationinsights.internal.channel.samplingV2.TelemetryType; import com.microsoft.applicationinsights.internal.logger.InternalLogger; import com.microsoft.applicationinsights.internal.quickpulse.QuickPulse; -import com.microsoft.applicationinsights.telemetry.BaseSampleSourceTelemetry; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -128,7 +124,7 @@ public TelemetryClient telemetryClient(TelemetryConfiguration configuration) { @Bean public FixedRateSamplingTelemetryProcessor fixedRateSamplingTelemetryProcessor() { - Sampling sampling = applicationInsightsProperties.getSampling(); + Sampling sampling = applicationInsightsProperties.getTelemetryProcessor().getSampling(); FixedRateSamplingTelemetryProcessor processor = new FixedRateSamplingTelemetryProcessor(); processor.setSamplingPercentage(String.valueOf(sampling.getPercentage())); for (TelemetryType include : sampling.getInclude()) { diff --git a/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java b/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java index 31bb23500f2..1ab196589be 100644 --- a/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java +++ b/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java @@ -29,20 +29,20 @@ import com.microsoft.applicationinsights.extensibility.TelemetryInitializer; import com.microsoft.applicationinsights.extensibility.TelemetryModule; import com.microsoft.applicationinsights.extensibility.TelemetryProcessor; +import com.microsoft.applicationinsights.internal.channel.samplingV2.FixedRateSamplingTelemetryProcessor; import com.microsoft.applicationinsights.telemetry.EventTelemetry; +import com.microsoft.applicationinsights.telemetry.RequestTelemetry; import com.microsoft.applicationinsights.telemetry.Telemetry; import com.microsoft.applicationinsights.telemetry.TelemetryContext; +import com.microsoft.applicationinsights.web.extensibility.modules.WebUserTrackingTelemetryModule; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.test.util.EnvironmentTestUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; /** * @author Arthur Gavlyukovskiy @@ -118,7 +118,7 @@ void shouldNotFailIfInstrumentationKeyIsNotSet() { } @Test - void shouldNotBeAbleToDisableInstrumentationByProperty() { + void shouldBeAbleToDisableInstrumentationByProperty() { EnvironmentTestUtils.addEnvironment(context, "azure.application-insights.enabled: false", "azure.application-insights.instrumentation-key: 00000000-0000-0000-0000-000000000000"); @@ -126,8 +126,8 @@ void shouldNotBeAbleToDisableInstrumentationByProperty() { ApplicationInsightsTelemetryAutoConfiguration.class); context.refresh(); - assertThat(context.getBeansOfType(TelemetryClient.class)).isEmpty(); - assertThat(context.getBeansOfType(TelemetryConfiguration.class)).isEmpty(); + TelemetryConfiguration telemetryConfiguration = context.getBean(TelemetryConfiguration.class); + assertThat(telemetryConfiguration.isTrackingDisabled()).isTrue(); } @Test @@ -150,6 +150,49 @@ void shouldBeAbleToConfigureTelemetryChannel() { assertThat(channel).extracting("telemetryBuffer").extracting("maxTelemetriesInBatch").contains(10); } + @Test + void shouldBeAbleToConfigureSamplingTelemetryProcessor() { + EnvironmentTestUtils.addEnvironment(context, + "azure.application-insights.instrumentation-key: 00000000-0000-0000-0000-000000000000", + "azure.application-insights.telemetry-processor.sampling.percentage=50", + "azure.application-insights.telemetry-processor.sampling.include=Request"); + context.register(PropertyPlaceholderAutoConfiguration.class, + ApplicationInsightsTelemetryAutoConfiguration.class); + context.refresh(); + + TelemetryConfiguration telemetryConfiguration = context.getBean(TelemetryConfiguration.class); + FixedRateSamplingTelemetryProcessor fixedRateSamplingTelemetryProcessor = context.getBean(FixedRateSamplingTelemetryProcessor.class); + + assertThat(telemetryConfiguration.getTelemetryProcessors()).extracting("class").contains(FixedRateSamplingTelemetryProcessor.class); + assertThat(fixedRateSamplingTelemetryProcessor).extracting("samplingPercentage").contains(50.); + assertThat(fixedRateSamplingTelemetryProcessor.getIncludedTypes()).contains(RequestTelemetry.class); + assertThat(fixedRateSamplingTelemetryProcessor.getExcludedTypes()).isEmpty(); + } + + @Test + void shouldBeAbleToDisableAllWebModules() { + EnvironmentTestUtils.addEnvironment(context, + "azure.application-insights.instrumentation-key: 00000000-0000-0000-0000-000000000000", + "azure.application-insights.web.enabled=false"); + context.register(PropertyPlaceholderAutoConfiguration.class, + ApplicationInsightsTelemetryAutoConfiguration.class); + context.refresh(); + + assertThat(context.getBeansOfType(WebUserTrackingTelemetryModule.class)).isEmpty(); + } + + @Test + void shouldBeAbleToDisableDefaultModules() { + EnvironmentTestUtils.addEnvironment(context, + "azure.application-insights.instrumentation-key: 00000000-0000-0000-0000-000000000000", + "azure.application-insights.default-modules.WebUserTrackingTelemetryModule.enabled=false"); + context.register(PropertyPlaceholderAutoConfiguration.class, + ApplicationInsightsTelemetryAutoConfiguration.class); + context.refresh(); + + assertThat(context.getBeansOfType(WebUserTrackingTelemetryModule.class)).isEmpty(); + } + @Test void shouldBeAbleToAddCustomModules() { EnvironmentTestUtils.addEnvironment(context, diff --git a/core/src/test/java/com/microsoft/applicationinsights/internal/channel/inprocess/InProcessTelemetryChannelTest.java b/core/src/test/java/com/microsoft/applicationinsights/internal/channel/inprocess/InProcessTelemetryChannelTest.java index 0619790d0ed..14a2647fbfb 100644 --- a/core/src/test/java/com/microsoft/applicationinsights/internal/channel/inprocess/InProcessTelemetryChannelTest.java +++ b/core/src/test/java/com/microsoft/applicationinsights/internal/channel/inprocess/InProcessTelemetryChannelTest.java @@ -22,6 +22,7 @@ package com.microsoft.applicationinsights.internal.channel.inprocess; import com.microsoft.applicationinsights.channel.concrete.inprocess.InProcessTelemetryChannel; +import org.junit.Assert; import org.junit.Test; import java.util.HashMap; @@ -36,4 +37,10 @@ public void testNotValidEndpointAddressAsMapValue() { map.put("EndpointAddress", NON_VALID_URL); new InProcessTelemetryChannel(map); } + + @Test + public void testInProcessTelemetryChannelWithDefaultSpringBootParameters() { + new InProcessTelemetryChannel("https://dc.services.visualstudio.com/v2/track", "10", + false, 500, 5, true); + } } \ No newline at end of file From 83e15547ee16758c38578c35ae91e1c966055c48 Mon Sep 17 00:00:00 2001 From: Arthur Gavlyukovskiy Date: Wed, 28 Feb 2018 00:35:08 +0200 Subject: [PATCH 09/43] Changed constants with default values to public in order to use them in spring boot starter --- .../boot/ApplicationInsightsProperties.java | 12 +++++++----- .../inprocess/InProcessTelemetryChannel.java | 4 ++-- .../channel/common/TransmissionFileSystemOutput.java | 2 +- .../channel/common/TransmissionNetworkOutput.java | 2 +- .../FixedRateSamplingTelemetryProcessor.java | 3 ++- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java index 700bd39ec6a..3f894ef6324 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java @@ -22,6 +22,8 @@ package com.microsoft.applicationinsights.boot; import com.microsoft.applicationinsights.channel.concrete.inprocess.InProcessTelemetryChannel; +import com.microsoft.applicationinsights.internal.channel.common.TransmissionFileSystemOutput; +import com.microsoft.applicationinsights.internal.channel.common.TransmissionNetworkOutput; import com.microsoft.applicationinsights.internal.channel.samplingV2.FixedRateSamplingTelemetryProcessor; import com.microsoft.applicationinsights.internal.channel.samplingV2.TelemetryType; import com.microsoft.applicationinsights.internal.logger.InternalLogger.LoggerOutputType; @@ -157,19 +159,19 @@ static class InProcess { /** * Endpoint address. */ - private String endpointAddress; + private String endpointAddress = TransmissionNetworkOutput.DEFAULT_SERVER_URI; /** * Maximum count of telemetries that will be batched before sending. */ - private int maxTelemetryBufferCapacity = 500; + private int maxTelemetryBufferCapacity = InProcessTelemetryChannel.DEFAULT_MAX_TELEMETRY_BUFFER_CAPACITY; /** * nterval to send telemetry. */ - private int flushIntervalInSeconds = 5; + private int flushIntervalInSeconds = InProcessTelemetryChannel.DEFAULT_FLUSH_BUFFER_TIMEOUT_IN_SECONDS; /** * Size of disk that we can use. */ - private int maxTransmissionStorageFilesCapacityInMb = 10; + private int maxTransmissionStorageFilesCapacityInMb = TransmissionFileSystemOutput.DEFAULT_CAPACITY_MEGABYTES; /** * Enables throttling on sending telemetry data. */ @@ -244,7 +246,7 @@ static class Sampling { /** * Percent of telemetry events that will be sent to Application Insights. */ - private double percentage = 100; + private double percentage = FixedRateSamplingTelemetryProcessor.DEFAULT_SAMPLING_PERCENTAGE; /** * If set only telemetry of specified types will be included. */ diff --git a/core/src/main/java/com/microsoft/applicationinsights/channel/concrete/inprocess/InProcessTelemetryChannel.java b/core/src/main/java/com/microsoft/applicationinsights/channel/concrete/inprocess/InProcessTelemetryChannel.java index 481e843de0e..790cd088f00 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/channel/concrete/inprocess/InProcessTelemetryChannel.java +++ b/core/src/main/java/com/microsoft/applicationinsights/channel/concrete/inprocess/InProcessTelemetryChannel.java @@ -65,12 +65,12 @@ * Created by gupele on 12/17/2014. */ public final class InProcessTelemetryChannel implements TelemetryChannel { - private final static int DEFAULT_MAX_TELEMETRY_BUFFER_CAPACITY = 500; + public final static int DEFAULT_MAX_TELEMETRY_BUFFER_CAPACITY = 500; private final static int MIN_MAX_TELEMETRY_BUFFER_CAPACITY = 1; private final static int MAX_MAX_TELEMETRY_BUFFER_CAPACITY = 1000; private final static String MAX_MAX_TELEMETRY_BUFFER_CAPACITY_NAME = "MaxTelemetryBufferCapacity"; - private final static int DEFAULT_FLUSH_BUFFER_TIMEOUT_IN_SECONDS = 5; + public final static int DEFAULT_FLUSH_BUFFER_TIMEOUT_IN_SECONDS = 5; private final static int MIN_FLUSH_BUFFER_TIMEOUT_IN_SECONDS = 1; private final static int MAX_FLUSH_BUFFER_TIMEOUT_IN_SECONDS = 300; private final static String FLUSH_BUFFER_TIMEOUT_IN_SECONDS_NAME = "FlushIntervalInSeconds"; diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmissionFileSystemOutput.java b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmissionFileSystemOutput.java index f6da9b9bd0e..83b54e72349 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmissionFileSystemOutput.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmissionFileSystemOutput.java @@ -77,7 +77,7 @@ public final class TransmissionFileSystemOutput implements TransmissionOutput { private final static int MAX_RETRY_FOR_DELETE = 2; private final static int DELETE_TIMEOUT_ON_FAILURE_IN_MILLS = 100; - private final static int DEFAULT_CAPACITY_MEGABYTES = 10; + public final static int DEFAULT_CAPACITY_MEGABYTES = 10; private final static int MAX_CAPACITY_MEGABYTES = 100; private final static int MIN_CAPACITY_MEGABYTES = 1; private static final String MAX_TRANSMISSION_STORAGE_CAPACITY_NAME = "Channel.MaxTransmissionStorageCapacityInMB"; diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmissionNetworkOutput.java b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmissionNetworkOutput.java index 2247c6356bf..f6cb2604f9f 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmissionNetworkOutput.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/common/TransmissionNetworkOutput.java @@ -60,7 +60,7 @@ public final class TransmissionNetworkOutput implements TransmissionOutput { private final static String RESPONSE_THROTTLING_HEADER = "Retry-After"; private final static String RESPONSE_RETRY_AFTER_DATE_FORMAT = "E, dd MMM yyyy HH:mm:ss"; - private final static String DEFAULT_SERVER_URI = "https://dc.services.visualstudio.com/v2/track"; + public final static String DEFAULT_SERVER_URI = "https://dc.services.visualstudio.com/v2/track"; private final static int DEFAULT_BACKOFF_TIME_SECONDS = 300; // For future use: re-send a failed transmission back to the dispatcher diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/FixedRateSamplingTelemetryProcessor.java b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/FixedRateSamplingTelemetryProcessor.java index d68e0d46c48..ba86512b912 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/FixedRateSamplingTelemetryProcessor.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/FixedRateSamplingTelemetryProcessor.java @@ -45,6 +45,7 @@ @BuiltInProcessor("FixedRateSamplingTelemetryProcessor") public final class FixedRateSamplingTelemetryProcessor implements TelemetryProcessor { + public static final double DEFAULT_SAMPLING_PERCENTAGE = 100.; private static Map allowedTypes = new HashMap<>(); static { @@ -71,7 +72,7 @@ public final class FixedRateSamplingTelemetryProcessor implements TelemetryProce * to default settings */ public FixedRateSamplingTelemetryProcessor() { - this.samplingPercentage = 100.00; + this.samplingPercentage = DEFAULT_SAMPLING_PERCENTAGE; this.includedTypes = new HashSet<>(); this.excludedTypes = new HashSet<>(); } From b55c46750928d938099a9d63e8ca69d0539c980f Mon Sep 17 00:00:00 2001 From: Arthur Gavlyukovskiy Date: Thu, 1 Mar 2018 10:24:00 +0200 Subject: [PATCH 10/43] Added explicit dependency on TelemetryConfiguration for QuickPulse bean --- .../boot/ApplicationInsightsTelemetryAutoConfiguration.java | 2 ++ .../boot/ApplicationInsightsWebMvcAutoConfiguration.java | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java index bda11d798c3..b7c99cb74fc 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java @@ -43,6 +43,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.Import; import java.util.Collection; @@ -147,6 +148,7 @@ public TelemetryChannel telemetryChannel() { @Bean @ConditionalOnProperty(value = "azure.application-insights.quick-pulse.enabled", havingValue = "true", matchIfMissing = true) + @DependsOn("telemetryConfiguration") public QuickPulse quickPulse() { QuickPulse.INSTANCE.initialize(); return QuickPulse.INSTANCE; diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java index 0cf60464e64..b5b3701d7bb 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java @@ -33,6 +33,7 @@ import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.Import; import org.springframework.core.Ordered; @@ -56,9 +57,8 @@ public FilterRegistrationBean webRequestTrackingFilterRegistrationBean(WebReques @Bean @ConditionalOnMissingBean - public WebRequestTrackingFilter webRequestTrackingFilter(@Value("${spring.application.name:application}") String applicationName, - // we have implicit dependency on configured telemetryConfiguration here - @SuppressWarnings("unused") TelemetryConfiguration telemetryConfiguration) { + @DependsOn("telemetryConfiguration") + public WebRequestTrackingFilter webRequestTrackingFilter(@Value("${spring.application.name:application}") String applicationName) { return new WebRequestTrackingFilter(applicationName); } } From afe1d0c4de0998f55f644617418b21468eb89037 Mon Sep 17 00:00:00 2001 From: Arthur Gavlyukovskiy Date: Thu, 1 Mar 2018 10:24:35 +0200 Subject: [PATCH 11/43] Polish --- .../boot/ApplicationInsightsModuleConfiguration.java | 2 -- .../applicationinsights/boot/ApplicationInsightsProperties.java | 1 - .../boot/ApplicationInsightsWebModuleConfiguration.java | 2 -- 3 files changed, 5 deletions(-) diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java index d130ee2e7a8..e5f07dfcc13 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java @@ -21,14 +21,12 @@ package com.microsoft.applicationinsights.boot; -import com.microsoft.applicationinsights.TelemetryConfiguration; import com.microsoft.applicationinsights.boot.conditional.ConditionalOnOperatingSystem; import com.microsoft.applicationinsights.boot.conditional.OperatingSystem; import com.microsoft.applicationinsights.boot.initializer.SpringBootContextInitializer; import com.microsoft.applicationinsights.extensibility.initializer.DeviceInfoContextInitializer; import com.microsoft.applicationinsights.extensibility.initializer.SdkVersionContextInitializer; import com.microsoft.applicationinsights.internal.perfcounter.ProcessPerformanceCountersModule; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java index 3f894ef6324..280e77ca889 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java @@ -28,7 +28,6 @@ import com.microsoft.applicationinsights.internal.channel.samplingV2.TelemetryType; import com.microsoft.applicationinsights.internal.logger.InternalLogger.LoggerOutputType; import com.microsoft.applicationinsights.internal.logger.InternalLogger.LoggingLevel; -import com.microsoft.applicationinsights.telemetry.BaseSampleSourceTelemetry; import com.microsoft.applicationinsights.web.extensibility.initializers.WebOperationIdTelemetryInitializer; import com.microsoft.applicationinsights.web.extensibility.initializers.WebOperationNameTelemetryInitializer; import com.microsoft.applicationinsights.web.extensibility.initializers.WebSessionTelemetryInitializer; diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java index 6082f7b33f7..13f77402357 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java @@ -21,7 +21,6 @@ package com.microsoft.applicationinsights.boot; -import com.microsoft.applicationinsights.TelemetryConfiguration; import com.microsoft.applicationinsights.web.extensibility.initializers.WebOperationIdTelemetryInitializer; import com.microsoft.applicationinsights.web.extensibility.initializers.WebOperationNameTelemetryInitializer; import com.microsoft.applicationinsights.web.extensibility.initializers.WebSessionTelemetryInitializer; @@ -31,7 +30,6 @@ import com.microsoft.applicationinsights.web.extensibility.modules.WebSessionTrackingTelemetryModule; import com.microsoft.applicationinsights.web.extensibility.modules.WebUserTrackingTelemetryModule; import com.microsoft.applicationinsights.web.internal.perfcounter.WebPerformanceCounterModule; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.context.annotation.Bean; From 62086f3256add3b8ea7a9430b682564f8df0e460 Mon Sep 17 00:00:00 2001 From: Arthur Gavlyukovskiy Date: Wed, 14 Mar 2018 00:07:05 +0200 Subject: [PATCH 12/43] Updated documentation regarding configuration values window --- azure-application-insights-spring-boot-starter/README.md | 8 ++++---- .../boot/ApplicationInsightsProperties.java | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/azure-application-insights-spring-boot-starter/README.md b/azure-application-insights-spring-boot-starter/README.md index e76201c95eb..c708391a8cb 100644 --- a/azure-application-insights-spring-boot-starter/README.md +++ b/azure-application-insights-spring-boot-starter/README.md @@ -133,16 +133,16 @@ azure.application-insights.logger.level=error azure.application-insights.channel.in-process.developer-mode=false # Endpoint address, Default value: https://dc.services.visualstudio.com/v2/track. azure.application-insights.channel.in-process.endpoint-address=https://dc.services.visualstudio.com/v2/track -# Maximum count of telemetries that will be batched before sending. Default value: 500. +# Maximum count of telemetries that will be batched before sending. Must be between 1 and 1000. Default value: 500. azure.application-insights.channel.in-process.max-telemetry-buffer-capacity=500 -# Interval to send telemetry. Default value: 5 seconds. +# Interval to send telemetry. Must be between 1 and 300. Default value: 5 seconds. azure.application-insights.channel.in-process.flush-interval-in-seconds=5 -# Size of disk that we can use. Default value: 10 megabytes. +# Size of disk that we can use. Must be between 1 and 1000. Default value: 10 megabytes. azure.application-insights.channel.in-process.max-transmission-storage-files-capacity-in-mb=10 # Enable/Disable throttling on sending telemetry data. Default value: true. azure.application-insights.channel.in-process.throttling=true -# Percent of telemetry events that will be sent to Application Insights. Default value: 100% (all telemetry events). +# Percent of telemetry events that will be sent to Application Insights. Must be between 0.0 and 100.0. Default value: 100 (all telemetry events). azure.application-insights.telemetry-processor.sampling.percentage=100 # If set only telemetry of specified types will be included. Default value: all telemetries are included; azure.application-insights.telemetry-processor.sampling.include= diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java index 280e77ca889..2f20aea6cd6 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java @@ -160,15 +160,15 @@ static class InProcess { */ private String endpointAddress = TransmissionNetworkOutput.DEFAULT_SERVER_URI; /** - * Maximum count of telemetries that will be batched before sending. + * Maximum count of telemetries that will be batched before sending. Must be between 1 and 1000. */ private int maxTelemetryBufferCapacity = InProcessTelemetryChannel.DEFAULT_MAX_TELEMETRY_BUFFER_CAPACITY; /** - * nterval to send telemetry. + * Interval to send telemetry. Must be between 1 and 300. */ private int flushIntervalInSeconds = InProcessTelemetryChannel.DEFAULT_FLUSH_BUFFER_TIMEOUT_IN_SECONDS; /** - * Size of disk that we can use. + * Size of disk that we can use. Must be between 1 and 1000. */ private int maxTransmissionStorageFilesCapacityInMb = TransmissionFileSystemOutput.DEFAULT_CAPACITY_MEGABYTES; /** @@ -243,7 +243,7 @@ public void setSampling(Sampling sampling) { static class Sampling { /** - * Percent of telemetry events that will be sent to Application Insights. + * Percent of telemetry events that will be sent to Application Insights. Must be between 0.0 and 100.0. */ private double percentage = FixedRateSamplingTelemetryProcessor.DEFAULT_SAMPLING_PERCENTAGE; /** From a4fda92d9ab4702a9d528bc7a74714b763bf0458 Mon Sep 17 00:00:00 2001 From: Arthur Gavlyukovskiy Date: Wed, 14 Mar 2018 10:25:08 +0200 Subject: [PATCH 13/43] Updated documentation of properties --- azure-application-insights-spring-boot-starter/README.md | 5 +++-- .../boot/ApplicationInsightsProperties.java | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/azure-application-insights-spring-boot-starter/README.md b/azure-application-insights-spring-boot-starter/README.md index c708391a8cb..86d01831bc8 100644 --- a/azure-application-insights-spring-boot-starter/README.md +++ b/azure-application-insights-spring-boot-starter/README.md @@ -137,12 +137,13 @@ azure.application-insights.channel.in-process.endpoint-address=https://dc.servic azure.application-insights.channel.in-process.max-telemetry-buffer-capacity=500 # Interval to send telemetry. Must be between 1 and 300. Default value: 5 seconds. azure.application-insights.channel.in-process.flush-interval-in-seconds=5 -# Size of disk that we can use. Must be between 1 and 1000. Default value: 10 megabytes. +# Size of disk space that Application Insights can use to store telemetry in case of network outage. Must be between 1 and 1000. Default value: 10 megabytes. azure.application-insights.channel.in-process.max-transmission-storage-files-capacity-in-mb=10 # Enable/Disable throttling on sending telemetry data. Default value: true. azure.application-insights.channel.in-process.throttling=true -# Percent of telemetry events that will be sent to Application Insights. Must be between 0.0 and 100.0. Default value: 100 (all telemetry events). +# Percent of telemetry events that will be sent to Application Insights. Percentage must be close to 100/N where N is an integer. +# E.g. 50 (=100/2), 33.33 (=100/3), 25 (=100/4), 20, 1 (=100/100), 0.1 (=100/1000). Default value: 100 (all telemetry events). azure.application-insights.telemetry-processor.sampling.percentage=100 # If set only telemetry of specified types will be included. Default value: all telemetries are included; azure.application-insights.telemetry-processor.sampling.include= diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java index 2f20aea6cd6..bc79205b234 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java @@ -168,7 +168,7 @@ static class InProcess { */ private int flushIntervalInSeconds = InProcessTelemetryChannel.DEFAULT_FLUSH_BUFFER_TIMEOUT_IN_SECONDS; /** - * Size of disk that we can use. Must be between 1 and 1000. + * Size of disk space that Application Insights can use to store telemetry in case of network outage. Must be between 1 and 1000. */ private int maxTransmissionStorageFilesCapacityInMb = TransmissionFileSystemOutput.DEFAULT_CAPACITY_MEGABYTES; /** @@ -243,7 +243,8 @@ public void setSampling(Sampling sampling) { static class Sampling { /** - * Percent of telemetry events that will be sent to Application Insights. Must be between 0.0 and 100.0. + * Percent of telemetry events that will be sent to Application Insights. Percentage must be close to 100/N where N is an integer. + * E.g. 50 (=100/2), 33.33 (=100/3), 25 (=100/4), 20, 1 (=100/100), 0.1 (=100/1000). */ private double percentage = FixedRateSamplingTelemetryProcessor.DEFAULT_SAMPLING_PERCENTAGE; /** From 4bd0b4b8fa97d00c91691a53e9f8f0518144b315 Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Thu, 15 Mar 2018 16:40:11 -0700 Subject: [PATCH 14/43] update build script to fix pom generation, enforced InternalLoggerBean to be created first --- .../build.gradle | 1 - .../boot/ApplicationInsightsProperties.java | 2 +- ...icationInsightsTelemetryAutoConfiguration.java | 2 ++ ...onInsightsTelemetryAutoConfigurationTests.java | 15 +++++++++++++++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/azure-application-insights-spring-boot-starter/build.gradle b/azure-application-insights-spring-boot-starter/build.gradle index f75570f5923..8f96f97646a 100644 --- a/azure-application-insights-spring-boot-starter/build.gradle +++ b/azure-application-insights-spring-boot-starter/build.gradle @@ -47,5 +47,4 @@ projectPomDescription = "This is the Spring Boot starter of " + project.msftAppI whenPomConfigured = { p -> def agentArtifactId = project(":agent").jar.baseName p.dependencies = p.dependencies.findAll { dep -> dep.artifactId != agentArtifactId } - writePomToArtifactsDirectory(p, project.name) } diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java index bc79205b234..780ef97051c 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java @@ -334,7 +334,7 @@ static class Logger { /** * Minimal level of application insights logger. */ - private LoggingLevel level = LoggingLevel.ERROR; + private LoggingLevel level = LoggingLevel.OFF; public LoggerOutputType getType() { return type; diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java index b7c99cb74fc..ed4c98f911c 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java @@ -37,6 +37,7 @@ import com.microsoft.applicationinsights.internal.quickpulse.QuickPulse; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -83,6 +84,7 @@ public class ApplicationInsightsTelemetryAutoConfiguration { private Collection telemetryProcessors; @Bean + @DependsOn("internalLogger") public TelemetryConfiguration telemetryConfiguration(TelemetryChannel telemetryChannel) { TelemetryConfiguration telemetryConfiguration = TelemetryConfiguration.getActive(); telemetryConfiguration.setTrackingIsDisabled(!applicationInsightsProperties.isEnabled()); diff --git a/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java b/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java index 1ab196589be..a7ca0e8bc80 100644 --- a/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java +++ b/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java @@ -30,6 +30,7 @@ import com.microsoft.applicationinsights.extensibility.TelemetryModule; import com.microsoft.applicationinsights.extensibility.TelemetryProcessor; import com.microsoft.applicationinsights.internal.channel.samplingV2.FixedRateSamplingTelemetryProcessor; +import com.microsoft.applicationinsights.internal.logger.InternalLogger; import com.microsoft.applicationinsights.telemetry.EventTelemetry; import com.microsoft.applicationinsights.telemetry.RequestTelemetry; import com.microsoft.applicationinsights.telemetry.Telemetry; @@ -181,6 +182,20 @@ void shouldBeAbleToDisableAllWebModules() { assertThat(context.getBeansOfType(WebUserTrackingTelemetryModule.class)).isEmpty(); } + @Test + void internalLoggerShouldBeInitializedBeforeTelemetryConfiguration() { + EnvironmentTestUtils.addEnvironment(context, + "azure.application-insights.instrumentation-key: 00000000-0000-0000-0000-000000000000", + "azure.application-insights.logger.level=INFO" + ); + context.register(PropertyPlaceholderAutoConfiguration.class, + ApplicationInsightsTelemetryAutoConfiguration.class); + context.refresh(); + InternalLogger logger = context.getBean(InternalLogger.class); + assertThat(logger.isInfoEnabled()).isEqualTo(true); + + } + @Test void shouldBeAbleToDisableDefaultModules() { EnvironmentTestUtils.addEnvironment(context, From bc19586a6b01cc338ce4bedeff3566a00868c9a8 Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Fri, 16 Mar 2018 11:38:04 -0700 Subject: [PATCH 15/43] improving the way to locate agent and registering web app --- .../common/CommonUtils.java | 54 ++++++++++++------- .../internal/WebRequestTrackingFilter.java | 29 ++++------ 2 files changed, 43 insertions(+), 40 deletions(-) diff --git a/core/src/main/java/com/microsoft/applicationinsights/common/CommonUtils.java b/core/src/main/java/com/microsoft/applicationinsights/common/CommonUtils.java index 9e30be1607c..93dafbd5588 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/common/CommonUtils.java +++ b/core/src/main/java/com/microsoft/applicationinsights/common/CommonUtils.java @@ -22,30 +22,44 @@ package com.microsoft.applicationinsights.common; import com.microsoft.applicationinsights.internal.logger.InternalLogger; -import org.apache.commons.lang3.exception.ExceptionUtils; - import java.net.InetAddress; import java.net.UnknownHostException; +import org.apache.commons.lang3.exception.ExceptionUtils; - -/** - * Created by oriy on 11/2/2016. - */ +/** Created by oriy on 11/2/2016. */ public class CommonUtils { - public static boolean isNullOrEmpty(String string) { - return string == null || string.length() == 0; + public static boolean isNullOrEmpty(String string) { + return string == null || string.length() == 0; + } + + public static String getHostName() { + try { + InetAddress addr; + addr = InetAddress.getLocalHost(); + return addr.getCanonicalHostName(); + } catch (UnknownHostException ex) { + // optional parameter. do nothing if unresolvable + InternalLogger.INSTANCE.trace( + "Unresolvable host error. Stack trace generated is %s", ExceptionUtils.getStackTrace(ex)); + return null; } - public static String getHostName(){ - try - { - InetAddress addr; - addr = InetAddress.getLocalHost(); - return addr.getCanonicalHostName(); - } - catch (UnknownHostException ex) { - // optional parameter. do nothing if unresolvable - InternalLogger.INSTANCE.trace("Unresolvable host error. Stack trace generated is %s", ExceptionUtils.getStackTrace(ex)); - return null; - } + } + + /** + * This method is used to test if the given class is loaded in the specified ClassLoader + * @param classSignature Fully Qualified signature of class + * @param classLoader ClassLoader under consideration + * @return true if class is loaded otherwise false + */ + public static boolean isClassPresentOnClassPath(String classSignature, ClassLoader classLoader) { + + try { + Class.forName(classSignature, false, classLoader); + return true; + } catch (ClassNotFoundException e) { + InternalLogger.INSTANCE.info( + "Specified class %s is not present on the classpath", classSignature); + return false; } + } } diff --git a/web/src/main/java/com/microsoft/applicationinsights/web/internal/WebRequestTrackingFilter.java b/web/src/main/java/com/microsoft/applicationinsights/web/internal/WebRequestTrackingFilter.java index 90eaa090384..4b5a4877bfb 100644 --- a/web/src/main/java/com/microsoft/applicationinsights/web/internal/WebRequestTrackingFilter.java +++ b/web/src/main/java/com/microsoft/applicationinsights/web/internal/WebRequestTrackingFilter.java @@ -62,6 +62,8 @@ public final class WebRequestTrackingFilter implements Filter { private boolean agentIsUp = false; private final LinkedList cleaners = new LinkedList(); private String appName; + private static final String AGENT_LOCATOR_INTERFACE_NAME = "com.microsoft.applicationinsights." + + "agent.internal.coresync.AgentNotificationsHandler"; // endregion Members @@ -230,33 +232,20 @@ public WebRequestTrackingFilter() { } private synchronized void initialize(FilterConfig filterConfig) { - try { - //if agent is not installed (jar not loaded), can skip the entire registration process - try { - AgentConnector test = AgentConnector.INSTANCE; - } catch (ThreadDeath td) { - throw td; - } catch (Throwable t) { - try { - InternalLogger.INSTANCE.info("Agent was not found. Skipping the agent registration"); - return; - } catch (ThreadDeath td) { - throw td; - } catch (Throwable t2) { - // chomp - } - } + //If Agent Jar is not present in the class path skip the process + if (!CommonUtils.isClassPresentOnClassPath(AGENT_LOCATOR_INTERFACE_NAME, + this.getClass().getClassLoader())) { + InternalLogger.INSTANCE.info("Agent was not found. Skipping the agent registration"); + return; + } + try { ServletContext context = filterConfig.getServletContext(); - String name = getName(context); - String key = registerWebApp(appName); setKey(key); - InternalLogger.INSTANCE.info("Successfully registered the filter '%s'", FILTER_NAME); - } catch (ThreadDeath td) { throw td; } catch (Throwable t) { From b2fbcd9d46d24715bd22b5d7306ffe5f48ae3b13 Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Sat, 17 Mar 2018 12:55:18 -0700 Subject: [PATCH 16/43] adding way to get empty telemetry configuration object --- ...tionInsightsTelemetryAutoConfiguration.java | 2 +- .../TelemetryConfiguration.java | 18 ++++++++++++++++++ .../TelemetryConfigurationFactoryTest.java | 13 +++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java index ed4c98f911c..8e19ca1929d 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java @@ -86,7 +86,7 @@ public class ApplicationInsightsTelemetryAutoConfiguration { @Bean @DependsOn("internalLogger") public TelemetryConfiguration telemetryConfiguration(TelemetryChannel telemetryChannel) { - TelemetryConfiguration telemetryConfiguration = TelemetryConfiguration.getActive(); + TelemetryConfiguration telemetryConfiguration = TelemetryConfiguration.getActiveWithoutInitializingCofig(); telemetryConfiguration.setTrackingIsDisabled(!applicationInsightsProperties.isEnabled()); telemetryConfiguration.setInstrumentationKey(applicationInsightsProperties.getInstrumentationKey()); if (contextInitializers != null) { diff --git a/core/src/main/java/com/microsoft/applicationinsights/TelemetryConfiguration.java b/core/src/main/java/com/microsoft/applicationinsights/TelemetryConfiguration.java index 82016f23e60..81bbe132599 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/TelemetryConfiguration.java +++ b/core/src/main/java/com/microsoft/applicationinsights/TelemetryConfiguration.java @@ -74,6 +74,24 @@ public static TelemetryConfiguration getActive() { return active; } + /** + * This method provides the new instance of TelmetryConfiguration without loading the configuration + * from configuration file. This will just give a plain bare bone instance. Typically used when + * performing configuration programatically by creating beans, using @Beans tags. This is a common + * scenario in SpringBoot. + * @return {@link com.microsoft.applicationinsights.TelemetryConfiguration} + */ + public static TelemetryConfiguration getActiveWithoutInitializingCofig() { + if (active == null) { + synchronized (s_lock) { + if (active == null) { + active = new TelemetryConfiguration(); + } + } + } + return active; + } + /** * Creates a new instance loaded from the ApplicationInsights.xml file. * If the configuration file does not exist, the new configuration instance is initialized with minimum defaults diff --git a/core/src/test/java/com/microsoft/applicationinsights/internal/config/TelemetryConfigurationFactoryTest.java b/core/src/test/java/com/microsoft/applicationinsights/internal/config/TelemetryConfigurationFactoryTest.java index d44037b4637..21509ce697c 100644 --- a/core/src/test/java/com/microsoft/applicationinsights/internal/config/TelemetryConfigurationFactoryTest.java +++ b/core/src/test/java/com/microsoft/applicationinsights/internal/config/TelemetryConfigurationFactoryTest.java @@ -21,6 +21,7 @@ package com.microsoft.applicationinsights.internal.config; +import com.microsoft.applicationinsights.telemetry.Telemetry; import java.io.InputStream; import java.lang.reflect.Field; import java.util.*; @@ -48,6 +49,7 @@ import org.junit.Assert; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.notNull; public final class TelemetryConfigurationFactoryTest { @@ -395,6 +397,17 @@ public void testDefaultChannelWithBadData() { assertEquals(mockConfiguration.getChannel().isDeveloperMode(), false); } + @Test + public void testEmptyConfiguration() { + TelemetryConfiguration emptyConfig = TelemetryConfiguration.getActiveWithoutInitializingCofig(); + Assert.assertEquals(null, emptyConfig.getInstrumentationKey()); + Assert.assertEquals(null, emptyConfig.getChannel()); + Assert.assertEquals(0, emptyConfig.getTelemetryModules().size()); + Assert.assertEquals(false, emptyConfig.isTrackingDisabled()); + Assert.assertEquals(0, emptyConfig.getContextInitializers().size()); + Assert.assertEquals(0, emptyConfig.getTelemetryProcessors().size()); + } + private MockTelemetryModule generateTelemetryModules(boolean addParameter) { AppInsightsConfigurationBuilder mockParser = createMockParser(true, true, false); ApplicationInsightsXmlConfiguration appConf = mockParser.build(null); From be1e23573cf1c7737928be8b36a466d32a8d06bd Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Tue, 20 Mar 2018 13:19:51 -0700 Subject: [PATCH 17/43] adding max_instant_rety configuration for boot --- .../boot/ApplicationInsightsProperties.java | 13 + ...ionInsightsTelemetryAutoConfiguration.java | 3 +- .../inprocess/InProcessTelemetryChannel.java | 717 +++++++++--------- 3 files changed, 391 insertions(+), 342 deletions(-) diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java index 780ef97051c..96c8a567887 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java @@ -176,6 +176,11 @@ static class InProcess { */ private boolean throttling = true; + /** + * Sets the size of maximum instant retries without delay + */ + private int maxInstantRetry = InProcessTelemetryChannel.DEFAULT_MAX_INSTANT_RETRY; + public boolean isDeveloperMode() { return developerMode; } @@ -184,6 +189,14 @@ public void setDeveloperMode(boolean developerMode) { this.developerMode = developerMode; } + public int getMaxInstantRetry() { + return maxInstantRetry; + } + + public void setMaxInstantRetry(int maxInstantRetry) { + this.maxInstantRetry = maxInstantRetry; + } + public String getEndpointAddress() { return endpointAddress; } diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java index 8e19ca1929d..d9aaec1027f 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java @@ -145,7 +145,8 @@ public TelemetryChannel telemetryChannel() { InProcess inProcess = applicationInsightsProperties.getChannel().getInProcess(); return new InProcessTelemetryChannel(inProcess.getEndpointAddress(), String.valueOf(inProcess.getMaxTransmissionStorageFilesCapacityInMb()), inProcess.isDeveloperMode(), - inProcess.getMaxTelemetryBufferCapacity(), inProcess.getFlushIntervalInSeconds(), inProcess.isThrottling()); + inProcess.getMaxTelemetryBufferCapacity(), inProcess.getFlushIntervalInSeconds(), inProcess.isThrottling(), + inProcess.getMaxInstantRetry()); } @Bean diff --git a/core/src/main/java/com/microsoft/applicationinsights/channel/concrete/inprocess/InProcessTelemetryChannel.java b/core/src/main/java/com/microsoft/applicationinsights/channel/concrete/inprocess/InProcessTelemetryChannel.java index 864ee75686d..029f6849ba6 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/channel/concrete/inprocess/InProcessTelemetryChannel.java +++ b/core/src/main/java/com/microsoft/applicationinsights/channel/concrete/inprocess/InProcessTelemetryChannel.java @@ -21,15 +21,11 @@ package com.microsoft.applicationinsights.channel.concrete.inprocess; -import java.io.IOException; -import java.io.StringWriter; -import java.net.URI; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; - -import com.microsoft.applicationinsights.internal.channel.TelemetriesTransmitter; +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; +import com.microsoft.applicationinsights.channel.TelemetryChannel; import com.microsoft.applicationinsights.channel.TelemetrySampler; +import com.microsoft.applicationinsights.internal.channel.TelemetriesTransmitter; import com.microsoft.applicationinsights.internal.channel.TransmitterFactory; import com.microsoft.applicationinsights.internal.channel.common.TelemetryBuffer; import com.microsoft.applicationinsights.internal.logger.InternalLogger; @@ -38,365 +34,404 @@ import com.microsoft.applicationinsights.internal.util.Sanitizer; import com.microsoft.applicationinsights.telemetry.JsonTelemetryDataSerializer; import com.microsoft.applicationinsights.telemetry.Telemetry; -import com.microsoft.applicationinsights.channel.TelemetryChannel; - -import com.google.common.base.Strings; -import com.google.common.base.Preconditions; +import java.io.IOException; +import java.io.StringWriter; +import java.net.URI; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; import org.apache.commons.lang3.exception.ExceptionUtils; /** - * An implementation of - * {@link com.microsoft.applicationinsights.channel.TelemetryChannel} - *

- * The channel holds two main entities: - *

- * A buffer for incoming - * {@link com.microsoft.applicationinsights.telemetry.Telemetry} instances A - * transmitter - *

- * The buffer is stores incoming telemetry instances. Every new buffer starts a - * timer. When the timer expires, or when the buffer is 'full' (whichever - * happens first), the transmitter will pick up that buffer and will handle its - * sending to the server. For example, a transmitter will be responsible for - * compressing, sending and activate a policy in case of failures. - *

- * The model here is: - *

- * Use application threads to populate the buffer Use channel's threads to send - * buffers to the server - *

- * Created by gupele on 12/17/2014. + * An implementation of {@link com.microsoft.applicationinsights.channel.TelemetryChannel} + * + *

The channel holds two main entities: + * + *

A buffer for incoming {@link com.microsoft.applicationinsights.telemetry.Telemetry} instances + * A transmitter + * + *

The buffer is stores incoming telemetry instances. Every new buffer starts a timer. When the + * timer expires, or when the buffer is 'full' (whichever happens first), the transmitter will pick + * up that buffer and will handle its sending to the server. For example, a transmitter will be + * responsible for compressing, sending and activate a policy in case of failures. + * + *

The model here is: + * + *

Use application threads to populate the buffer Use channel's threads to send buffers to the + * server + * + *

Created by gupele on 12/17/2014. */ public final class InProcessTelemetryChannel implements TelemetryChannel { - private final static String INSTANT_RETRY_NAME = "MaxInstantRetry"; - private final static int DEFAULT_MAX_INSTANT_RETRY = 3; - public final static int DEFAULT_MAX_TELEMETRY_BUFFER_CAPACITY = 500; - private final static int MIN_MAX_TELEMETRY_BUFFER_CAPACITY = 1; - private final static int MAX_MAX_TELEMETRY_BUFFER_CAPACITY = 1000; - private final static String MAX_MAX_TELEMETRY_BUFFER_CAPACITY_NAME = "MaxTelemetryBufferCapacity"; - - public final static int DEFAULT_FLUSH_BUFFER_TIMEOUT_IN_SECONDS = 5; - private final static int MIN_FLUSH_BUFFER_TIMEOUT_IN_SECONDS = 1; - private final static int MAX_FLUSH_BUFFER_TIMEOUT_IN_SECONDS = 300; - private final static String FLUSH_BUFFER_TIMEOUT_IN_SECONDS_NAME = "FlushIntervalInSeconds"; - - private final static String DEVELOPER_MODE_SYSTEM_PROPRETY_NAME = "APPLICATION_INSIGHTS_DEVELOPER_MODE"; - - private final static String DEVELOPER_MODE_NAME = "DeveloperMode"; - private final static String ENDPOINT_ADDRESS_NAME = "EndpointAddress"; - private final static String MAX_TRANSMISSION_STORAGE_CAPACITY_NAME = "MaxTransmissionStorageFilesCapacityInMB"; - - private boolean developerMode = false; - private static TransmitterFactory s_transmitterFactory; - - private boolean stopped = false; - - private TelemetriesTransmitter telemetriesTransmitter; - - private TelemetryBuffer telemetryBuffer; - private TelemetrySampler telemetrySampler; - - private static AtomicLong itemsSent = new AtomicLong(0); - - public InProcessTelemetryChannel() { - boolean developerMode = false; - try { - String developerModeAsString = System.getProperty(DEVELOPER_MODE_SYSTEM_PROPRETY_NAME); - if (!LocalStringsUtils.isNullOrEmpty(developerModeAsString)) { - developerMode = Boolean.valueOf(developerModeAsString); - } - } catch (Exception e) { - developerMode = false; - InternalLogger.INSTANCE.trace("%s generated exception in parsing, stack trace is %s", DEVELOPER_MODE_SYSTEM_PROPRETY_NAME, ExceptionUtils.getStackTrace(e)); - } - initialize(null, null, developerMode, createDefaultMaxTelemetryBufferCapacityEnforcer(null), - createDefaultSendIntervalInSecondsEnforcer(null), true); + private static final String INSTANT_RETRY_NAME = "MaxInstantRetry"; + public static final int DEFAULT_MAX_INSTANT_RETRY = 3; + public static final int DEFAULT_MAX_TELEMETRY_BUFFER_CAPACITY = 500; + private static final int MIN_MAX_TELEMETRY_BUFFER_CAPACITY = 1; + private static final int MAX_MAX_TELEMETRY_BUFFER_CAPACITY = 1000; + private static final String MAX_MAX_TELEMETRY_BUFFER_CAPACITY_NAME = "MaxTelemetryBufferCapacity"; + + public static final int DEFAULT_FLUSH_BUFFER_TIMEOUT_IN_SECONDS = 5; + private static final int MIN_FLUSH_BUFFER_TIMEOUT_IN_SECONDS = 1; + private static final int MAX_FLUSH_BUFFER_TIMEOUT_IN_SECONDS = 300; + private static final String FLUSH_BUFFER_TIMEOUT_IN_SECONDS_NAME = "FlushIntervalInSeconds"; + + private static final String DEVELOPER_MODE_SYSTEM_PROPRETY_NAME = + "APPLICATION_INSIGHTS_DEVELOPER_MODE"; + + private static final String DEVELOPER_MODE_NAME = "DeveloperMode"; + private static final String ENDPOINT_ADDRESS_NAME = "EndpointAddress"; + private static final String MAX_TRANSMISSION_STORAGE_CAPACITY_NAME = + "MaxTransmissionStorageFilesCapacityInMB"; + + private boolean developerMode = false; + private static TransmitterFactory s_transmitterFactory; + + private boolean stopped = false; + + private TelemetriesTransmitter telemetriesTransmitter; + + private TelemetryBuffer telemetryBuffer; + private TelemetrySampler telemetrySampler; + + private static AtomicLong itemsSent = new AtomicLong(0); + + public InProcessTelemetryChannel() { + boolean developerMode = false; + try { + String developerModeAsString = System.getProperty(DEVELOPER_MODE_SYSTEM_PROPRETY_NAME); + if (!LocalStringsUtils.isNullOrEmpty(developerModeAsString)) { + developerMode = Boolean.valueOf(developerModeAsString); + } + } catch (Exception e) { + developerMode = false; + InternalLogger.INSTANCE.trace( + "%s generated exception in parsing, stack trace is %s", + DEVELOPER_MODE_SYSTEM_PROPRETY_NAME, ExceptionUtils.getStackTrace(e)); } - - /** - * Ctor - * - * @param endpointAddress - * Must be empty string or a valid uri, else an exception will be - * thrown - * @param developerMode - * True will behave in a 'non-production' mode to ease the debugging - * @param maxTelemetryBufferCapacity - * Max number of Telemetries we keep in the buffer, when reached we - * will send the buffer Note, value should be between - * TRANSMIT_BUFFER_MIN_TIMEOUT_IN_MILLIS and - * TRANSMIT_BUFFER_MAX_TIMEOUT_IN_MILLIS inclusive - * @param sendIntervalInMillis - * The maximum number of milliseconds to wait before we send the - * buffer Note, value should be between - * MIN_MAX_TELEMETRY_BUFFER_CAPACITY and - * MAX_MAX_TELEMETRY_BUFFER_CAPACITY inclusive - */ - public InProcessTelemetryChannel(String endpointAddress, boolean developerMode, int maxTelemetryBufferCapacity, - int sendIntervalInMillis) { - this(endpointAddress, null, developerMode, maxTelemetryBufferCapacity, sendIntervalInMillis, true); - } - - public InProcessTelemetryChannel(String endpointAddress, String maxTransmissionStorageCapacity, boolean developerMode, - int maxTelemetryBufferCapacity, int sendIntervalInMillis, boolean throttling) { - initialize(endpointAddress, - maxTransmissionStorageCapacity, - developerMode, - createDefaultMaxTelemetryBufferCapacityEnforcer(maxTelemetryBufferCapacity), - createDefaultSendIntervalInSecondsEnforcer(sendIntervalInMillis), - throttling); - } - - /** - * This Ctor will query the 'namesAndValues' map for data to initialize itself - * It will ignore data that is not of its interest, this Ctor is useful for - * building an instance from configuration - * - * @param namesAndValues - * - The data passed as name and value pairs - */ - public InProcessTelemetryChannel(Map namesAndValues) { - boolean developerMode = false; - String endpointAddress = null; - int maxInstantRetries = DEFAULT_MAX_INSTANT_RETRY; - - LimitsEnforcer maxTelemetryBufferCapacityEnforcer = createDefaultMaxTelemetryBufferCapacityEnforcer(null); - - LimitsEnforcer sendIntervalInSecondsEnforcer = createDefaultSendIntervalInSecondsEnforcer(null); - - boolean throttling = true; - if (namesAndValues != null) { - throttling = Boolean.valueOf(namesAndValues.get("Throttling")); - developerMode = Boolean.valueOf(namesAndValues.get(DEVELOPER_MODE_NAME)); - try { - String instantRetryValue = namesAndValues.get(INSTANT_RETRY_NAME); - if (instantRetryValue != null){ - maxInstantRetries = Integer.parseInt(instantRetryValue); - } - - } catch (NumberFormatException e) { - InternalLogger.INSTANCE.error("Unable to parse configuration setting %s to integer value.%nStack Trace:%n%s", INSTANT_RETRY_NAME, ExceptionUtils.getStackTrace(e)); - } - - if (!developerMode) { - developerMode = Boolean.valueOf(System.getProperty(DEVELOPER_MODE_SYSTEM_PROPRETY_NAME)); - } - endpointAddress = namesAndValues.get(ENDPOINT_ADDRESS_NAME); - - maxTelemetryBufferCapacityEnforcer - .normalizeStringValue(namesAndValues.get(MAX_MAX_TELEMETRY_BUFFER_CAPACITY_NAME)); - sendIntervalInSecondsEnforcer - .normalizeStringValue(namesAndValues.get(FLUSH_BUFFER_TIMEOUT_IN_SECONDS_NAME)); + initialize( + null, + null, + developerMode, + createDefaultMaxTelemetryBufferCapacityEnforcer(null), + createDefaultSendIntervalInSecondsEnforcer(null), + true); + } + + /** + * Ctor + * + * @param endpointAddress Must be empty string or a valid uri, else an exception will be thrown + * @param developerMode True will behave in a 'non-production' mode to ease the debugging + * @param maxTelemetryBufferCapacity Max number of Telemetries we keep in the buffer, when reached + * we will send the buffer Note, value should be between TRANSMIT_BUFFER_MIN_TIMEOUT_IN_MILLIS + * and TRANSMIT_BUFFER_MAX_TIMEOUT_IN_MILLIS inclusive + * @param sendIntervalInMillis The maximum number of milliseconds to wait before we send the + * buffer Note, value should be between MIN_MAX_TELEMETRY_BUFFER_CAPACITY and + * MAX_MAX_TELEMETRY_BUFFER_CAPACITY inclusive + */ + public InProcessTelemetryChannel( + String endpointAddress, + boolean developerMode, + int maxTelemetryBufferCapacity, + int sendIntervalInMillis) { + + //Builder pattern implementation + this( + endpointAddress, + null, + developerMode, + maxTelemetryBufferCapacity, + sendIntervalInMillis, + true, DEFAULT_MAX_INSTANT_RETRY); + } + + public InProcessTelemetryChannel( + String endpointAddress, + String maxTransmissionStorageCapacity, + boolean developerMode, + int maxTelemetryBufferCapacity, + int sendIntervalInMillis, + boolean throttling, int maxInstantRetries) { + initialize( + endpointAddress, + maxTransmissionStorageCapacity, + developerMode, + createDefaultMaxTelemetryBufferCapacityEnforcer(maxTelemetryBufferCapacity), + createDefaultSendIntervalInSecondsEnforcer(sendIntervalInMillis), + throttling, maxInstantRetries); + } + + /** + * This Ctor will query the 'namesAndValues' map for data to initialize itself It will ignore data + * that is not of its interest, this Ctor is useful for building an instance from configuration + * + * @param namesAndValues - The data passed as name and value pairs + */ + public InProcessTelemetryChannel(Map namesAndValues) { + boolean developerMode = false; + String endpointAddress = null; + int maxInstantRetries = DEFAULT_MAX_INSTANT_RETRY; + + LimitsEnforcer maxTelemetryBufferCapacityEnforcer = + createDefaultMaxTelemetryBufferCapacityEnforcer(null); + + LimitsEnforcer sendIntervalInSecondsEnforcer = createDefaultSendIntervalInSecondsEnforcer(null); + + boolean throttling = true; + if (namesAndValues != null) { + throttling = Boolean.valueOf(namesAndValues.get("Throttling")); + developerMode = Boolean.valueOf(namesAndValues.get(DEVELOPER_MODE_NAME)); + try { + String instantRetryValue = namesAndValues.get(INSTANT_RETRY_NAME); + if (instantRetryValue != null) { + maxInstantRetries = Integer.parseInt(instantRetryValue); } - String maxTransmissionStorageCapacity = namesAndValues.get(MAX_TRANSMISSION_STORAGE_CAPACITY_NAME); - initialize(endpointAddress, maxTransmissionStorageCapacity, developerMode, maxTelemetryBufferCapacityEnforcer, - sendIntervalInSecondsEnforcer, throttling, maxInstantRetries); - } - - /** - * Gets value indicating whether this channel is in developer mode. - */ - @Override - public boolean isDeveloperMode() { - return developerMode; + } catch (NumberFormatException e) { + InternalLogger.INSTANCE.error( + "Unable to parse configuration setting %s to integer value.%nStack Trace:%n%s", + INSTANT_RETRY_NAME, ExceptionUtils.getStackTrace(e)); + } + + if (!developerMode) { + developerMode = Boolean.valueOf(System.getProperty(DEVELOPER_MODE_SYSTEM_PROPRETY_NAME)); + } + endpointAddress = namesAndValues.get(ENDPOINT_ADDRESS_NAME); + + maxTelemetryBufferCapacityEnforcer.normalizeStringValue( + namesAndValues.get(MAX_MAX_TELEMETRY_BUFFER_CAPACITY_NAME)); + sendIntervalInSecondsEnforcer.normalizeStringValue( + namesAndValues.get(FLUSH_BUFFER_TIMEOUT_IN_SECONDS_NAME)); } - /** - * Sets value indicating whether this channel is in developer mode. - * - * @param developerMode - * True or false - */ - @Override - public void setDeveloperMode(boolean developerMode) { - if (developerMode != this.developerMode) { - this.developerMode = developerMode; - int maxTelemetriesInBatch = this.developerMode ? 1 : DEFAULT_MAX_TELEMETRY_BUFFER_CAPACITY; - - setMaxTelemetriesInBatch(maxTelemetriesInBatch); - } - } - - /** - * Sends a Telemetry instance through the channel. - */ - @Override - public void send(Telemetry telemetry) { - Preconditions.checkNotNull(telemetry, "Telemetry item must be non null"); - - if (isDeveloperMode()) { - telemetry.getContext().getProperties().put("DeveloperMode", "true"); - } - - if (telemetrySampler != null) { - if (!telemetrySampler.isSampledIn(telemetry)) { - return; - } - } - - StringWriter writer = new StringWriter(); - JsonTelemetryDataSerializer jsonWriter = null; - try { - jsonWriter = new JsonTelemetryDataSerializer(writer); - telemetry.serialize(jsonWriter); - jsonWriter.close(); - String asJson = writer.toString(); - telemetryBuffer.add(asJson); - telemetry.reset(); - if (itemsSent.incrementAndGet() % 10000 == 0) { - InternalLogger.INSTANCE.info("items sent till now %d", itemsSent.get()); - } - - } catch (IOException e) { - InternalLogger.INSTANCE.error("Failed to serialize Telemetry"); - InternalLogger.INSTANCE.trace("Stack trace is %s", ExceptionUtils.getStackTrace(e)); - return; - } - - if (isDeveloperMode()) { - writeTelemetryToDebugOutput(telemetry); - } + String maxTransmissionStorageCapacity = + namesAndValues.get(MAX_TRANSMISSION_STORAGE_CAPACITY_NAME); + initialize( + endpointAddress, + maxTransmissionStorageCapacity, + developerMode, + maxTelemetryBufferCapacityEnforcer, + sendIntervalInSecondsEnforcer, + throttling, + maxInstantRetries); + } + + /** Gets value indicating whether this channel is in developer mode. */ + @Override + public boolean isDeveloperMode() { + return developerMode; + } + + /** + * Sets value indicating whether this channel is in developer mode. + * + * @param developerMode True or false + */ + @Override + public void setDeveloperMode(boolean developerMode) { + if (developerMode != this.developerMode) { + this.developerMode = developerMode; + int maxTelemetriesInBatch = this.developerMode ? 1 : DEFAULT_MAX_TELEMETRY_BUFFER_CAPACITY; + + setMaxTelemetriesInBatch(maxTelemetriesInBatch); } + } - /** - * Stops on going work - */ - @Override - public synchronized void stop(long timeout, TimeUnit timeUnit) { - try { - if (stopped) { - return; - } - - telemetriesTransmitter.stop(timeout, timeUnit); - stopped = true; - } catch (ThreadDeath td) { - throw td; - } catch (Throwable t) { - try { - InternalLogger.INSTANCE.error("Exception generated while stopping telemetry transmitter"); - InternalLogger.INSTANCE.trace("Stack trace generated is %s", ExceptionUtils.getStackTrace(t)); - } catch (ThreadDeath td) { - throw td; - } catch (Throwable t2) { - // chomp - } - } - } + /** Sends a Telemetry instance through the channel. */ + @Override + public void send(Telemetry telemetry) { + Preconditions.checkNotNull(telemetry, "Telemetry item must be non null"); - /** - * Flushes the data that the channel might have internally. - */ - @Override - public void flush() { - telemetryBuffer.flush(); + if (isDeveloperMode()) { + telemetry.getContext().getProperties().put("DeveloperMode", "true"); } - /** - * Sets an optional Sampler that can sample out telemetries Currently, we don't - * allow to replace a valid telemtry sampler. - * - * @param telemetrySampler - * - The sampler - */ - @Override - public void setSampler(TelemetrySampler telemetrySampler) { - if (this.telemetrySampler == null) { - this.telemetrySampler = telemetrySampler; - } + if (telemetrySampler != null) { + if (!telemetrySampler.isSampledIn(telemetry)) { + return; + } } - /** - * Sets the buffer size - * - * @param maxTelemetriesInBatch - * should be between MIN_MAX_TELEMETRY_BUFFER_CAPACITY and - * MAX_MAX_TELEMETRY_BUFFER_CAPACITY inclusive if the number is lower - * than the minimum then the minimum will be used if the number is - * higher than the maximum then the maximum will be used - */ - public void setMaxTelemetriesInBatch(int maxTelemetriesInBatch) { - telemetryBuffer.setMaxTelemetriesInBatch(maxTelemetriesInBatch); + StringWriter writer = new StringWriter(); + JsonTelemetryDataSerializer jsonWriter = null; + try { + jsonWriter = new JsonTelemetryDataSerializer(writer); + telemetry.serialize(jsonWriter); + jsonWriter.close(); + String asJson = writer.toString(); + telemetryBuffer.add(asJson); + telemetry.reset(); + if (itemsSent.incrementAndGet() % 10000 == 0) { + InternalLogger.INSTANCE.info("items sent till now %d", itemsSent.get()); + } + + } catch (IOException e) { + InternalLogger.INSTANCE.error("Failed to serialize Telemetry"); + InternalLogger.INSTANCE.trace("Stack trace is %s", ExceptionUtils.getStackTrace(e)); + return; } - /** - * Sets the time tow wait before flushing the internal buffer - * - * @param transmitBufferTimeoutInSeconds - * should be between MIN_FLUSH_BUFFER_TIMEOUT_IN_SECONDS and - * MAX_FLUSH_BUFFER_TIMEOUT_IN_SECONDS inclusive if the number is - * lower than the minimum then the minimum will be used if the number - * is higher than the maximum then the maximum will be used - */ - public void setTransmitBufferTimeoutInSeconds(int transmitBufferTimeoutInSeconds) { - telemetryBuffer.setTransmitBufferTimeoutInSeconds(transmitBufferTimeoutInSeconds); + if (isDeveloperMode()) { + writeTelemetryToDebugOutput(telemetry); } - - private void writeTelemetryToDebugOutput(Telemetry telemetry) { - InternalLogger.INSTANCE.trace("InProcessTelemetryChannel sending telemetry"); + } + + /** Stops on going work */ + @Override + public synchronized void stop(long timeout, TimeUnit timeUnit) { + try { + if (stopped) { + return; + } + + telemetriesTransmitter.stop(timeout, timeUnit); + stopped = true; + } catch (ThreadDeath td) { + throw td; + } catch (Throwable t) { + try { + InternalLogger.INSTANCE.error("Exception generated while stopping telemetry transmitter"); + InternalLogger.INSTANCE.trace( + "Stack trace generated is %s", ExceptionUtils.getStackTrace(t)); + } catch (ThreadDeath td) { + throw td; + } catch (Throwable t2) { + // chomp + } } - - private synchronized void initialize(String endpointAddress, String maxTransmissionStorageCapacity, - boolean developerMode, LimitsEnforcer maxTelemetryBufferCapacityEnforcer, - LimitsEnforcer sendIntervalInSeconds, boolean throttling) { - initialize(endpointAddress, maxTransmissionStorageCapacity, developerMode, maxTelemetryBufferCapacityEnforcer, - sendIntervalInSeconds, throttling, DEFAULT_MAX_INSTANT_RETRY); - } - - private synchronized void initialize(String endpointAddress, String maxTransmissionStorageCapacity, - boolean developerMode, LimitsEnforcer maxTelemetryBufferCapacityEnforcer, - LimitsEnforcer sendIntervalInSeconds, boolean throttling, int maxInstantRetry) { - makeSureEndpointAddressIsValid(endpointAddress); - - if (s_transmitterFactory == null) { - s_transmitterFactory = new InProcessTelemetryChannelFactory(); - } - - telemetriesTransmitter = s_transmitterFactory.create(endpointAddress, maxTransmissionStorageCapacity, - throttling, maxInstantRetry); - telemetryBuffer = new TelemetryBuffer(telemetriesTransmitter, maxTelemetryBufferCapacityEnforcer, - sendIntervalInSeconds); - - setDeveloperMode(developerMode); + } + + /** Flushes the data that the channel might have internally. */ + @Override + public void flush() { + telemetryBuffer.flush(); + } + + /** + * Sets an optional Sampler that can sample out telemetries Currently, we don't allow to replace a + * valid telemtry sampler. + * + * @param telemetrySampler - The sampler + */ + @Override + public void setSampler(TelemetrySampler telemetrySampler) { + if (this.telemetrySampler == null) { + this.telemetrySampler = telemetrySampler; } - - /** - * The method will throw IllegalArgumentException if the endpointAddress is not - * a valid uri Please note that a null or empty string is valid as far as the - * class is concerned and thus considered valid - * - * @param endpointAddress - */ - private void makeSureEndpointAddressIsValid(String endpointAddress) { - if (Strings.isNullOrEmpty(endpointAddress)) { - return; - } - - URI uri = Sanitizer.sanitizeUri(endpointAddress); - if (uri == null) { - String errorMessage = String.format("Endpoint address %s is not a valid uri", endpointAddress); - InternalLogger.INSTANCE.error(errorMessage); - throw new IllegalArgumentException(errorMessage); - } + } + + /** + * Sets the buffer size + * + * @param maxTelemetriesInBatch should be between MIN_MAX_TELEMETRY_BUFFER_CAPACITY and + * MAX_MAX_TELEMETRY_BUFFER_CAPACITY inclusive if the number is lower than the minimum then + * the minimum will be used if the number is higher than the maximum then the maximum will be + * used + */ + public void setMaxTelemetriesInBatch(int maxTelemetriesInBatch) { + telemetryBuffer.setMaxTelemetriesInBatch(maxTelemetriesInBatch); + } + + /** + * Sets the time tow wait before flushing the internal buffer + * + * @param transmitBufferTimeoutInSeconds should be between MIN_FLUSH_BUFFER_TIMEOUT_IN_SECONDS and + * MAX_FLUSH_BUFFER_TIMEOUT_IN_SECONDS inclusive if the number is lower than the minimum then + * the minimum will be used if the number is higher than the maximum then the maximum will be + * used + */ + public void setTransmitBufferTimeoutInSeconds(int transmitBufferTimeoutInSeconds) { + telemetryBuffer.setTransmitBufferTimeoutInSeconds(transmitBufferTimeoutInSeconds); + } + + private void writeTelemetryToDebugOutput(Telemetry telemetry) { + InternalLogger.INSTANCE.trace("InProcessTelemetryChannel sending telemetry"); + } + + private synchronized void initialize( + String endpointAddress, + String maxTransmissionStorageCapacity, + boolean developerMode, + LimitsEnforcer maxTelemetryBufferCapacityEnforcer, + LimitsEnforcer sendIntervalInSeconds, + boolean throttling) { + initialize( + endpointAddress, + maxTransmissionStorageCapacity, + developerMode, + maxTelemetryBufferCapacityEnforcer, + sendIntervalInSeconds, + throttling, + DEFAULT_MAX_INSTANT_RETRY); + } + + private synchronized void initialize( + String endpointAddress, + String maxTransmissionStorageCapacity, + boolean developerMode, + LimitsEnforcer maxTelemetryBufferCapacityEnforcer, + LimitsEnforcer sendIntervalInSeconds, + boolean throttling, + int maxInstantRetry) { + makeSureEndpointAddressIsValid(endpointAddress); + + if (s_transmitterFactory == null) { + s_transmitterFactory = new InProcessTelemetryChannelFactory(); } - private LimitsEnforcer createDefaultMaxTelemetryBufferCapacityEnforcer(Integer currentValue) { - LimitsEnforcer maxItemsInBatchEnforcer = LimitsEnforcer.createWithClosestLimitOnError( - MAX_MAX_TELEMETRY_BUFFER_CAPACITY_NAME, MIN_MAX_TELEMETRY_BUFFER_CAPACITY, - MAX_MAX_TELEMETRY_BUFFER_CAPACITY, DEFAULT_MAX_TELEMETRY_BUFFER_CAPACITY, - currentValue == null ? DEFAULT_MAX_TELEMETRY_BUFFER_CAPACITY : currentValue); - - return maxItemsInBatchEnforcer; + telemetriesTransmitter = + s_transmitterFactory.create( + endpointAddress, maxTransmissionStorageCapacity, throttling, maxInstantRetry); + telemetryBuffer = + new TelemetryBuffer( + telemetriesTransmitter, maxTelemetryBufferCapacityEnforcer, sendIntervalInSeconds); + + setDeveloperMode(developerMode); + } + + /** + * The method will throw IllegalArgumentException if the endpointAddress is not a valid uri Please + * note that a null or empty string is valid as far as the class is concerned and thus considered + * valid + * + * @param endpointAddress + */ + private void makeSureEndpointAddressIsValid(String endpointAddress) { + if (Strings.isNullOrEmpty(endpointAddress)) { + return; } - private LimitsEnforcer createDefaultSendIntervalInSecondsEnforcer(Integer currentValue) { - LimitsEnforcer sendIntervalInSecondsEnforcer = LimitsEnforcer.createWithClosestLimitOnError( - FLUSH_BUFFER_TIMEOUT_IN_SECONDS_NAME, MIN_FLUSH_BUFFER_TIMEOUT_IN_SECONDS, - MAX_FLUSH_BUFFER_TIMEOUT_IN_SECONDS, DEFAULT_FLUSH_BUFFER_TIMEOUT_IN_SECONDS, - currentValue == null ? DEFAULT_FLUSH_BUFFER_TIMEOUT_IN_SECONDS : currentValue); - - return sendIntervalInSecondsEnforcer; + URI uri = Sanitizer.sanitizeUri(endpointAddress); + if (uri == null) { + String errorMessage = + String.format("Endpoint address %s is not a valid uri", endpointAddress); + InternalLogger.INSTANCE.error(errorMessage); + throw new IllegalArgumentException(errorMessage); } + } + + private LimitsEnforcer createDefaultMaxTelemetryBufferCapacityEnforcer(Integer currentValue) { + LimitsEnforcer maxItemsInBatchEnforcer = + LimitsEnforcer.createWithClosestLimitOnError( + MAX_MAX_TELEMETRY_BUFFER_CAPACITY_NAME, + MIN_MAX_TELEMETRY_BUFFER_CAPACITY, + MAX_MAX_TELEMETRY_BUFFER_CAPACITY, + DEFAULT_MAX_TELEMETRY_BUFFER_CAPACITY, + currentValue == null ? DEFAULT_MAX_TELEMETRY_BUFFER_CAPACITY : currentValue); + + return maxItemsInBatchEnforcer; + } + + private LimitsEnforcer createDefaultSendIntervalInSecondsEnforcer(Integer currentValue) { + LimitsEnforcer sendIntervalInSecondsEnforcer = + LimitsEnforcer.createWithClosestLimitOnError( + FLUSH_BUFFER_TIMEOUT_IN_SECONDS_NAME, + MIN_FLUSH_BUFFER_TIMEOUT_IN_SECONDS, + MAX_FLUSH_BUFFER_TIMEOUT_IN_SECONDS, + DEFAULT_FLUSH_BUFFER_TIMEOUT_IN_SECONDS, + currentValue == null ? DEFAULT_FLUSH_BUFFER_TIMEOUT_IN_SECONDS : currentValue); + + return sendIntervalInSecondsEnforcer; + } } From 94cdc2d359af0767e6302f06e8ccaf6e379d3eb0 Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Mon, 26 Mar 2018 08:50:50 -0700 Subject: [PATCH 18/43] refactoring spelling error --- .../boot/ApplicationInsightsTelemetryAutoConfiguration.java | 3 +-- .../microsoft/applicationinsights/TelemetryConfiguration.java | 2 +- .../internal/config/TelemetryConfigurationFactoryTest.java | 4 +--- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java index 8e19ca1929d..7b64257687f 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java @@ -37,7 +37,6 @@ import com.microsoft.applicationinsights.internal.quickpulse.QuickPulse; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -86,7 +85,7 @@ public class ApplicationInsightsTelemetryAutoConfiguration { @Bean @DependsOn("internalLogger") public TelemetryConfiguration telemetryConfiguration(TelemetryChannel telemetryChannel) { - TelemetryConfiguration telemetryConfiguration = TelemetryConfiguration.getActiveWithoutInitializingCofig(); + TelemetryConfiguration telemetryConfiguration = TelemetryConfiguration.getActiveWithoutInitializingConfig(); telemetryConfiguration.setTrackingIsDisabled(!applicationInsightsProperties.isEnabled()); telemetryConfiguration.setInstrumentationKey(applicationInsightsProperties.getInstrumentationKey()); if (contextInitializers != null) { diff --git a/core/src/main/java/com/microsoft/applicationinsights/TelemetryConfiguration.java b/core/src/main/java/com/microsoft/applicationinsights/TelemetryConfiguration.java index 81bbe132599..4be9d840a88 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/TelemetryConfiguration.java +++ b/core/src/main/java/com/microsoft/applicationinsights/TelemetryConfiguration.java @@ -81,7 +81,7 @@ public static TelemetryConfiguration getActive() { * scenario in SpringBoot. * @return {@link com.microsoft.applicationinsights.TelemetryConfiguration} */ - public static TelemetryConfiguration getActiveWithoutInitializingCofig() { + public static TelemetryConfiguration getActiveWithoutInitializingConfig() { if (active == null) { synchronized (s_lock) { if (active == null) { diff --git a/core/src/test/java/com/microsoft/applicationinsights/internal/config/TelemetryConfigurationFactoryTest.java b/core/src/test/java/com/microsoft/applicationinsights/internal/config/TelemetryConfigurationFactoryTest.java index 21509ce697c..9e7daa8efb1 100644 --- a/core/src/test/java/com/microsoft/applicationinsights/internal/config/TelemetryConfigurationFactoryTest.java +++ b/core/src/test/java/com/microsoft/applicationinsights/internal/config/TelemetryConfigurationFactoryTest.java @@ -21,7 +21,6 @@ package com.microsoft.applicationinsights.internal.config; -import com.microsoft.applicationinsights.telemetry.Telemetry; import java.io.InputStream; import java.lang.reflect.Field; import java.util.*; @@ -30,7 +29,6 @@ import com.microsoft.applicationinsights.channel.concrete.inprocess.InProcessTelemetryChannel; import com.microsoft.applicationinsights.extensibility.TelemetryModule; import com.microsoft.applicationinsights.extensibility.TelemetryProcessor; -import com.microsoft.applicationinsights.internal.annotation.BuiltInProcessor; import com.microsoft.applicationinsights.internal.channel.stdout.StdOutChannel; import com.microsoft.applicationinsights.internal.annotation.PerformanceModule; @@ -399,7 +397,7 @@ public void testDefaultChannelWithBadData() { @Test public void testEmptyConfiguration() { - TelemetryConfiguration emptyConfig = TelemetryConfiguration.getActiveWithoutInitializingCofig(); + TelemetryConfiguration emptyConfig = TelemetryConfiguration.getActiveWithoutInitializingConfig(); Assert.assertEquals(null, emptyConfig.getInstrumentationKey()); Assert.assertEquals(null, emptyConfig.getChannel()); Assert.assertEquals(0, emptyConfig.getTelemetryModules().size()); From b7ef48947089745a2480b5039f12e486910227ce Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Tue, 3 Apr 2018 15:44:45 -0700 Subject: [PATCH 19/43] fix a test --- .../channel/inprocess/InProcessTelemetryChannelTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/test/java/com/microsoft/applicationinsights/internal/channel/inprocess/InProcessTelemetryChannelTest.java b/core/src/test/java/com/microsoft/applicationinsights/internal/channel/inprocess/InProcessTelemetryChannelTest.java index d52c72cae8a..9d4e489bfd4 100644 --- a/core/src/test/java/com/microsoft/applicationinsights/internal/channel/inprocess/InProcessTelemetryChannelTest.java +++ b/core/src/test/java/com/microsoft/applicationinsights/internal/channel/inprocess/InProcessTelemetryChannelTest.java @@ -29,8 +29,8 @@ public class InProcessTelemetryChannelTest { - private final static String NON_VALID_URL = "http:sd{@~fsd.s.d.f;fffff"; - private final static String INSTANT_RETRY_NAME = "MaxInstantRetry"; + private final static String NON_VALID_URL = "http:sd{@~fsd.s.d.f;fffff"; + private final static String INSTANT_RETRY_NAME = "MaxInstantRetry"; private final static int DEFAULT_MAX_INSTANT_RETRY = 3; @Test(expected = IllegalArgumentException.class) @@ -63,6 +63,6 @@ public void testInvalidIntegerMaxInstanceRetry() { @Test public void testInProcessTelemetryChannelWithDefaultSpringBootParameters() { new InProcessTelemetryChannel("https://dc.services.visualstudio.com/v2/track", "10", - false, 500, 5, true); + false, 500, 5, true, DEFAULT_MAX_INSTANT_RETRY); } } \ No newline at end of file From 943ad11d3c4ed390ee57c0b1300b1c91b95db947 Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Tue, 3 Apr 2018 17:11:27 -0700 Subject: [PATCH 20/43] fixing broken initialization --- .../applicationinsights/TelemetryConfiguration.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/com/microsoft/applicationinsights/TelemetryConfiguration.java b/core/src/main/java/com/microsoft/applicationinsights/TelemetryConfiguration.java index 4be9d840a88..68d01811fc0 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/TelemetryConfiguration.java +++ b/core/src/main/java/com/microsoft/applicationinsights/TelemetryConfiguration.java @@ -82,12 +82,8 @@ public static TelemetryConfiguration getActive() { * @return {@link com.microsoft.applicationinsights.TelemetryConfiguration} */ public static TelemetryConfiguration getActiveWithoutInitializingConfig() { - if (active == null) { - synchronized (s_lock) { - if (active == null) { - active = new TelemetryConfiguration(); - } - } + synchronized (s_lock) { + active = new TelemetryConfiguration(); } return active; } From 79b5f0c4beeb5b31d04c0167af2ff01425702143 Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Wed, 4 Apr 2018 16:54:48 -0700 Subject: [PATCH 21/43] changing SpringBootContextInitializer to TelemetryInitializer, contextTags are not reflected on UX if not in bond schema definition --- ...pplicationInsightsModuleConfiguration.java | 6 +++--- ...va => SpringBootTelemetryInitializer.java} | 21 ++++++++++--------- 2 files changed, 14 insertions(+), 13 deletions(-) rename azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/{SpringBootContextInitializer.java => SpringBootTelemetryInitializer.java} (72%) diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java index e5f07dfcc13..b8c5dad33a5 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java @@ -23,7 +23,7 @@ import com.microsoft.applicationinsights.boot.conditional.ConditionalOnOperatingSystem; import com.microsoft.applicationinsights.boot.conditional.OperatingSystem; -import com.microsoft.applicationinsights.boot.initializer.SpringBootContextInitializer; +import com.microsoft.applicationinsights.boot.initializer.SpringBootTelemetryInitializer; import com.microsoft.applicationinsights.extensibility.initializer.DeviceInfoContextInitializer; import com.microsoft.applicationinsights.extensibility.initializer.SdkVersionContextInitializer; import com.microsoft.applicationinsights.internal.perfcounter.ProcessPerformanceCountersModule; @@ -41,8 +41,8 @@ public class ApplicationInsightsModuleConfiguration { @Bean - public SpringBootContextInitializer springBootContextInitializer(Environment environment) { - return new SpringBootContextInitializer(environment); + public SpringBootTelemetryInitializer springBootTelemetryInitializer(Environment environment) { + return new SpringBootTelemetryInitializer(environment); } @Bean diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/SpringBootContextInitializer.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/SpringBootTelemetryInitializer.java similarity index 72% rename from azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/SpringBootContextInitializer.java rename to azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/SpringBootTelemetryInitializer.java index 72aed517ea3..570de4b4bd8 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/SpringBootContextInitializer.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/SpringBootTelemetryInitializer.java @@ -21,35 +21,36 @@ package com.microsoft.applicationinsights.boot.initializer; -import com.microsoft.applicationinsights.extensibility.ContextInitializer; +import com.microsoft.applicationinsights.extensibility.TelemetryInitializer; import com.microsoft.applicationinsights.extensibility.context.ContextTagKeys; -import com.microsoft.applicationinsights.telemetry.TelemetryContext; +import com.microsoft.applicationinsights.telemetry.Telemetry; import org.springframework.boot.SpringBootVersion; import org.springframework.boot.bind.RelaxedPropertyResolver; import org.springframework.core.SpringVersion; import org.springframework.core.env.Environment; /** - * Context initializer that adds information regarding spring and spring boot version. + * Telemetry initializer that adds information regarding spring and spring boot version. * - * @author Arthur Gavlyukovskiy + * @author Dhaval Doshi */ -public class SpringBootContextInitializer implements ContextInitializer { +public class SpringBootTelemetryInitializer implements TelemetryInitializer { private final Environment environment; - public SpringBootContextInitializer(Environment environment) { + public SpringBootTelemetryInitializer(Environment environment) { this.environment = environment; } @Override - public void initialize(TelemetryContext telemetryContext) { + public void initialize(Telemetry telemetry) { RelaxedPropertyResolver relaxedPropertyResolver = new RelaxedPropertyResolver(environment); - telemetryContext.getTags().put("ai.spring-boot.version", SpringBootVersion.getVersion()); - telemetryContext.getTags().put("ai.spring.version", SpringVersion.getVersion()); + telemetry.getProperties().put("ai.spring-boot.version", SpringBootVersion.getVersion()); + telemetry.getProperties().put("ai.spring.version", SpringVersion.getVersion()); String ipAddress = relaxedPropertyResolver.getProperty("spring.cloud.client.ipAddress"); if (ipAddress != null) { // if spring-cloud is available we can set ip address - telemetryContext.getTags().put(ContextTagKeys.getKeys().getLocationIP(), ipAddress); + telemetry.getProperties().put(ContextTagKeys.getKeys().getLocationIP(), ipAddress); } + } } From 1580e79bdc47fe8a673f896add288c36219d374b Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Sun, 8 Apr 2018 21:39:53 -0700 Subject: [PATCH 22/43] updating enabling web modules and enabling AI, adding autoconfiguration for JMX counters and JVM counters --- .../build.gradle | 7 +- ...pplicationInsightsModuleConfiguration.java | 18 +++ .../boot/ApplicationInsightsProperties.java | 65 ++++++++- ...ionInsightsTelemetryAutoConfiguration.java | 135 ++++++++++++++++++ ...icationInsightsWebModuleConfiguration.java | 4 +- ...cationInsightsWebMvcAutoConfiguration.java | 2 +- ...itional-spring-configuration-metadata.json | 6 + .../PerformanceCounterContainer.java | 2 +- 8 files changed, 231 insertions(+), 8 deletions(-) diff --git a/azure-application-insights-spring-boot-starter/build.gradle b/azure-application-insights-spring-boot-starter/build.gradle index 8f96f97646a..9c491f93ec7 100644 --- a/azure-application-insights-spring-boot-starter/build.gradle +++ b/azure-application-insights-spring-boot-starter/build.gradle @@ -32,13 +32,14 @@ dependencies { provided('org.springframework.boot:spring-boot-starter-web:1.5.9.RELEASE') provided('org.springframework.boot:spring-boot-configuration-processor:1.5.9.RELEASE') - testCompile('org.junit.jupiter:junit-jupiter-api:5.0.2') - testCompile('org.junit.jupiter:junit-jupiter-params:5.0.2') - testCompile('org.junit.jupiter:junit-jupiter-engine:5.0.2') + testCompile('org.junit.jupiter:junit-jupiter-api:5.1.1') + testCompile('org.junit.jupiter:junit-jupiter-params:5.1.1') + testCompile('org.junit.jupiter:junit-jupiter-engine:5.1.1') testCompile('org.springframework.boot:spring-boot-starter-test:1.5.9.RELEASE') testCompile('org.assertj:assertj-core:3.9.0') } +compileJava.dependsOn(processResources) // region Publishing properties projectPomName = project.msftAppInsightsJavaSdk + " Spring Boot starter" diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java index b8c5dad33a5..d3bb47e8e5d 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java @@ -26,10 +26,12 @@ import com.microsoft.applicationinsights.boot.initializer.SpringBootTelemetryInitializer; import com.microsoft.applicationinsights.extensibility.initializer.DeviceInfoContextInitializer; import com.microsoft.applicationinsights.extensibility.initializer.SdkVersionContextInitializer; +import com.microsoft.applicationinsights.internal.perfcounter.JvmPerformanceCountersModule; import com.microsoft.applicationinsights.internal.perfcounter.ProcessPerformanceCountersModule; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; import org.springframework.core.env.Environment; /** @@ -38,6 +40,7 @@ * @author Arthur Gavlyukovskiy */ @Configuration +@ConditionalOnProperty(value = "azure.application-insights.enabled", havingValue = "true", matchIfMissing = true) public class ApplicationInsightsModuleConfiguration { @Bean @@ -56,6 +59,7 @@ public DeviceInfoContextInitializer deviceInfoContextInitializer() { } @Bean + @DependsOn("performanceCounterContainer") @ConditionalOnOperatingSystem(OperatingSystem.WINDOWS) @ConditionalOnProperty(value = "azure.application-insights.default-modules.ProcessPerformanceCountersModule.enabled", havingValue = "true", matchIfMissing = true) public ProcessPerformanceCountersModule processPerformanceCountersModule() { @@ -67,4 +71,18 @@ public ProcessPerformanceCountersModule processPerformanceCountersModule() { "please set property 'azure.application-insights.default-modules.ProcessPerformanceCountersModule.enabled=false' to avoid this error message.", e); } } + + @Bean + @DependsOn("performanceCounterContainer") + @ConditionalOnProperty(value = "azure.application-insights.default.modules.JvmPerformanceCountersModule.enabled", havingValue = "true", matchIfMissing = true) + public JvmPerformanceCountersModule jvmPerformanceCountersModule() { + try { + return new JvmPerformanceCountersModule(); + } + catch (Exception e) { + throw new IllegalStateException("Could not initialize Jvm Performance Counters module " + + "please set the property 'azure.application-insights.default.modules.JvmPerformanceCountersModule.enabled=false' to " + + "avoid this error message", e); + } + } } diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java index 96c8a567887..438624d15d3 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java @@ -28,6 +28,7 @@ import com.microsoft.applicationinsights.internal.channel.samplingV2.TelemetryType; import com.microsoft.applicationinsights.internal.logger.InternalLogger.LoggerOutputType; import com.microsoft.applicationinsights.internal.logger.InternalLogger.LoggingLevel; +import com.microsoft.applicationinsights.internal.perfcounter.PerformanceCounterContainer; import com.microsoft.applicationinsights.web.extensibility.initializers.WebOperationIdTelemetryInitializer; import com.microsoft.applicationinsights.web.extensibility.initializers.WebOperationNameTelemetryInitializer; import com.microsoft.applicationinsights.web.extensibility.initializers.WebSessionTelemetryInitializer; @@ -37,10 +38,9 @@ import com.microsoft.applicationinsights.web.extensibility.modules.WebSessionTrackingTelemetryModule; import com.microsoft.applicationinsights.web.extensibility.modules.WebUserTrackingTelemetryModule; import com.microsoft.applicationinsights.web.internal.perfcounter.WebPerformanceCounterModule; -import org.springframework.boot.context.properties.ConfigurationProperties; - import java.util.ArrayList; import java.util.List; +import org.springframework.boot.context.properties.ConfigurationProperties; /** * {@link ConfigurationProperties} for configuring application insights. @@ -79,6 +79,17 @@ public class ApplicationInsightsProperties { */ private Logger logger = new Logger(); + /** + * Performance Counter Container Properties + */ + + private PerformanceCounter performanceCounter = new PerformanceCounter(); + + /** + * Jmx Counter container + */ + private Jmx jmx = new Jmx(); + public boolean isEnabled() { return enabled; } @@ -133,6 +144,24 @@ public Logger getLogger() { public void setLogger(Logger logger) { this.logger = logger; + + } + + public PerformanceCounter getPerformanceCounter() { + return performanceCounter; + } + + public void setPerformanceCounter( + PerformanceCounter performanceCounter) { + this.performanceCounter = performanceCounter; + } + + public Jmx getJmx() { + return jmx; + } + + public void setJmx(Jmx jmx) { + this.jmx = jmx; } static class Channel { @@ -365,4 +394,36 @@ public void setLevel(LoggingLevel level) { this.level = level; } } + + static class PerformanceCounter { + + /** + * Default collection frequency of performance counters + */ + private long collectionFrequencyInSeconds = PerformanceCounterContainer.DEFAULT_COLLECTION_FREQUENCY_IN_SEC; + + public long getCollectionFrequencyInSeconds() { + return collectionFrequencyInSeconds; + } + + public void setCollectionFrequencyInSeconds(long collectionFrequencyInSeconds) { + this.collectionFrequencyInSeconds = collectionFrequencyInSeconds; + } + } + + static class Jmx { + + /** + * List of JMX counters + */ + List jmxCounters = new ArrayList<>(); + + public List getJmxCounters() { + return jmxCounters; + } + + public void setJmxCounters(List jmxCounters) { + this.jmxCounters = jmxCounters; + } + } } diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java index a5a68c1598a..5e397a5ab79 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java @@ -24,6 +24,7 @@ import com.microsoft.applicationinsights.TelemetryClient; import com.microsoft.applicationinsights.TelemetryConfiguration; import com.microsoft.applicationinsights.boot.ApplicationInsightsProperties.Channel.InProcess; +import com.microsoft.applicationinsights.boot.ApplicationInsightsProperties.PerformanceCounter; import com.microsoft.applicationinsights.boot.ApplicationInsightsProperties.TelemetryProcessor.Sampling; import com.microsoft.applicationinsights.channel.TelemetryChannel; import com.microsoft.applicationinsights.channel.concrete.inprocess.InProcessTelemetryChannel; @@ -33,8 +34,13 @@ import com.microsoft.applicationinsights.extensibility.TelemetryProcessor; import com.microsoft.applicationinsights.internal.channel.samplingV2.FixedRateSamplingTelemetryProcessor; import com.microsoft.applicationinsights.internal.channel.samplingV2.TelemetryType; +import com.microsoft.applicationinsights.internal.jmx.JmxAttributeData; import com.microsoft.applicationinsights.internal.logger.InternalLogger; +import com.microsoft.applicationinsights.internal.perfcounter.JmxMetricPerformanceCounter; +import com.microsoft.applicationinsights.internal.perfcounter.PerformanceCounterContainer; import com.microsoft.applicationinsights.internal.quickpulse.QuickPulse; +import java.util.ArrayList; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -164,4 +170,133 @@ public InternalLogger internalLogger() { InternalLogger.INSTANCE.initialize(logger.getType().name(), loggerParameters); return InternalLogger.INSTANCE; } + + @Bean + public PerformanceCounterContainer performanceCounterContainer() { + ApplicationInsightsProperties.PerformanceCounter performanceCounter = applicationInsightsProperties.getPerformanceCounter(); + PerformanceCounterContainer.INSTANCE.setCollectionFrequencyInSec(performanceCounter.getCollectionFrequencyInSeconds()); + + ApplicationInsightsProperties.Jmx jmx = applicationInsightsProperties.getJmx(); + if (jmx.getJmxCounters() !=null && jmx.getJmxCounters().size() > 0) { + processAndLoadJmxCounters(jmx.getJmxCounters()); + } + return PerformanceCounterContainer.INSTANCE; + } + + private void processAndLoadJmxCounters(List jmxCounterList) { + + try { + Map> data = new HashMap<>(); + for (String jmxCounter : jmxCounterList) { + CompositeJmxData compositeJmxData = convertToCompositeJmxData(jmxCounter); + if (compositeJmxData == null) { + InternalLogger.INSTANCE.warn("unable to add Jmx counter %s", jmxCounter); + } else { + List collection = data.get(compositeJmxData.getObjectName()); + if (collection == null) { + collection = new ArrayList<>(); + data.put(compositeJmxData.getObjectName(), collection); + } + collection.add(new JmxAttributeData(compositeJmxData.getDisplayName(), + compositeJmxData.getAttributeName(), compositeJmxData.getType())); + } + } + + //Register each entry in performance counter container + for (Map.Entry> entry : data.entrySet()) { + try { + if (PerformanceCounterContainer.INSTANCE.register(new JmxMetricPerformanceCounter( + entry.getKey(), entry.getKey(), entry.getValue() + ))) { + InternalLogger.INSTANCE.trace("Registered Jmx performance counter %s", + entry.getKey()); + } + else { + InternalLogger.INSTANCE.trace("Failed to register Jmx performance" + + " counter %s", entry.getKey()); + } + } + catch (Exception e) { + InternalLogger.INSTANCE.warn("Failed to register Jmx performance counter," + + " of object name %s Stack trace is %s", entry.getKey(), ExceptionUtils.getStackTrace(e)); + } + } + } + catch (Exception e) { + InternalLogger.INSTANCE.warn("Unable to add Jmx performance counter. Exception is" + + " %s", ExceptionUtils.getStackTrace(e)); + } + } + + + private class CompositeJmxData { + String displayName; + String objectName; + String attributeName; + String type; + + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + public String getObjectName() { + return objectName; + } + + public void setObjectName(String objectName) { + this.objectName = objectName; + } + + public String getAttributeName() { + return attributeName; + } + + public void setAttributeName(String attributeName) { + this.attributeName = attributeName; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + if (this.type != null) { + this.type = this.type.toUpperCase(); + } + } + } + + private CompositeJmxData convertToCompositeJmxData(String jmxCounter) { + if (jmxCounter != null && jmxCounter.length() > 0) { + String[] attributes = jmxCounter.split("/"); + if (attributes.length < 3) { + InternalLogger.INSTANCE.warn("Missing either objectName or attributeName or" + + " display name. Jmx counter %s will not be added" , jmxCounter); + return null; + } + CompositeJmxData data = new CompositeJmxData(); + for (int i = 0; i < attributes.length; ++i) { + if (i > 3) break; + if (i == 0) { + data.setObjectName(attributes[0]); + } + else if (i == 1) { + data.setAttributeName(attributes[1]); + } + else if (i == 2) { + data.setDisplayName(attributes[2]); + } + else { + data.setType(attributes[3]); + } + } + return data; + } + return null; + } } diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java index 13f77402357..6740612efd0 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java @@ -34,6 +34,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; /** * {@link Configuration} for web applications. @@ -41,7 +42,7 @@ * @author Arthur Gavlyukovskiy */ @Configuration -@ConditionalOnProperty(value = "azure.application-insights.enabled", havingValue = "true", matchIfMissing = true) +@ConditionalOnProperty(value = "azure.application-insights.web.enabled", havingValue = "true", matchIfMissing = true) @ConditionalOnWebApplication public class ApplicationInsightsWebModuleConfiguration { @@ -64,6 +65,7 @@ public WebUserTrackingTelemetryModule webUserTrackingTelemetryModule() { } @Bean + @DependsOn("performanceCounterContainer") @ConditionalOnProperty(value = "azure.application-insights.default-modules.WebPerformanceCounterModule.enabled", havingValue = "true", matchIfMissing = true) public WebPerformanceCounterModule webPerformanceCounterModule() { return new WebPerformanceCounterModule(); diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java index b5b3701d7bb..efb3bb4049b 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java @@ -41,7 +41,7 @@ @Import(InterceptorRegistry.class) @ConditionalOnBean(TelemetryConfiguration.class) @ConditionalOnWebApplication -@ConditionalOnProperty(value = "azure.application-insights.enabled", havingValue = "true", matchIfMissing = true) +@ConditionalOnProperty(value = "azure.application-insights.web.enabled", havingValue = "true", matchIfMissing = true) @AutoConfigureAfter(ApplicationInsightsTelemetryAutoConfiguration.class) public class ApplicationInsightsWebMvcAutoConfiguration { diff --git a/azure-application-insights-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/azure-application-insights-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 6b82884dbd7..923d5a1e734 100644 --- a/azure-application-insights-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/azure-application-insights-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -59,6 +59,12 @@ "type": "java.lang.Boolean", "description": "Enable WebUserAgentTelemetryInitializer.", "defaultValue": "true" + }, + { + "name": "azure.application-insights.default.modules.JvmPerformanceCountersModule.enabled", + "type":"java.lang.Boolean", + "description": "Enable JvmPerformanceCountersModule.", + "defaultValue": true } ] } \ No newline at end of file diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/perfcounter/PerformanceCounterContainer.java b/core/src/main/java/com/microsoft/applicationinsights/internal/perfcounter/PerformanceCounterContainer.java index de11b112e6d..6fa1f9e5ce8 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/perfcounter/PerformanceCounterContainer.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/perfcounter/PerformanceCounterContainer.java @@ -63,7 +63,7 @@ public enum PerformanceCounterContainer implements Stoppable { private final static long START_DEFAULT_MIN_DELAY_IN_MILLIS = 20000; // By default the container will collect performance data every 1 minute. - private final static long DEFAULT_COLLECTION_FREQUENCY_IN_SEC = 60; + public final static long DEFAULT_COLLECTION_FREQUENCY_IN_SEC = 60; private final static long MIN_COLLECTION_FREQUENCY_IN_SEC = 1; private final ConcurrentMap performanceCounters = new ConcurrentHashMap(); From 3d194e5201f023f133c152ccc4a9e52228a3892f Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Mon, 9 Apr 2018 15:09:42 -0700 Subject: [PATCH 23/43] migrate tests to junit4 --- .../build.gradle | 7 ++-- ...sightsTelemetryAutoConfigurationTests.java | 35 ++++++++++--------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/azure-application-insights-spring-boot-starter/build.gradle b/azure-application-insights-spring-boot-starter/build.gradle index 9c491f93ec7..4e6dae53b50 100644 --- a/azure-application-insights-spring-boot-starter/build.gradle +++ b/azure-application-insights-spring-boot-starter/build.gradle @@ -32,9 +32,10 @@ dependencies { provided('org.springframework.boot:spring-boot-starter-web:1.5.9.RELEASE') provided('org.springframework.boot:spring-boot-configuration-processor:1.5.9.RELEASE') - testCompile('org.junit.jupiter:junit-jupiter-api:5.1.1') - testCompile('org.junit.jupiter:junit-jupiter-params:5.1.1') - testCompile('org.junit.jupiter:junit-jupiter-engine:5.1.1') +// testCompile('org.junit.jupiter:junit-jupiter-api:5.1.1') +// testCompile('org.junit.jupiter:junit-jupiter-params:5.1.1') +// testCompile('org.junit.jupiter:junit-jupiter-engine:5.1.1') + testCompile('junit:junit:4.12') testCompile('org.springframework.boot:spring-boot-starter-test:1.5.9.RELEASE') testCompile('org.assertj:assertj-core:3.9.0') } diff --git a/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java b/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java index a7ca0e8bc80..0cef6174185 100644 --- a/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java +++ b/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java @@ -21,6 +21,8 @@ package com.microsoft.applicationinsights.boot; +import static org.assertj.core.api.Assertions.assertThat; + import com.microsoft.applicationinsights.TelemetryClient; import com.microsoft.applicationinsights.TelemetryConfiguration; import com.microsoft.applicationinsights.channel.TelemetryChannel; @@ -36,29 +38,27 @@ import com.microsoft.applicationinsights.telemetry.Telemetry; import com.microsoft.applicationinsights.telemetry.TelemetryContext; import com.microsoft.applicationinsights.web.extensibility.modules.WebUserTrackingTelemetryModule; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; +import org.junit.After; +import org.junit.Test; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.test.util.EnvironmentTestUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; -import static org.assertj.core.api.Assertions.assertThat; - /** * @author Arthur Gavlyukovskiy */ -class ApplicationInsightsTelemetryAutoConfigurationTests { +public final class ApplicationInsightsTelemetryAutoConfigurationTests { private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - @AfterEach + @After public void restore() { context.close(); } @Test - void shouldSetInstrumentationKeyWhenContextLoads() { + public void shouldSetInstrumentationKeyWhenContextLoads() { EnvironmentTestUtils.addEnvironment(context, "azure.application-insights.instrumentation-key: 00000000-0000-0000-0000-000000000000"); context.register(PropertyPlaceholderAutoConfiguration.class, @@ -71,10 +71,11 @@ void shouldSetInstrumentationKeyWhenContextLoads() { assertThat(telemetryConfiguration).isSameAs(TelemetryConfiguration.getActive()); assertThat(telemetryConfiguration.getInstrumentationKey()).isEqualTo("00000000-0000-0000-0000-000000000000"); assertThat(telemetryClient.getContext().getInstrumentationKey()).isEqualTo("00000000-0000-0000-0000-000000000000"); + } @Test - void shouldSetInstrumentationKeyFromRelaxedCase() { + public void shouldSetInstrumentationKeyFromRelaxedCase() { EnvironmentTestUtils.addEnvironment(context, "AZURE.APPLICATION_INSIGHTS.INSTRUMENTATION_KEY: 00000000-0000-0000-0000-000000000000"); context.register(PropertyPlaceholderAutoConfiguration.class, @@ -90,7 +91,7 @@ void shouldSetInstrumentationKeyFromRelaxedCase() { } @Test - void shouldReloadInstrumentationKeyOnTelemetryClient() { + public void shouldReloadInstrumentationKeyOnTelemetryClient() { TelemetryClient myClient = new TelemetryClient(); EventTelemetry eventTelemetry1 = new EventTelemetry("test1"); @@ -109,7 +110,7 @@ void shouldReloadInstrumentationKeyOnTelemetryClient() { } @Test - void shouldNotFailIfInstrumentationKeyIsNotSet() { + public void shouldNotFailIfInstrumentationKeyIsNotSet() { context.register(PropertyPlaceholderAutoConfiguration.class, ApplicationInsightsTelemetryAutoConfiguration.class); context.refresh(); @@ -119,7 +120,7 @@ void shouldNotFailIfInstrumentationKeyIsNotSet() { } @Test - void shouldBeAbleToDisableInstrumentationByProperty() { + public void shouldBeAbleToDisableInstrumentationByProperty() { EnvironmentTestUtils.addEnvironment(context, "azure.application-insights.enabled: false", "azure.application-insights.instrumentation-key: 00000000-0000-0000-0000-000000000000"); @@ -132,7 +133,7 @@ void shouldBeAbleToDisableInstrumentationByProperty() { } @Test - void shouldBeAbleToConfigureTelemetryChannel() { + public void shouldBeAbleToConfigureTelemetryChannel() { EnvironmentTestUtils.addEnvironment(context, "azure.application-insights.instrumentation-key: 00000000-0000-0000-0000-000000000000", "azure.application-insights.channel.in-process.developer-mode=false", @@ -152,7 +153,7 @@ void shouldBeAbleToConfigureTelemetryChannel() { } @Test - void shouldBeAbleToConfigureSamplingTelemetryProcessor() { + public void shouldBeAbleToConfigureSamplingTelemetryProcessor() { EnvironmentTestUtils.addEnvironment(context, "azure.application-insights.instrumentation-key: 00000000-0000-0000-0000-000000000000", "azure.application-insights.telemetry-processor.sampling.percentage=50", @@ -171,7 +172,7 @@ void shouldBeAbleToConfigureSamplingTelemetryProcessor() { } @Test - void shouldBeAbleToDisableAllWebModules() { + public void shouldBeAbleToDisableAllWebModules() { EnvironmentTestUtils.addEnvironment(context, "azure.application-insights.instrumentation-key: 00000000-0000-0000-0000-000000000000", "azure.application-insights.web.enabled=false"); @@ -183,7 +184,7 @@ void shouldBeAbleToDisableAllWebModules() { } @Test - void internalLoggerShouldBeInitializedBeforeTelemetryConfiguration() { + public void internalLoggerShouldBeInitializedBeforeTelemetryConfiguration() { EnvironmentTestUtils.addEnvironment(context, "azure.application-insights.instrumentation-key: 00000000-0000-0000-0000-000000000000", "azure.application-insights.logger.level=INFO" @@ -197,7 +198,7 @@ void internalLoggerShouldBeInitializedBeforeTelemetryConfiguration() { } @Test - void shouldBeAbleToDisableDefaultModules() { + public void shouldBeAbleToDisableDefaultModules() { EnvironmentTestUtils.addEnvironment(context, "azure.application-insights.instrumentation-key: 00000000-0000-0000-0000-000000000000", "azure.application-insights.default-modules.WebUserTrackingTelemetryModule.enabled=false"); @@ -209,7 +210,7 @@ void shouldBeAbleToDisableDefaultModules() { } @Test - void shouldBeAbleToAddCustomModules() { + public void shouldBeAbleToAddCustomModules() { EnvironmentTestUtils.addEnvironment(context, "azure.application-insights.instrumentation-key: 00000000-0000-0000-0000-000000000000"); context.register(PropertyPlaceholderAutoConfiguration.class, From b90254f89111c6e405cb594312b7c86ffe48bfbe Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Mon, 9 Apr 2018 17:39:20 -0700 Subject: [PATCH 24/43] adding more tests --- ...pplicationInsightsModuleConfiguration.java | 2 +- .../boot/ApplicationInsightsProperties.java | 2 +- ...ionInsightsTelemetryAutoConfiguration.java | 2 +- ...sightsTelemetryAutoConfigurationTests.java | 40 +++++++++++++++++-- 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java index d3bb47e8e5d..c49d7c47d83 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java @@ -37,7 +37,7 @@ /** * {@link Configuration} for non-web applications. * - * @author Arthur Gavlyukovskiy + * @author Arthur Gavlyukovskiy, Dhaval Doshi */ @Configuration @ConditionalOnProperty(value = "azure.application-insights.enabled", havingValue = "true", matchIfMissing = true) diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java index 438624d15d3..de2c180f667 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java @@ -45,7 +45,7 @@ /** * {@link ConfigurationProperties} for configuring application insights. * - * @author Arthur Gavlyukovskiy + * @author Arthur Gavlyukovskiy, Dhaval Doshi */ @ConfigurationProperties("azure.application-insights") public class ApplicationInsightsProperties { diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java index 5e397a5ab79..a2335942eaa 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java @@ -62,7 +62,7 @@ /** * Auto-configuration for application insights. Configures {@link TelemetryConfiguration} * - * @author Arthur Gavlyukovskiy + * @author Arthur Gavlyukovskiy, Dhaval Doshi */ @Configuration @ConditionalOnProperty(value = "azure.application-insights.instrumentation-key") diff --git a/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java b/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java index 0cef6174185..4c19065bd72 100644 --- a/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java +++ b/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java @@ -33,12 +33,18 @@ import com.microsoft.applicationinsights.extensibility.TelemetryProcessor; import com.microsoft.applicationinsights.internal.channel.samplingV2.FixedRateSamplingTelemetryProcessor; import com.microsoft.applicationinsights.internal.logger.InternalLogger; +import com.microsoft.applicationinsights.internal.perfcounter.JvmPerformanceCountersModule; +import com.microsoft.applicationinsights.internal.perfcounter.PerformanceCounter; +import com.microsoft.applicationinsights.internal.perfcounter.PerformanceCounterContainer; import com.microsoft.applicationinsights.telemetry.EventTelemetry; import com.microsoft.applicationinsights.telemetry.RequestTelemetry; import com.microsoft.applicationinsights.telemetry.Telemetry; import com.microsoft.applicationinsights.telemetry.TelemetryContext; import com.microsoft.applicationinsights.web.extensibility.modules.WebUserTrackingTelemetryModule; +import java.lang.reflect.Field; +import java.util.Map; import org.junit.After; +import org.junit.Ignore; import org.junit.Test; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.test.util.EnvironmentTestUtils; @@ -46,7 +52,7 @@ import org.springframework.context.annotation.Bean; /** - * @author Arthur Gavlyukovskiy + * @author Arthur Gavlyukovskiy, Dhaval Doshi */ public final class ApplicationInsightsTelemetryAutoConfigurationTests { @@ -71,7 +77,6 @@ public void shouldSetInstrumentationKeyWhenContextLoads() { assertThat(telemetryConfiguration).isSameAs(TelemetryConfiguration.getActive()); assertThat(telemetryConfiguration.getInstrumentationKey()).isEqualTo("00000000-0000-0000-0000-000000000000"); assertThat(telemetryClient.getContext().getInstrumentationKey()).isEqualTo("00000000-0000-0000-0000-000000000000"); - } @Test @@ -91,6 +96,7 @@ public void shouldSetInstrumentationKeyFromRelaxedCase() { } @Test + @Ignore public void shouldReloadInstrumentationKeyOnTelemetryClient() { TelemetryClient myClient = new TelemetryClient(); @@ -194,7 +200,6 @@ public void internalLoggerShouldBeInitializedBeforeTelemetryConfiguration() { context.refresh(); InternalLogger logger = context.getBean(InternalLogger.class); assertThat(logger.isInfoEnabled()).isEqualTo(true); - } @Test @@ -231,6 +236,35 @@ public void shouldBeAbleToAddCustomModules() { assertThat(telemetryConfiguration.getTelemetryProcessors()).contains(myTelemetryProcessor); } + @Test + public void shouldBeAbleToConfigureJmxPerformanceCounters() throws Exception{ + EnvironmentTestUtils.addEnvironment(context, + "azure.application-insights.instrumentation-key: 00000000-0000-0000-0000-000000000000", + "azure.application-insights.jmx.jmx-counters:" + + "java.lang:type=ClassLoading/LoadedClassCount/Current Loaded Class Count"); + context.register(PropertyPlaceholderAutoConfiguration.class, + ApplicationInsightsTelemetryAutoConfiguration.class); + context.refresh(); + + PerformanceCounterContainer counterContainer = context.getBean(PerformanceCounterContainer.class); + Field field = counterContainer.getClass().getDeclaredField("performanceCounters"); + field.setAccessible(true); + Map map = (Map)field.get(counterContainer); + assertThat(map.containsKey("java.lang:type=ClassLoading")).isNotNull(); + } + + @Test + public void shouldBeAbleToConfigureJvmPerformanceCounters() { + EnvironmentTestUtils.addEnvironment(context, + "azure.application-insights.instrumentation-key: 00000000-0000-0000-0000-000000000000", + "azure.application-insights.default.modules.JvmPerformanceCountersModule.enabled=true"); + context.register(PropertyPlaceholderAutoConfiguration.class, + ApplicationInsightsTelemetryAutoConfiguration.class); + context.refresh(); + + assertThat(context.getBeansOfType(JvmPerformanceCountersModule.class)).isNotEmpty(); + } + private static class CustomModuleConfiguration { @Bean From 9338c7add82891ad99dd70fdca6ccbede90159fd Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Tue, 10 Apr 2018 16:38:43 -0700 Subject: [PATCH 25/43] Heartbeat updates to accomodate autoconfig in SpringBoot --- .../TelemetryConfiguration.java | 7 ++++++ .../internal/heartbeat/HeartBeatProvider.java | 2 +- .../heartbeat/HeartbeatDefaultPayload.java | 8 +++++++ .../internal/heartbeat/MiscUtils.java | 4 ++-- .../internal/heartbeat/HeartbeatTests.java | 22 +++++++++++++++++++ 5 files changed, 40 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/com/microsoft/applicationinsights/TelemetryConfiguration.java b/core/src/main/java/com/microsoft/applicationinsights/TelemetryConfiguration.java index 68d01811fc0..9c91d9b89eb 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/TelemetryConfiguration.java +++ b/core/src/main/java/com/microsoft/applicationinsights/TelemetryConfiguration.java @@ -202,4 +202,11 @@ public void setInstrumentationKey(String key) { instrumentationKey = key; } + + /** + * Method for tear down in tests + */ + private static void setActiveAsNull() { + active = null; + } } diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/heartbeat/HeartBeatProvider.java b/core/src/main/java/com/microsoft/applicationinsights/internal/heartbeat/HeartBeatProvider.java index ae83669270b..59dcc9fdce7 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/heartbeat/HeartBeatProvider.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/heartbeat/HeartBeatProvider.java @@ -249,6 +249,7 @@ private void send() { MetricTelemetry telemetry = (MetricTelemetry)gatherData(); telemetry.getContext().getOperation().setSyntheticSource(HEARTBEAT_SYNTHETIC_METRIC_NAME); telemetryClient.trackMetric(telemetry); + heartbeatsSent.incrementAndGet(); InternalLogger.INSTANCE.trace("No of heartbeats sent, %s", heartbeatsSent.get()); } @@ -267,7 +268,6 @@ private Telemetry gatherData() { double currentValue = heartbeat.getValue(); currentValue += entry.getValue().isHealthy() ? 0 : 1; heartbeat.setValue(currentValue); - heartbeatsSent.incrementAndGet(); } return heartbeat; } diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/heartbeat/HeartbeatDefaultPayload.java b/core/src/main/java/com/microsoft/applicationinsights/internal/heartbeat/HeartbeatDefaultPayload.java index 8ab38aa1c1b..386b235ec9e 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/heartbeat/HeartbeatDefaultPayload.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/heartbeat/HeartbeatDefaultPayload.java @@ -23,6 +23,14 @@ public static boolean isDefaultKeyWord(String keyword) { return false; } + public static boolean addDefaultPayLoadProvider(HeartBeatDefaultPayloadProviderInterface payloadProviderInterface) { + if (payloadProviderInterface != null) { + defaultPayloadProviders.add(payloadProviderInterface); + return true; + } + return false; + } + public static Callable populateDefaultPayload(final List disabledFields, final List disabledProviders, final HeartBeatProviderInterface provider) { return new Callable() { diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/heartbeat/MiscUtils.java b/core/src/main/java/com/microsoft/applicationinsights/internal/heartbeat/MiscUtils.java index 9ffc39bca01..56af680d6cf 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/heartbeat/MiscUtils.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/heartbeat/MiscUtils.java @@ -12,7 +12,7 @@ * @author Dhaval Doshi * @since 03-30-2018 */ -class MiscUtils { +public class MiscUtils { /** * Returns a list which contains Items present in list2 but not in the set. @@ -20,7 +20,7 @@ class MiscUtils { * @param list2 * @return */ - static Set except(Set set, List list2) { + public static Set except(Set set, List list2) { try { if (set == null || list2 == null) throw new IllegalArgumentException("Input is null"); Set result = new HashSet<>(); diff --git a/core/src/test/java/com/microsoft/applicationinsights/internal/heartbeat/HeartbeatTests.java b/core/src/test/java/com/microsoft/applicationinsights/internal/heartbeat/HeartbeatTests.java index 9f43b5e3053..ba4fb5e4ee7 100644 --- a/core/src/test/java/com/microsoft/applicationinsights/internal/heartbeat/HeartbeatTests.java +++ b/core/src/test/java/com/microsoft/applicationinsights/internal/heartbeat/HeartbeatTests.java @@ -14,11 +14,20 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.junit.After; +import org.junit.AfterClass; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; public class HeartbeatTests { + @Before + public void setTelemetryConfigurationNull() throws Exception{ + tearDown(); + } + @Test public void initializeHeartBeatModuleDoesNotThrow() { HeartBeatModule module = new HeartBeatModule(new HashMap()); @@ -114,6 +123,7 @@ public void initializationOfTelemetryClientDoesNotResetHeartbeat() { public void heartBeatIsEnabledByDefault() { TelemetryClient client = new TelemetryClient(); List modules = TelemetryConfiguration.getActive().getTelemetryModules(); + System.out.println(modules.size()); boolean hasHeartBeatModule = false; HeartBeatModule hbm = null; for (TelemetryModule m : modules) { @@ -123,6 +133,7 @@ public void heartBeatIsEnabledByDefault() { break; } } + System.out.println(hasHeartBeatModule); Assert.assertTrue(hasHeartBeatModule); Assert.assertNotNull(hbm); Assert.assertTrue(hbm.isHeartBeatEnabled()); @@ -305,4 +316,15 @@ public void configurationParsingWorksAsExpectedWhenMultipleParamsArePassed() Assert.assertTrue(module.getExcludedHeartBeatPropertiesProvider().contains("Base")); Assert.assertTrue(module.getExcludedHeartBeatPropertiesProvider().contains("webapps")); } + + @AfterClass + public static void tear() throws Exception{ + tearDown(); + } + + private static void tearDown() throws Exception{ + Method method = TelemetryConfiguration.class.getDeclaredMethod("setActiveAsNull"); + method.setAccessible(true); + method.invoke(null); + } } From 7b60bc2cb5ecf5df744a61fd224299c9ddec9ec7 Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Tue, 10 Apr 2018 17:18:02 -0700 Subject: [PATCH 26/43] Adding auto cofiguration for SpringBoot --- ...pplicationInsightsModuleConfiguration.java | 41 ++++++- .../boot/ApplicationInsightsProperties.java | 59 ++++++++- .../SpringBootHeartBeatProvider.java | 113 ++++++++++++++++++ ...sightsTelemetryAutoConfigurationTests.java | 10 ++ 4 files changed, 218 insertions(+), 5 deletions(-) create mode 100644 azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/HeartBeatProvider/SpringBootHeartBeatProvider.java diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java index c49d7c47d83..e49c93c9781 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java @@ -21,14 +21,21 @@ package com.microsoft.applicationinsights.boot; +import com.microsoft.applicationinsights.boot.ApplicationInsightsProperties.HeartBeat; +import com.microsoft.applicationinsights.boot.HeartBeatProvider.SpringBootHeartBeatProvider; import com.microsoft.applicationinsights.boot.conditional.ConditionalOnOperatingSystem; import com.microsoft.applicationinsights.boot.conditional.OperatingSystem; import com.microsoft.applicationinsights.boot.initializer.SpringBootTelemetryInitializer; import com.microsoft.applicationinsights.extensibility.initializer.DeviceInfoContextInitializer; import com.microsoft.applicationinsights.extensibility.initializer.SdkVersionContextInitializer; +import com.microsoft.applicationinsights.internal.heartbeat.HeartBeatModule; +import com.microsoft.applicationinsights.internal.heartbeat.HeartbeatDefaultPayload; +import com.microsoft.applicationinsights.internal.logger.InternalLogger; import com.microsoft.applicationinsights.internal.perfcounter.JvmPerformanceCountersModule; import com.microsoft.applicationinsights.internal.perfcounter.ProcessPerformanceCountersModule; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; @@ -40,13 +47,17 @@ * @author Arthur Gavlyukovskiy, Dhaval Doshi */ @Configuration +@EnableConfigurationProperties(ApplicationInsightsProperties.class) @ConditionalOnProperty(value = "azure.application-insights.enabled", havingValue = "true", matchIfMissing = true) public class ApplicationInsightsModuleConfiguration { - @Bean - public SpringBootTelemetryInitializer springBootTelemetryInitializer(Environment environment) { - return new SpringBootTelemetryInitializer(environment); - } + @Autowired + ApplicationInsightsProperties applicationInsightsProperties; + +// @Bean +// public SpringBootTelemetryInitializer springBootTelemetryInitializer(Environment environment) { +// return new SpringBootTelemetryInitializer(environment); +// } @Bean public SdkVersionContextInitializer sdkVersionContextInitializer() { @@ -85,4 +96,26 @@ public JvmPerformanceCountersModule jvmPerformanceCountersModule() { + "avoid this error message", e); } } + + @Bean + @ConditionalOnProperty(value = "azure.application-insights.default.modules.HearBeat.enabled", havingValue = "true", matchIfMissing = true) + public HeartBeatModule heartBeatModule(Environment environment) { + try { + HeartBeatModule heartBeatModule = new HeartBeatModule(null); + HeartbeatDefaultPayload.addDefaultPayLoadProvider(new SpringBootHeartBeatProvider(environment)); + HeartBeat heartBeat = applicationInsightsProperties.getHeartBeat(); + heartBeatModule.setHeartBeatInterval(heartBeat.getHeartBeatInterval()); + if (heartBeat.getExcludedHeartBeatPropertiesList().size() > 0) { + heartBeatModule.setExcludedHeartBeatProperties(heartBeat.getExcludedHeartBeatPropertiesList()); + } + if (heartBeat.getExcludedHeartBeatProviderList().size() > 0) { + heartBeatModule.setExcludedHeartBeatPropertiesProvider(heartBeat.getExcludedHeartBeatProviderList()); + } + return heartBeatModule; + } + catch (Exception e) { + throw new IllegalStateException("could not configure Heartbeat, please disable 'azure.application-insights.default.modules.HearBeat.enabled'" + + " to false ", e); + } + } } diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java index de2c180f667..ec92b902ded 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java @@ -26,6 +26,7 @@ import com.microsoft.applicationinsights.internal.channel.common.TransmissionNetworkOutput; import com.microsoft.applicationinsights.internal.channel.samplingV2.FixedRateSamplingTelemetryProcessor; import com.microsoft.applicationinsights.internal.channel.samplingV2.TelemetryType; +import com.microsoft.applicationinsights.internal.heartbeat.HeartBeatProvider; import com.microsoft.applicationinsights.internal.logger.InternalLogger.LoggerOutputType; import com.microsoft.applicationinsights.internal.logger.InternalLogger.LoggingLevel; import com.microsoft.applicationinsights.internal.perfcounter.PerformanceCounterContainer; @@ -90,6 +91,8 @@ public class ApplicationInsightsProperties { */ private Jmx jmx = new Jmx(); + private HeartBeat heartBeat = new HeartBeat(); + public boolean isEnabled() { return enabled; } @@ -164,7 +167,16 @@ public void setJmx(Jmx jmx) { this.jmx = jmx; } - static class Channel { + public HeartBeat getHeartBeat() { + return heartBeat; + } + + public void setHeartBeat( + HeartBeat heartBeat) { + this.heartBeat = heartBeat; + } + + static class Channel { /** * Configuration of {@link InProcessTelemetryChannel}. */ @@ -426,4 +438,49 @@ public void setJmxCounters(List jmxCounters) { this.jmxCounters = jmxCounters; } } + + static class HeartBeat { + + boolean isEnabled = false; + + long heartBeatInterval = HeartBeatProvider.DEFAULT_HEARTBEAT_INTERVAL; + + List excludedHeartBeatProviderList = new ArrayList<>(); + + List excludedHeartBeatPropertiesList = new ArrayList<>(); + + public boolean isEnabled() { + return isEnabled; + } + + public void setEnabled(boolean enabled) { + isEnabled = enabled; + } + + public long getHeartBeatInterval() { + return heartBeatInterval; + } + + public void setHeartBeatInterval(long heartBeatInterval) { + this.heartBeatInterval = heartBeatInterval; + } + + public List getExcludedHeartBeatProviderList() { + return excludedHeartBeatProviderList; + } + + public void setExcludedHeartBeatProviderList( + List excludedHeartBeatProviderList) { + this.excludedHeartBeatProviderList = excludedHeartBeatProviderList; + } + + public List getExcludedHeartBeatPropertiesList() { + return excludedHeartBeatPropertiesList; + } + + public void setExcludedHeartBeatPropertiesList( + List excludedHeartBeatPropertiesList) { + this.excludedHeartBeatPropertiesList = excludedHeartBeatPropertiesList; + } + } } diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/HeartBeatProvider/SpringBootHeartBeatProvider.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/HeartBeatProvider/SpringBootHeartBeatProvider.java new file mode 100644 index 00000000000..02b8765eddb --- /dev/null +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/HeartBeatProvider/SpringBootHeartBeatProvider.java @@ -0,0 +1,113 @@ +package com.microsoft.applicationinsights.boot.HeartBeatProvider; + +import com.microsoft.applicationinsights.internal.heartbeat.HeartBeatDefaultPayloadProviderInterface; +import com.microsoft.applicationinsights.internal.heartbeat.HeartBeatProviderInterface; +import com.microsoft.applicationinsights.internal.heartbeat.MiscUtils; +import com.microsoft.applicationinsights.internal.logger.InternalLogger; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.Callable; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.boot.SpringBootVersion; +import org.springframework.core.SpringVersion; +import org.springframework.core.env.Environment; + +public class SpringBootHeartBeatProvider implements HeartBeatDefaultPayloadProviderInterface { + + /** + * Collection holding default properties for this default provider. + */ + private final Set defaultFields; + + /** + * Name of this provider. + */ + private final String name = "SpringBootProvider"; + + private final Environment environment; + + public SpringBootHeartBeatProvider(Environment environment) { + defaultFields = new HashSet<>(); + this.environment = environment; + initializeDefaultFields(defaultFields); + } + + @Override + + public String getName() { + return this.name; + } + + @Override + public boolean isKeyWord(String keyword) { + return defaultFields.contains(keyword); + } + + @Override + public Callable setDefaultPayload(final List disableFields, + final HeartBeatProviderInterface provider) { + return new Callable() { + + // using volatile here to avoid caching in threads. + volatile boolean hasSetValues = false; + volatile Set enabledProperties = MiscUtils.except(defaultFields, disableFields); + @Override + public Boolean call() { + for (String fieldName : enabledProperties) { + try { + switch (fieldName) { + case "ai.spring-boot.version": + provider.addHeartBeatProperty(fieldName, getSpringBootVersion(), true); + hasSetValues = true; + break; + case "ai.spring.version": + provider.addHeartBeatProperty(fieldName, getSpringVersion(), true); + hasSetValues = true; + break; + default: + //We won't accept unknown properties in default providers. + InternalLogger.INSTANCE.trace("Encountered unknown default property"); + break; + } + } + catch (Exception e) { + InternalLogger.INSTANCE.warn("Failed to obtain heartbeat property, stack trace" + + "is: %s", ExceptionUtils.getStackTrace(e)); + } + } + return hasSetValues; + } + }; + } + + /** + * This method initializes the collection with Default Properties of this provider. + * @param defaultFields collection to hold default properties. + */ + private void initializeDefaultFields(Set defaultFields) { + + if (defaultFields == null) { + defaultFields = new HashSet<>(); + } + defaultFields.add("ai.spring-boot.version"); + defaultFields.add("ai.spring.version"); + } + + /** + * Gets the version of SpringBoot + * @return returns springboot version string + */ + private String getSpringBootVersion() { + return SpringBootVersion.getVersion(); + } + + /** + * Gets the Spring Framework version + * @return returns the SpringFrameWork version String + */ + private String getSpringVersion() { + return SpringVersion.getVersion(); + } + +} diff --git a/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java b/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java index 4c19065bd72..9f4dc94f1af 100644 --- a/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java +++ b/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java @@ -32,6 +32,7 @@ import com.microsoft.applicationinsights.extensibility.TelemetryModule; import com.microsoft.applicationinsights.extensibility.TelemetryProcessor; import com.microsoft.applicationinsights.internal.channel.samplingV2.FixedRateSamplingTelemetryProcessor; +import com.microsoft.applicationinsights.internal.config.TelemetryConfigurationFactory; import com.microsoft.applicationinsights.internal.logger.InternalLogger; import com.microsoft.applicationinsights.internal.perfcounter.JvmPerformanceCountersModule; import com.microsoft.applicationinsights.internal.perfcounter.PerformanceCounter; @@ -42,8 +43,10 @@ import com.microsoft.applicationinsights.telemetry.TelemetryContext; import com.microsoft.applicationinsights.web.extensibility.modules.WebUserTrackingTelemetryModule; import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.util.Map; import org.junit.After; +import org.junit.AfterClass; import org.junit.Ignore; import org.junit.Test; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; @@ -304,4 +307,11 @@ public boolean process(Telemetry telemetry) { }; } } + + @AfterClass + public static void tearDown() throws Exception { + Method method = TelemetryConfiguration.class.getDeclaredMethod("setActiveAsNull"); + method.setAccessible(true); + method.invoke(null); + } } \ No newline at end of file From fd1f2ebe8e566b5127eefc4b0e73e08c7871ba50 Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Tue, 10 Apr 2018 17:52:28 -0700 Subject: [PATCH 27/43] removing SpringBootInitializer to push meta deta, instead moving to heartbeat --- ...pplicationInsightsModuleConfiguration.java | 7 --- .../SpringBootTelemetryInitializer.java | 56 ------------------- 2 files changed, 63 deletions(-) delete mode 100644 azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/SpringBootTelemetryInitializer.java diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java index e49c93c9781..f6f4c31f8aa 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java @@ -25,12 +25,10 @@ import com.microsoft.applicationinsights.boot.HeartBeatProvider.SpringBootHeartBeatProvider; import com.microsoft.applicationinsights.boot.conditional.ConditionalOnOperatingSystem; import com.microsoft.applicationinsights.boot.conditional.OperatingSystem; -import com.microsoft.applicationinsights.boot.initializer.SpringBootTelemetryInitializer; import com.microsoft.applicationinsights.extensibility.initializer.DeviceInfoContextInitializer; import com.microsoft.applicationinsights.extensibility.initializer.SdkVersionContextInitializer; import com.microsoft.applicationinsights.internal.heartbeat.HeartBeatModule; import com.microsoft.applicationinsights.internal.heartbeat.HeartbeatDefaultPayload; -import com.microsoft.applicationinsights.internal.logger.InternalLogger; import com.microsoft.applicationinsights.internal.perfcounter.JvmPerformanceCountersModule; import com.microsoft.applicationinsights.internal.perfcounter.ProcessPerformanceCountersModule; import org.springframework.beans.factory.annotation.Autowired; @@ -54,11 +52,6 @@ public class ApplicationInsightsModuleConfiguration { @Autowired ApplicationInsightsProperties applicationInsightsProperties; -// @Bean -// public SpringBootTelemetryInitializer springBootTelemetryInitializer(Environment environment) { -// return new SpringBootTelemetryInitializer(environment); -// } - @Bean public SdkVersionContextInitializer sdkVersionContextInitializer() { return new SdkVersionContextInitializer(); diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/SpringBootTelemetryInitializer.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/SpringBootTelemetryInitializer.java deleted file mode 100644 index 570de4b4bd8..00000000000 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/SpringBootTelemetryInitializer.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * ApplicationInsights-Java - * Copyright (c) Microsoft Corporation - * All rights reserved. - * - * MIT License - * Permission is hereby granted, free of charge, to any person obtaining a copy of this - * software and associated documentation files (the ""Software""), to deal in the Software - * without restriction, including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, and to permit - * persons to whom the Software is furnished to do so, subject to the following conditions: - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE - * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package com.microsoft.applicationinsights.boot.initializer; - -import com.microsoft.applicationinsights.extensibility.TelemetryInitializer; -import com.microsoft.applicationinsights.extensibility.context.ContextTagKeys; -import com.microsoft.applicationinsights.telemetry.Telemetry; -import org.springframework.boot.SpringBootVersion; -import org.springframework.boot.bind.RelaxedPropertyResolver; -import org.springframework.core.SpringVersion; -import org.springframework.core.env.Environment; - -/** - * Telemetry initializer that adds information regarding spring and spring boot version. - * - * @author Dhaval Doshi - */ -public class SpringBootTelemetryInitializer implements TelemetryInitializer { - private final Environment environment; - - public SpringBootTelemetryInitializer(Environment environment) { - this.environment = environment; - } - - @Override - public void initialize(Telemetry telemetry) { - RelaxedPropertyResolver relaxedPropertyResolver = new RelaxedPropertyResolver(environment); - telemetry.getProperties().put("ai.spring-boot.version", SpringBootVersion.getVersion()); - telemetry.getProperties().put("ai.spring.version", SpringVersion.getVersion()); - String ipAddress = relaxedPropertyResolver.getProperty("spring.cloud.client.ipAddress"); - if (ipAddress != null) { - // if spring-cloud is available we can set ip address - telemetry.getProperties().put(ContextTagKeys.getKeys().getLocationIP(), ipAddress); - } - - } -} From aad2b50ac598cddfef7a7454c6d29a43044fc0f3 Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Thu, 12 Apr 2018 11:39:18 -0700 Subject: [PATCH 28/43] autoconfigure cloud_RoleName, removed field injection to constructor and setter injection, added java docs, added tests and improved README --- .../README.md | 18 + ...pplicationInsightsModuleConfiguration.java | 15 +- .../boot/ApplicationInsightsProperties.java | 694 +++++++++--------- ...ionInsightsTelemetryAutoConfiguration.java | 81 +- ...cationInsightsWebMvcAutoConfiguration.java | 4 + .../SpringBootTelemetryInitializer.java | 25 + ...sightsTelemetryAutoConfigurationTests.java | 14 +- .../SdkVersionContextInitializer.java | 4 +- 8 files changed, 463 insertions(+), 392 deletions(-) create mode 100644 azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/SpringBootTelemetryInitializer.java diff --git a/azure-application-insights-spring-boot-starter/README.md b/azure-application-insights-spring-boot-starter/README.md index 86d01831bc8..38268f18506 100644 --- a/azure-application-insights-spring-boot-starter/README.md +++ b/azure-application-insights-spring-boot-starter/README.md @@ -152,6 +152,7 @@ azure.application-insights.telemetry-processor.sampling.exclude= # Enable/Disable default telemetry modules. Default value: true. azure.application-insights.default-modules.ProcessPerformanceCountersModule.enabled=true +azure.application-insights.default-modules.JvmPerformanceCountersModule.enabled=true azure.application-insights.default-modules.WebRequestTrackingTelemetryModule.enabled=true azure.application-insights.default-modules.WebSessionTrackingTelemetryModule.enabled=true azure.application-insights.default-modules.WebUserTrackingTelemetryModule.enabled=true @@ -161,4 +162,21 @@ azure.application-insights.default-modules.WebOperationNameTelemetryInitializer. azure.application-insights.default-modules.WebSessionTelemetryInitializer.enabled=true azure.application-insights.default-modules.WebUserTelemetryInitializer.enabled=true azure.application-insights.default-modules.WebUserAgentTelemetryInitializer.enabled=true + +#Enable/Disable heartbeat module. Default value : true +azure.application-insights.heart-beat.enabled=true +#Default heartbeat interval is 15 minutes. Minimum heartbeat interval can be 30 seconds. +azure.application-insights.heart-beat.heart-beat-interval=900 +#If set of properties are specified they would be excluded from Heartbeat payload +azure.application-insights.heart-beat.excluded-heart-beat-properties-list= +#If set of HeartBeat providers are specified they would be excluded +azure.application-insights.heart-beat.excluded-heart-beat-provider-list +``` + +###Completely disable Application Insights using `application.properties` +```properties +azure.application-insights.enabled=false +azure.application-insights.web.enabled=false ``` +Note: Do not configure `azure.application-insights.instrumentation-key` property for optimal performance +and avoiding any Application Insights beans creation by Spring. diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java index f6f4c31f8aa..8c8c496d70b 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java @@ -25,6 +25,7 @@ import com.microsoft.applicationinsights.boot.HeartBeatProvider.SpringBootHeartBeatProvider; import com.microsoft.applicationinsights.boot.conditional.ConditionalOnOperatingSystem; import com.microsoft.applicationinsights.boot.conditional.OperatingSystem; +import com.microsoft.applicationinsights.boot.initializer.SpringBootTelemetryInitializer; import com.microsoft.applicationinsights.extensibility.initializer.DeviceInfoContextInitializer; import com.microsoft.applicationinsights.extensibility.initializer.SdkVersionContextInitializer; import com.microsoft.applicationinsights.internal.heartbeat.HeartBeatModule; @@ -49,8 +50,12 @@ @ConditionalOnProperty(value = "azure.application-insights.enabled", havingValue = "true", matchIfMissing = true) public class ApplicationInsightsModuleConfiguration { + private ApplicationInsightsProperties applicationInsightsProperties; + @Autowired - ApplicationInsightsProperties applicationInsightsProperties; + public ApplicationInsightsModuleConfiguration(ApplicationInsightsProperties properties) { + this.applicationInsightsProperties = properties; + } @Bean public SdkVersionContextInitializer sdkVersionContextInitializer() { @@ -62,9 +67,15 @@ public DeviceInfoContextInitializer deviceInfoContextInitializer() { return new DeviceInfoContextInitializer(); } + @Bean + public SpringBootTelemetryInitializer springBootTelemetryInitializer() { + return new SpringBootTelemetryInitializer(); + } + + //FIXME: This should be conditional on operating System. However, current architecture of ProcessBuiltInPerformanceCountersFactory + //FIXME: does not separate this concerns therefore cannot condition as of now. @Bean @DependsOn("performanceCounterContainer") - @ConditionalOnOperatingSystem(OperatingSystem.WINDOWS) @ConditionalOnProperty(value = "azure.application-insights.default-modules.ProcessPerformanceCountersModule.enabled", havingValue = "true", matchIfMissing = true) public ProcessPerformanceCountersModule processPerformanceCountersModule() { try { diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java index ec92b902ded..4abf4a8fc77 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java @@ -51,436 +51,402 @@ @ConfigurationProperties("azure.application-insights") public class ApplicationInsightsProperties { - /** - * Enables application insights auto-configuration. - */ - private boolean enabled = true; - /** - * Instrumentation key from Azure Portal. - */ - private String instrumentationKey; - /** - * Telemetry transmission channel configuration. - */ - private Channel channel = new Channel(); - /** - * Built in telemetry processors configuration. - */ - private TelemetryProcessor telemetryProcessor = new TelemetryProcessor(); - /** - * Web plugins settings. - */ - private Web web = new Web(); - /** - * Quick Pulse settings. - */ - private QuickPulse quickPulse = new QuickPulse(); - /** - * Logger properties. - */ - private Logger logger = new Logger(); + /** Enables application insights auto-configuration. */ + private boolean enabled = true; + /** Instrumentation key from Azure Portal. */ + private String instrumentationKey; + /** Telemetry transmission channel configuration. */ + private Channel channel = new Channel(); + /** Built in telemetry processors configuration. */ + private TelemetryProcessor telemetryProcessor = new TelemetryProcessor(); + /** Web plugins settings. */ + private Web web = new Web(); + /** Quick Pulse settings. */ + private QuickPulse quickPulse = new QuickPulse(); + /** Logger properties. */ + private Logger logger = new Logger(); + + /** Performance Counter Container Properties */ + private PerformanceCounter performanceCounter = new PerformanceCounter(); + + /** Jmx Counter container */ + private Jmx jmx = new Jmx(); + + /** Heartbeat Properties container */ + private HeartBeat heartBeat = new HeartBeat(); + + public boolean isEnabled() { + return enabled; + } - /** - * Performance Counter Container Properties - */ + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } - private PerformanceCounter performanceCounter = new PerformanceCounter(); + public String getInstrumentationKey() { + return instrumentationKey; + } - /** - * Jmx Counter container - */ - private Jmx jmx = new Jmx(); + public void setInstrumentationKey(String instrumentationKey) { + this.instrumentationKey = instrumentationKey; + } - private HeartBeat heartBeat = new HeartBeat(); + public Channel getChannel() { + return channel; + } - public boolean isEnabled() { - return enabled; - } + public void setChannel(Channel channel) { + this.channel = channel; + } - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } + public TelemetryProcessor getTelemetryProcessor() { + return telemetryProcessor; + } - public String getInstrumentationKey() { - return instrumentationKey; - } + public void setTelemetryProcessor(TelemetryProcessor telemetryProcessor) { + this.telemetryProcessor = telemetryProcessor; + } - public void setInstrumentationKey(String instrumentationKey) { - this.instrumentationKey = instrumentationKey; - } + public Web getWeb() { + return web; + } - public Channel getChannel() { - return channel; - } + public void setWeb(Web web) { + this.web = web; + } - public void setChannel(Channel channel) { - this.channel = channel; - } + public QuickPulse getQuickPulse() { + return quickPulse; + } - public TelemetryProcessor getTelemetryProcessor() { - return telemetryProcessor; - } + public void setQuickPulse(QuickPulse quickPulse) { + this.quickPulse = quickPulse; + } - public void setTelemetryProcessor(TelemetryProcessor telemetryProcessor) { - this.telemetryProcessor = telemetryProcessor; - } + public Logger getLogger() { + return logger; + } - public Web getWeb() { - return web; - } + public void setLogger(Logger logger) { + this.logger = logger; + } - public void setWeb(Web web) { - this.web = web; - } + public PerformanceCounter getPerformanceCounter() { + return performanceCounter; + } - public QuickPulse getQuickPulse() { - return quickPulse; - } + public void setPerformanceCounter(PerformanceCounter performanceCounter) { + this.performanceCounter = performanceCounter; + } + + public Jmx getJmx() { + return jmx; + } + + public void setJmx(Jmx jmx) { + this.jmx = jmx; + } + + public HeartBeat getHeartBeat() { + return heartBeat; + } + + public void setHeartBeat(HeartBeat heartBeat) { + this.heartBeat = heartBeat; + } - public void setQuickPulse(QuickPulse quickPulse) { - this.quickPulse = quickPulse; + static class Channel { + /** Configuration of {@link InProcessTelemetryChannel}. */ + private InProcess inProcess = new InProcess(); + + public InProcess getInProcess() { + return inProcess; } - public Logger getLogger() { - return logger; + public void setInProcess(InProcess inProcess) { + this.inProcess = inProcess; } - public void setLogger(Logger logger) { - this.logger = logger; + static class InProcess { + /** + * Enables developer mode, all telemetry will be sent immediately without batching. + * Significantly affects performance and should be used only in developer environment. + */ + private boolean developerMode = false; + /** Endpoint address. */ + private String endpointAddress = TransmissionNetworkOutput.DEFAULT_SERVER_URI; + /** + * Maximum count of telemetries that will be batched before sending. Must be between 1 and + * 1000. + */ + private int maxTelemetryBufferCapacity = + InProcessTelemetryChannel.DEFAULT_MAX_TELEMETRY_BUFFER_CAPACITY; + /** Interval to send telemetry. Must be between 1 and 300. */ + private int flushIntervalInSeconds = + InProcessTelemetryChannel.DEFAULT_FLUSH_BUFFER_TIMEOUT_IN_SECONDS; + /** + * Size of disk space that Application Insights can use to store telemetry in case of network + * outage. Must be between 1 and 1000. + */ + private int maxTransmissionStorageFilesCapacityInMb = + TransmissionFileSystemOutput.DEFAULT_CAPACITY_MEGABYTES; + /** Enables throttling on sending telemetry data. */ + private boolean throttling = true; + + /** Sets the size of maximum instant retries without delay */ + private int maxInstantRetry = InProcessTelemetryChannel.DEFAULT_MAX_INSTANT_RETRY; + + public boolean isDeveloperMode() { + return developerMode; + } + + public void setDeveloperMode(boolean developerMode) { + this.developerMode = developerMode; + } + + public int getMaxInstantRetry() { + return maxInstantRetry; + } + + public void setMaxInstantRetry(int maxInstantRetry) { + this.maxInstantRetry = maxInstantRetry; + } + + public String getEndpointAddress() { + return endpointAddress; + } + + public void setEndpointAddress(String endpointAddress) { + this.endpointAddress = endpointAddress; + } + + public int getMaxTelemetryBufferCapacity() { + return maxTelemetryBufferCapacity; + } + + public void setMaxTelemetryBufferCapacity(int maxTelemetryBufferCapacity) { + this.maxTelemetryBufferCapacity = maxTelemetryBufferCapacity; + } + + public int getFlushIntervalInSeconds() { + return flushIntervalInSeconds; + } + + public void setFlushIntervalInSeconds(int flushIntervalInSeconds) { + this.flushIntervalInSeconds = flushIntervalInSeconds; + } + + public int getMaxTransmissionStorageFilesCapacityInMb() { + return maxTransmissionStorageFilesCapacityInMb; + } + + public void setMaxTransmissionStorageFilesCapacityInMb( + int maxTransmissionStorageFilesCapacityInMb) { + this.maxTransmissionStorageFilesCapacityInMb = maxTransmissionStorageFilesCapacityInMb; + } + + public boolean isThrottling() { + return throttling; + } + public void setThrottling(boolean throttling) { + this.throttling = throttling; + } } + } + + static class TelemetryProcessor { - public PerformanceCounter getPerformanceCounter() { - return performanceCounter; + /** Configuration of {@link FixedRateSamplingTelemetryProcessor}. */ + private Sampling sampling = new Sampling(); + + public Sampling getSampling() { + return sampling; } - public void setPerformanceCounter( - PerformanceCounter performanceCounter) { - this.performanceCounter = performanceCounter; + public void setSampling(Sampling sampling) { + this.sampling = sampling; } - public Jmx getJmx() { - return jmx; + static class Sampling { + /** + * Percent of telemetry events that will be sent to Application Insights. Percentage must be + * close to 100/N where N is an integer. E.g. 50 (=100/2), 33.33 (=100/3), 25 (=100/4), 20, 1 + * (=100/100), 0.1 (=100/1000). + */ + private double percentage = FixedRateSamplingTelemetryProcessor.DEFAULT_SAMPLING_PERCENTAGE; + /** If set only telemetry of specified types will be included. */ + private List include = new ArrayList<>(); + /** If set telemetry of specified type will be excluded. */ + private List exclude = new ArrayList<>(); + + public double getPercentage() { + return percentage; + } + + public void setPercentage(double percentage) { + this.percentage = percentage; + } + + public List getInclude() { + return include; + } + + public void setInclude(List include) { + this.include = include; + } + + public List getExclude() { + return exclude; + } + + public void setExclude(List exclude) { + this.exclude = exclude; + } } + } - public void setJmx(Jmx jmx) { - this.jmx = jmx; + static class Web { + /** + * Enables Web telemetry modules. + * + *

Implicitly affects modules: - {@link WebRequestTrackingTelemetryModule} - {@link + * WebSessionTrackingTelemetryModule} - {@link WebUserTrackingTelemetryModule} - {@link + * WebPerformanceCounterModule} - {@link WebOperationIdTelemetryInitializer} - {@link + * WebOperationNameTelemetryInitializer} - {@link WebSessionTelemetryInitializer} - {@link + * WebUserTelemetryInitializer} - {@link WebUserAgentTelemetryInitializer} + * + *

False means that all those modules will be disabled regardless of the enabled property of + * concrete module. + */ + private boolean enabled = true; + + public boolean isEnabled() { + return enabled; } - public HeartBeat getHeartBeat() { - return heartBeat; + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } } - public void setHeartBeat( - HeartBeat heartBeat) { - this.heartBeat = heartBeat; - } + public static class QuickPulse { + /** Enables Quick Pulse integration. */ + private boolean enabled = true; - static class Channel { - /** - * Configuration of {@link InProcessTelemetryChannel}. - */ - private InProcess inProcess = new InProcess(); - - public InProcess getInProcess() { - return inProcess; - } - - public void setInProcess(InProcess inProcess) { - this.inProcess = inProcess; - } - - static class InProcess { - /** - * Enables developer mode, all telemetry will be sent immediately without batching. - * Significantly affects performance and should be used only in developer environment. - */ - private boolean developerMode = false; - /** - * Endpoint address. - */ - private String endpointAddress = TransmissionNetworkOutput.DEFAULT_SERVER_URI; - /** - * Maximum count of telemetries that will be batched before sending. Must be between 1 and 1000. - */ - private int maxTelemetryBufferCapacity = InProcessTelemetryChannel.DEFAULT_MAX_TELEMETRY_BUFFER_CAPACITY; - /** - * Interval to send telemetry. Must be between 1 and 300. - */ - private int flushIntervalInSeconds = InProcessTelemetryChannel.DEFAULT_FLUSH_BUFFER_TIMEOUT_IN_SECONDS; - /** - * Size of disk space that Application Insights can use to store telemetry in case of network outage. Must be between 1 and 1000. - */ - private int maxTransmissionStorageFilesCapacityInMb = TransmissionFileSystemOutput.DEFAULT_CAPACITY_MEGABYTES; - /** - * Enables throttling on sending telemetry data. - */ - private boolean throttling = true; - - /** - * Sets the size of maximum instant retries without delay - */ - private int maxInstantRetry = InProcessTelemetryChannel.DEFAULT_MAX_INSTANT_RETRY; - - public boolean isDeveloperMode() { - return developerMode; - } - - public void setDeveloperMode(boolean developerMode) { - this.developerMode = developerMode; - } - - public int getMaxInstantRetry() { - return maxInstantRetry; - } - - public void setMaxInstantRetry(int maxInstantRetry) { - this.maxInstantRetry = maxInstantRetry; - } - - public String getEndpointAddress() { - return endpointAddress; - } - - public void setEndpointAddress(String endpointAddress) { - this.endpointAddress = endpointAddress; - } - - public int getMaxTelemetryBufferCapacity() { - return maxTelemetryBufferCapacity; - } - - public void setMaxTelemetryBufferCapacity(int maxTelemetryBufferCapacity) { - this.maxTelemetryBufferCapacity = maxTelemetryBufferCapacity; - } - - public int getFlushIntervalInSeconds() { - return flushIntervalInSeconds; - } - - public void setFlushIntervalInSeconds(int flushIntervalInSeconds) { - this.flushIntervalInSeconds = flushIntervalInSeconds; - } - - public int getMaxTransmissionStorageFilesCapacityInMb() { - return maxTransmissionStorageFilesCapacityInMb; - } - - public void setMaxTransmissionStorageFilesCapacityInMb(int maxTransmissionStorageFilesCapacityInMb) { - this.maxTransmissionStorageFilesCapacityInMb = maxTransmissionStorageFilesCapacityInMb; - } - - public boolean isThrottling() { - return throttling; - } - - public void setThrottling(boolean throttling) { - this.throttling = throttling; - } - } + public boolean isEnabled() { + return enabled; } - static class TelemetryProcessor { - - /** - * Configuration of {@link FixedRateSamplingTelemetryProcessor}. - */ - private Sampling sampling = new Sampling(); - - public Sampling getSampling() { - return sampling; - } - - public void setSampling(Sampling sampling) { - this.sampling = sampling; - } - - static class Sampling { - /** - * Percent of telemetry events that will be sent to Application Insights. Percentage must be close to 100/N where N is an integer. - * E.g. 50 (=100/2), 33.33 (=100/3), 25 (=100/4), 20, 1 (=100/100), 0.1 (=100/1000). - */ - private double percentage = FixedRateSamplingTelemetryProcessor.DEFAULT_SAMPLING_PERCENTAGE; - /** - * If set only telemetry of specified types will be included. - */ - private List include = new ArrayList<>(); - /** - * If set telemetry of specified type will be excluded. - */ - private List exclude = new ArrayList<>(); - - public double getPercentage() { - return percentage; - } - - public void setPercentage(double percentage) { - this.percentage = percentage; - } - - public List getInclude() { - return include; - } - - public void setInclude(List include) { - this.include = include; - } - - public List getExclude() { - return exclude; - } - - public void setExclude(List exclude) { - this.exclude = exclude; - } - } + public void setEnabled(boolean enabled) { + this.enabled = enabled; } + } - static class Web { - /** - * Enables Web telemetry modules. - * - * Implicitly affects modules: - * - {@link WebRequestTrackingTelemetryModule} - * - {@link WebSessionTrackingTelemetryModule} - * - {@link WebUserTrackingTelemetryModule} - * - {@link WebPerformanceCounterModule} - * - {@link WebOperationIdTelemetryInitializer} - * - {@link WebOperationNameTelemetryInitializer} - * - {@link WebSessionTelemetryInitializer} - * - {@link WebUserTelemetryInitializer} - * - {@link WebUserAgentTelemetryInitializer} - * - * False means that all those modules will be disabled - * regardless of the enabled property of concrete module. - */ - private boolean enabled = true; - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - } + static class Logger { + /** Type of application insights logger. */ + private LoggerOutputType type = LoggerOutputType.CONSOLE; + /** Minimal level of application insights logger. */ + private LoggingLevel level = LoggingLevel.OFF; - public static class QuickPulse { - /** - * Enables Quick Pulse integration. - */ - private boolean enabled = true; + public LoggerOutputType getType() { + return type; + } - public boolean isEnabled() { - return enabled; - } + public void setType(LoggerOutputType type) { + this.type = type; + } - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } + public LoggingLevel getLevel() { + return level; } - static class Logger { - /** - * Type of application insights logger. - */ - private LoggerOutputType type = LoggerOutputType.CONSOLE; - /** - * Minimal level of application insights logger. - */ - private LoggingLevel level = LoggingLevel.OFF; - - public LoggerOutputType getType() { - return type; - } - - public void setType(LoggerOutputType type) { - this.type = type; - } - - public LoggingLevel getLevel() { - return level; - } - - public void setLevel(LoggingLevel level) { - this.level = level; - } + public void setLevel(LoggingLevel level) { + this.level = level; } + } - static class PerformanceCounter { + static class PerformanceCounter { - /** - * Default collection frequency of performance counters - */ - private long collectionFrequencyInSeconds = PerformanceCounterContainer.DEFAULT_COLLECTION_FREQUENCY_IN_SEC; + /** Default collection frequency of performance counters */ + private long collectionFrequencyInSeconds = + PerformanceCounterContainer.DEFAULT_COLLECTION_FREQUENCY_IN_SEC; - public long getCollectionFrequencyInSeconds() { - return collectionFrequencyInSeconds; - } + public long getCollectionFrequencyInSeconds() { + return collectionFrequencyInSeconds; + } - public void setCollectionFrequencyInSeconds(long collectionFrequencyInSeconds) { - this.collectionFrequencyInSeconds = collectionFrequencyInSeconds; - } + public void setCollectionFrequencyInSeconds(long collectionFrequencyInSeconds) { + this.collectionFrequencyInSeconds = collectionFrequencyInSeconds; } + } - static class Jmx { + static class Jmx { - /** - * List of JMX counters - */ - List jmxCounters = new ArrayList<>(); + /** List of JMX counters */ + List jmxCounters = new ArrayList<>(); - public List getJmxCounters() { - return jmxCounters; - } + public List getJmxCounters() { + return jmxCounters; + } - public void setJmxCounters(List jmxCounters) { - this.jmxCounters = jmxCounters; - } + public void setJmxCounters(List jmxCounters) { + this.jmxCounters = jmxCounters; } + } - static class HeartBeat { + static class HeartBeat { - boolean isEnabled = false; + /** + * Switch to enable / disable heartbeat + */ + boolean isEnabled = false; - long heartBeatInterval = HeartBeatProvider.DEFAULT_HEARTBEAT_INTERVAL; + /** + * The heartbeat interval in seconds. + */ + long heartBeatInterval = HeartBeatProvider.DEFAULT_HEARTBEAT_INTERVAL; - List excludedHeartBeatProviderList = new ArrayList<>(); + /** + * List of excluded heartbeat properties + */ + List excludedHeartBeatProviderList = new ArrayList<>(); - List excludedHeartBeatPropertiesList = new ArrayList<>(); + /** + * List of excluded heartbeat providers + */ + List excludedHeartBeatPropertiesList = new ArrayList<>(); - public boolean isEnabled() { - return isEnabled; - } + public boolean isEnabled() { + return isEnabled; + } - public void setEnabled(boolean enabled) { - isEnabled = enabled; - } + public void setEnabled(boolean enabled) { + isEnabled = enabled; + } - public long getHeartBeatInterval() { - return heartBeatInterval; - } + public long getHeartBeatInterval() { + return heartBeatInterval; + } - public void setHeartBeatInterval(long heartBeatInterval) { - this.heartBeatInterval = heartBeatInterval; - } + public void setHeartBeatInterval(long heartBeatInterval) { + this.heartBeatInterval = heartBeatInterval; + } - public List getExcludedHeartBeatProviderList() { - return excludedHeartBeatProviderList; - } + public List getExcludedHeartBeatProviderList() { + return excludedHeartBeatProviderList; + } - public void setExcludedHeartBeatProviderList( - List excludedHeartBeatProviderList) { - this.excludedHeartBeatProviderList = excludedHeartBeatProviderList; - } + public void setExcludedHeartBeatProviderList(List excludedHeartBeatProviderList) { + this.excludedHeartBeatProviderList = excludedHeartBeatProviderList; + } - public List getExcludedHeartBeatPropertiesList() { - return excludedHeartBeatPropertiesList; - } + public List getExcludedHeartBeatPropertiesList() { + return excludedHeartBeatPropertiesList; + } - public void setExcludedHeartBeatPropertiesList( - List excludedHeartBeatPropertiesList) { - this.excludedHeartBeatPropertiesList = excludedHeartBeatPropertiesList; - } + public void setExcludedHeartBeatPropertiesList(List excludedHeartBeatPropertiesList) { + this.excludedHeartBeatPropertiesList = excludedHeartBeatPropertiesList; } + } } diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java index a2335942eaa..7ef522e7c83 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java @@ -21,10 +21,11 @@ package com.microsoft.applicationinsights.boot; +import static org.slf4j.LoggerFactory.getLogger; + import com.microsoft.applicationinsights.TelemetryClient; import com.microsoft.applicationinsights.TelemetryConfiguration; import com.microsoft.applicationinsights.boot.ApplicationInsightsProperties.Channel.InProcess; -import com.microsoft.applicationinsights.boot.ApplicationInsightsProperties.PerformanceCounter; import com.microsoft.applicationinsights.boot.ApplicationInsightsProperties.TelemetryProcessor.Sampling; import com.microsoft.applicationinsights.channel.TelemetryChannel; import com.microsoft.applicationinsights.channel.concrete.inprocess.InProcessTelemetryChannel; @@ -40,6 +41,10 @@ import com.microsoft.applicationinsights.internal.perfcounter.PerformanceCounterContainer; import com.microsoft.applicationinsights.internal.quickpulse.QuickPulse; import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.apache.commons.lang3.exception.ExceptionUtils; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; @@ -52,13 +57,6 @@ import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.Import; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static org.slf4j.LoggerFactory.getLogger; - /** * Auto-configuration for application insights. Configures {@link TelemetryConfiguration} * @@ -76,18 +74,46 @@ public class ApplicationInsightsTelemetryAutoConfiguration { private static final Logger log = getLogger(ApplicationInsightsTelemetryAutoConfiguration.class); - @Autowired private ApplicationInsightsProperties applicationInsightsProperties; - @Autowired(required = false) private Collection contextInitializers; - @Autowired(required = false) + private Collection telemetryInitializers; - @Autowired(required = false) + private Collection telemetryModules; - @Autowired(required = false) + private Collection telemetryProcessors; + @Autowired + public ApplicationInsightsTelemetryAutoConfiguration( + ApplicationInsightsProperties applicationInsightsProperties) { + this.applicationInsightsProperties = applicationInsightsProperties; + } + + @Autowired(required = false) + public void setContextInitializers( + Collection contextInitializers) { + this.contextInitializers = contextInitializers; + } + + @Autowired(required = false) + public void setTelemetryInitializers( + Collection telemetryInitializers) { + this.telemetryInitializers = telemetryInitializers; + } + + @Autowired(required = false) + public void setTelemetryModules( + Collection telemetryModules) { + this.telemetryModules = telemetryModules; + } + + @Autowired(required = false) + public void setTelemetryProcessors( + Collection telemetryProcessors) { + this.telemetryProcessors = telemetryProcessors; + } + @Bean @DependsOn("internalLogger") public TelemetryConfiguration telemetryConfiguration(TelemetryChannel telemetryChannel) { @@ -183,6 +209,10 @@ public PerformanceCounterContainer performanceCounterContainer() { return PerformanceCounterContainer.INSTANCE; } + /** + * This method is used to process and load list of JmxCounters provided in the configuration. + * @param jmxCounterList + */ private void processAndLoadJmxCounters(List jmxCounterList) { try { @@ -228,42 +258,44 @@ private void processAndLoadJmxCounters(List jmxCounterList) { } } - + /** + * This Internal class is used to represent the Jmx Object Structure + */ private class CompositeJmxData { String displayName; String objectName; String attributeName; String type; - public String getDisplayName() { + String getDisplayName() { return displayName; } - public void setDisplayName(String displayName) { + void setDisplayName(String displayName) { this.displayName = displayName; } - public String getObjectName() { + String getObjectName() { return objectName; } - public void setObjectName(String objectName) { + void setObjectName(String objectName) { this.objectName = objectName; } - public String getAttributeName() { + String getAttributeName() { return attributeName; } - public void setAttributeName(String attributeName) { + void setAttributeName(String attributeName) { this.attributeName = attributeName; } - public String getType() { + String getType() { return type; } - public void setType(String type) { + void setType(String type) { this.type = type; if (this.type != null) { this.type = this.type.toUpperCase(); @@ -271,6 +303,11 @@ public void setType(String type) { } } + /** + * This converts jmxCounter String to {@link CompositeJmxData} object + * @param jmxCounter + * @return CompositeJmxData object + */ private CompositeJmxData convertToCompositeJmxData(String jmxCounter) { if (jmxCounter != null && jmxCounter.length() > 0) { String[] attributes = jmxCounter.split("/"); diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java index efb3bb4049b..c581260ccda 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java @@ -37,6 +37,10 @@ import org.springframework.context.annotation.Import; import org.springframework.core.Ordered; +/** + * Configuration for Auto-collection of HTTP requests. + */ + @Configuration @Import(InterceptorRegistry.class) @ConditionalOnBean(TelemetryConfiguration.class) diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/SpringBootTelemetryInitializer.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/SpringBootTelemetryInitializer.java new file mode 100644 index 00000000000..c235ade349a --- /dev/null +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/SpringBootTelemetryInitializer.java @@ -0,0 +1,25 @@ +package com.microsoft.applicationinsights.boot.initializer; + +import com.microsoft.applicationinsights.extensibility.TelemetryInitializer; +import com.microsoft.applicationinsights.extensibility.context.DeviceContext; +import com.microsoft.applicationinsights.telemetry.Telemetry; +import org.springframework.beans.factory.annotation.Value; + +/** + * @author Dhaval Doshi + * This Telemetry Initializer is used to auto-configure cloud_RoleName field + * to get a logical component on AppMap. + */ +public class SpringBootTelemetryInitializer implements TelemetryInitializer { + + @Value("${spring.application.name:application}") + String appName; + + @Override + public void initialize(Telemetry telemetry) { + + DeviceContext device = telemetry.getContext().getDevice(); + device.setRoleName(appName); + } + +} diff --git a/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java b/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java index 9f4dc94f1af..d1b4135d576 100644 --- a/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java +++ b/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java @@ -32,7 +32,7 @@ import com.microsoft.applicationinsights.extensibility.TelemetryModule; import com.microsoft.applicationinsights.extensibility.TelemetryProcessor; import com.microsoft.applicationinsights.internal.channel.samplingV2.FixedRateSamplingTelemetryProcessor; -import com.microsoft.applicationinsights.internal.config.TelemetryConfigurationFactory; +import com.microsoft.applicationinsights.internal.heartbeat.HeartBeatModule; import com.microsoft.applicationinsights.internal.logger.InternalLogger; import com.microsoft.applicationinsights.internal.perfcounter.JvmPerformanceCountersModule; import com.microsoft.applicationinsights.internal.perfcounter.PerformanceCounter; @@ -268,6 +268,18 @@ public void shouldBeAbleToConfigureJvmPerformanceCounters() { assertThat(context.getBeansOfType(JvmPerformanceCountersModule.class)).isNotEmpty(); } + @Test + public void heartBeatModuleShouldBeEnabledByDefault() { + EnvironmentTestUtils.addEnvironment(context, + "azure.application-insights.instrumentation-key: 00000000-0000-0000-0000-000000000000", + "azure.application-insights.heart-beat.enabled=true"); + context.register(PropertyPlaceholderAutoConfiguration.class, + ApplicationInsightsTelemetryAutoConfiguration.class); + context.refresh(); + + assertThat(context.getBeansOfType(HeartBeatModule.class)).isNotEmpty(); + } + private static class CustomModuleConfiguration { @Bean diff --git a/core/src/main/java/com/microsoft/applicationinsights/extensibility/initializer/SdkVersionContextInitializer.java b/core/src/main/java/com/microsoft/applicationinsights/extensibility/initializer/SdkVersionContextInitializer.java index c2cc91cd642..152039997b8 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/extensibility/initializer/SdkVersionContextInitializer.java +++ b/core/src/main/java/com/microsoft/applicationinsights/extensibility/initializer/SdkVersionContextInitializer.java @@ -21,11 +21,9 @@ package com.microsoft.applicationinsights.extensibility.initializer; -import com.microsoft.applicationinsights.internal.logger.InternalLogger; +import com.microsoft.applicationinsights.extensibility.ContextInitializer; import com.microsoft.applicationinsights.internal.util.PropertyHelper; import com.microsoft.applicationinsights.telemetry.TelemetryContext; -import com.microsoft.applicationinsights.extensibility.ContextInitializer; - import java.util.Properties; /** From 99fb891ba9dec5c4e51dd8cfe91f4f522323fc2e Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Thu, 12 Apr 2018 14:20:21 -0700 Subject: [PATCH 29/43] fixing dependency version --- azure-application-insights-spring-boot-starter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-application-insights-spring-boot-starter/build.gradle b/azure-application-insights-spring-boot-starter/build.gradle index 4e6dae53b50..e58bd8d4c2f 100644 --- a/azure-application-insights-spring-boot-starter/build.gradle +++ b/azure-application-insights-spring-boot-starter/build.gradle @@ -37,7 +37,7 @@ dependencies { // testCompile('org.junit.jupiter:junit-jupiter-engine:5.1.1') testCompile('junit:junit:4.12') testCompile('org.springframework.boot:spring-boot-starter-test:1.5.9.RELEASE') - testCompile('org.assertj:assertj-core:3.9.0') + testCompile('org.assertj:assertj-core:2.6.0') } compileJava.dependsOn(processResources) From 2896f6d08585f4841df1fbd3ac8387e911b9ef63 Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Thu, 12 Apr 2018 15:31:27 -0700 Subject: [PATCH 30/43] specifying the version number --- azure-application-insights-spring-boot-starter/build.gradle | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/azure-application-insights-spring-boot-starter/build.gradle b/azure-application-insights-spring-boot-starter/build.gradle index e58bd8d4c2f..b0d8206e70f 100644 --- a/azure-application-insights-spring-boot-starter/build.gradle +++ b/azure-application-insights-spring-boot-starter/build.gradle @@ -23,6 +23,7 @@ apply from: "$buildScriptsDir/common-java.gradle" apply from: "$buildScriptsDir/publishing.gradle" archivesBaseName = 'azure-application-insights-spring-boot-starter' +version = '1.0.0' dependencies { compile (project(':core')) @@ -31,10 +32,6 @@ dependencies { provided('org.springframework.boot:spring-boot-autoconfigure:1.5.9.RELEASE') provided('org.springframework.boot:spring-boot-starter-web:1.5.9.RELEASE') provided('org.springframework.boot:spring-boot-configuration-processor:1.5.9.RELEASE') - -// testCompile('org.junit.jupiter:junit-jupiter-api:5.1.1') -// testCompile('org.junit.jupiter:junit-jupiter-params:5.1.1') -// testCompile('org.junit.jupiter:junit-jupiter-engine:5.1.1') testCompile('junit:junit:4.12') testCompile('org.springframework.boot:spring-boot-starter-test:1.5.9.RELEASE') testCompile('org.assertj:assertj-core:2.6.0') From 85a2072855c6ae200c892b5e49b54026a8abda8e Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Fri, 20 Apr 2018 09:49:29 -0700 Subject: [PATCH 31/43] resolving merge conflict, removed unused Operating system conditional, some refactoring to make the AutoConfiguration class simple --- ...pplicationInsightsModuleConfiguration.java | 4 +- .../boot/ApplicationInsightsProperties.java | 135 +++++++++ ...ionInsightsTelemetryAutoConfiguration.java | 256 +++++++++--------- .../SpringBootHeartBeatProvider.java | 38 +-- .../ConditionalOnOperatingSystem.java | 49 ---- .../OnOperationSystemCondition.java | 55 ---- .../boot/conditional/OperatingSystem.java | 32 --- .../internal/heartbeat/MiscUtils.java | 4 +- 8 files changed, 287 insertions(+), 286 deletions(-) delete mode 100644 azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/ConditionalOnOperatingSystem.java delete mode 100644 azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/OnOperationSystemCondition.java delete mode 100644 azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/OperatingSystem.java diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java index 8c8c496d70b..e3a6a778336 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java @@ -102,7 +102,7 @@ public JvmPerformanceCountersModule jvmPerformanceCountersModule() { } @Bean - @ConditionalOnProperty(value = "azure.application-insights.default.modules.HearBeat.enabled", havingValue = "true", matchIfMissing = true) + @ConditionalOnProperty(value = "azure.application-insights.default.modules.HeartBeat.enabled", havingValue = "true", matchIfMissing = true) public HeartBeatModule heartBeatModule(Environment environment) { try { HeartBeatModule heartBeatModule = new HeartBeatModule(null); @@ -118,7 +118,7 @@ public HeartBeatModule heartBeatModule(Environment environment) { return heartBeatModule; } catch (Exception e) { - throw new IllegalStateException("could not configure Heartbeat, please disable 'azure.application-insights.default.modules.HearBeat.enabled'" + throw new IllegalStateException("could not configure Heartbeat, please set 'azure.application-insights.default.modules.HearBeat.enabled'" + " to false ", e); } } diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java index 4abf4a8fc77..3bffcd60fdc 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java @@ -27,8 +27,11 @@ import com.microsoft.applicationinsights.internal.channel.samplingV2.FixedRateSamplingTelemetryProcessor; import com.microsoft.applicationinsights.internal.channel.samplingV2.TelemetryType; import com.microsoft.applicationinsights.internal.heartbeat.HeartBeatProvider; +import com.microsoft.applicationinsights.internal.jmx.JmxAttributeData; +import com.microsoft.applicationinsights.internal.logger.InternalLogger; import com.microsoft.applicationinsights.internal.logger.InternalLogger.LoggerOutputType; import com.microsoft.applicationinsights.internal.logger.InternalLogger.LoggingLevel; +import com.microsoft.applicationinsights.internal.perfcounter.JmxMetricPerformanceCounter; import com.microsoft.applicationinsights.internal.perfcounter.PerformanceCounterContainer; import com.microsoft.applicationinsights.web.extensibility.initializers.WebOperationIdTelemetryInitializer; import com.microsoft.applicationinsights.web.extensibility.initializers.WebOperationNameTelemetryInitializer; @@ -40,7 +43,11 @@ import com.microsoft.applicationinsights.web.extensibility.modules.WebUserTrackingTelemetryModule; import com.microsoft.applicationinsights.web.internal.perfcounter.WebPerformanceCounterModule; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.exception.ExceptionUtils; import org.springframework.boot.context.properties.ConfigurationProperties; /** @@ -449,4 +456,132 @@ public void setExcludedHeartBeatPropertiesList(List excludedHeartBeatPro this.excludedHeartBeatPropertiesList = excludedHeartBeatPropertiesList; } } + + /** + * This method is used to process and load list of JmxCounters provided in the configuration. + * @param jmxCounterList + */ + void processAndLoadJmxCounters(List jmxCounterList) { + + try { + Map> data = new HashMap<>(); + for (String jmxCounter : jmxCounterList) { + CompositeJmxData compositeJmxData = convertToCompositeJmxData(jmxCounter); + if (compositeJmxData == null) { + InternalLogger.INSTANCE.warn("unable to add Jmx counter %s", jmxCounter); + } else { + List collection = data.get(compositeJmxData.getObjectName()); + if (collection == null) { + collection = new ArrayList<>(); + data.put(compositeJmxData.getObjectName(), collection); + } + collection.add(new JmxAttributeData(compositeJmxData.getDisplayName(), + compositeJmxData.getAttributeName(), compositeJmxData.getType())); + } + } + + //Register each entry in performance counter container + for (Map.Entry> entry : data.entrySet()) { + try { + if (PerformanceCounterContainer.INSTANCE.register(new JmxMetricPerformanceCounter( + entry.getKey(), entry.getKey(), entry.getValue() + ))) { + InternalLogger.INSTANCE.trace("Registered Jmx performance counter %s", + entry.getKey()); + } + else { + InternalLogger.INSTANCE.trace("Failed to register Jmx performance" + + " counter %s", entry.getKey()); + } + } + catch (Exception e) { + InternalLogger.INSTANCE.warn("Failed to register Jmx performance counter," + + " of object name %s Stack trace is %s", entry.getKey(), ExceptionUtils.getStackTrace(e)); + } + } + } + catch (Exception e) { + InternalLogger.INSTANCE.warn("Unable to add Jmx performance counter. Exception is" + + " %s", ExceptionUtils.getStackTrace(e)); + } + } + + /** + * This Internal class is used to represent the Jmx Object Structure + */ + private class CompositeJmxData { + String displayName; + String objectName; + String attributeName; + String type; + + String getDisplayName() { + return displayName; + } + + void setDisplayName(String displayName) { + this.displayName = displayName; + } + + String getObjectName() { + return objectName; + } + + void setObjectName(String objectName) { + this.objectName = objectName; + } + + String getAttributeName() { + return attributeName; + } + + void setAttributeName(String attributeName) { + this.attributeName = attributeName; + } + + String getType() { + return type; + } + + void setType(String type) { + this.type = type; + if (this.type != null) { + this.type = this.type.toUpperCase(); + } + } + } + + /** + * This converts jmxCounter String to {@link CompositeJmxData} object + * @param jmxCounter + * @return CompositeJmxData object + */ + private CompositeJmxData convertToCompositeJmxData(String jmxCounter) { + if (jmxCounter != null && jmxCounter.length() > 0) { + String[] attributes = jmxCounter.split("/"); + if (attributes.length < 3) { + InternalLogger.INSTANCE.warn("Missing either objectName or attributeName or" + + " display name. Jmx counter %s will not be added" , jmxCounter); + return null; + } + CompositeJmxData data = new CompositeJmxData(); + for (int i = 0; i < attributes.length; ++i) { + if (i > 3) break; + if (i == 0) { + data.setObjectName(attributes[0]); + } + else if (i == 1) { + data.setAttributeName(attributes[1]); + } + else if (i == 2) { + data.setDisplayName(attributes[2]); + } + else { + data.setType(attributes[3]); + } + } + return data; + } + return null; + } } diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java index 7ef522e7c83..05420e5a264 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java @@ -204,136 +204,136 @@ public PerformanceCounterContainer performanceCounterContainer() { ApplicationInsightsProperties.Jmx jmx = applicationInsightsProperties.getJmx(); if (jmx.getJmxCounters() !=null && jmx.getJmxCounters().size() > 0) { - processAndLoadJmxCounters(jmx.getJmxCounters()); + applicationInsightsProperties.processAndLoadJmxCounters(jmx.getJmxCounters()); } return PerformanceCounterContainer.INSTANCE; } - /** - * This method is used to process and load list of JmxCounters provided in the configuration. - * @param jmxCounterList - */ - private void processAndLoadJmxCounters(List jmxCounterList) { - - try { - Map> data = new HashMap<>(); - for (String jmxCounter : jmxCounterList) { - CompositeJmxData compositeJmxData = convertToCompositeJmxData(jmxCounter); - if (compositeJmxData == null) { - InternalLogger.INSTANCE.warn("unable to add Jmx counter %s", jmxCounter); - } else { - List collection = data.get(compositeJmxData.getObjectName()); - if (collection == null) { - collection = new ArrayList<>(); - data.put(compositeJmxData.getObjectName(), collection); - } - collection.add(new JmxAttributeData(compositeJmxData.getDisplayName(), - compositeJmxData.getAttributeName(), compositeJmxData.getType())); - } - } - - //Register each entry in performance counter container - for (Map.Entry> entry : data.entrySet()) { - try { - if (PerformanceCounterContainer.INSTANCE.register(new JmxMetricPerformanceCounter( - entry.getKey(), entry.getKey(), entry.getValue() - ))) { - InternalLogger.INSTANCE.trace("Registered Jmx performance counter %s", - entry.getKey()); - } - else { - InternalLogger.INSTANCE.trace("Failed to register Jmx performance" - + " counter %s", entry.getKey()); - } - } - catch (Exception e) { - InternalLogger.INSTANCE.warn("Failed to register Jmx performance counter," - + " of object name %s Stack trace is %s", entry.getKey(), ExceptionUtils.getStackTrace(e)); - } - } - } - catch (Exception e) { - InternalLogger.INSTANCE.warn("Unable to add Jmx performance counter. Exception is" - + " %s", ExceptionUtils.getStackTrace(e)); - } - } - - /** - * This Internal class is used to represent the Jmx Object Structure - */ - private class CompositeJmxData { - String displayName; - String objectName; - String attributeName; - String type; - - String getDisplayName() { - return displayName; - } - - void setDisplayName(String displayName) { - this.displayName = displayName; - } - - String getObjectName() { - return objectName; - } - - void setObjectName(String objectName) { - this.objectName = objectName; - } - - String getAttributeName() { - return attributeName; - } - - void setAttributeName(String attributeName) { - this.attributeName = attributeName; - } - - String getType() { - return type; - } - - void setType(String type) { - this.type = type; - if (this.type != null) { - this.type = this.type.toUpperCase(); - } - } - } - - /** - * This converts jmxCounter String to {@link CompositeJmxData} object - * @param jmxCounter - * @return CompositeJmxData object - */ - private CompositeJmxData convertToCompositeJmxData(String jmxCounter) { - if (jmxCounter != null && jmxCounter.length() > 0) { - String[] attributes = jmxCounter.split("/"); - if (attributes.length < 3) { - InternalLogger.INSTANCE.warn("Missing either objectName or attributeName or" - + " display name. Jmx counter %s will not be added" , jmxCounter); - return null; - } - CompositeJmxData data = new CompositeJmxData(); - for (int i = 0; i < attributes.length; ++i) { - if (i > 3) break; - if (i == 0) { - data.setObjectName(attributes[0]); - } - else if (i == 1) { - data.setAttributeName(attributes[1]); - } - else if (i == 2) { - data.setDisplayName(attributes[2]); - } - else { - data.setType(attributes[3]); - } - } - return data; - } - return null; - } +// /** +// * This method is used to process and load list of JmxCounters provided in the configuration. +// * @param jmxCounterList +// */ +// private void processAndLoadJmxCounters(List jmxCounterList) { +// +// try { +// Map> data = new HashMap<>(); +// for (String jmxCounter : jmxCounterList) { +// CompositeJmxData compositeJmxData = convertToCompositeJmxData(jmxCounter); +// if (compositeJmxData == null) { +// InternalLogger.INSTANCE.warn("unable to add Jmx counter %s", jmxCounter); +// } else { +// List collection = data.get(compositeJmxData.getObjectName()); +// if (collection == null) { +// collection = new ArrayList<>(); +// data.put(compositeJmxData.getObjectName(), collection); +// } +// collection.add(new JmxAttributeData(compositeJmxData.getDisplayName(), +// compositeJmxData.getAttributeName(), compositeJmxData.getType())); +// } +// } +// +// //Register each entry in performance counter container +// for (Map.Entry> entry : data.entrySet()) { +// try { +// if (PerformanceCounterContainer.INSTANCE.register(new JmxMetricPerformanceCounter( +// entry.getKey(), entry.getKey(), entry.getValue() +// ))) { +// InternalLogger.INSTANCE.trace("Registered Jmx performance counter %s", +// entry.getKey()); +// } +// else { +// InternalLogger.INSTANCE.trace("Failed to register Jmx performance" +// + " counter %s", entry.getKey()); +// } +// } +// catch (Exception e) { +// InternalLogger.INSTANCE.warn("Failed to register Jmx performance counter," +// + " of object name %s Stack trace is %s", entry.getKey(), ExceptionUtils.getStackTrace(e)); +// } +// } +// } +// catch (Exception e) { +// InternalLogger.INSTANCE.warn("Unable to add Jmx performance counter. Exception is" +// + " %s", ExceptionUtils.getStackTrace(e)); +// } +// } +// +// /** +// * This Internal class is used to represent the Jmx Object Structure +// */ +// private class CompositeJmxData { +// String displayName; +// String objectName; +// String attributeName; +// String type; +// +// String getDisplayName() { +// return displayName; +// } +// +// void setDisplayName(String displayName) { +// this.displayName = displayName; +// } +// +// String getObjectName() { +// return objectName; +// } +// +// void setObjectName(String objectName) { +// this.objectName = objectName; +// } +// +// String getAttributeName() { +// return attributeName; +// } +// +// void setAttributeName(String attributeName) { +// this.attributeName = attributeName; +// } +// +// String getType() { +// return type; +// } +// +// void setType(String type) { +// this.type = type; +// if (this.type != null) { +// this.type = this.type.toUpperCase(); +// } +// } +// } +// +// /** +// * This converts jmxCounter String to {@link CompositeJmxData} object +// * @param jmxCounter +// * @return CompositeJmxData object +// */ +// private CompositeJmxData convertToCompositeJmxData(String jmxCounter) { +// if (jmxCounter != null && jmxCounter.length() > 0) { +// String[] attributes = jmxCounter.split("/"); +// if (attributes.length < 3) { +// InternalLogger.INSTANCE.warn("Missing either objectName or attributeName or" +// + " display name. Jmx counter %s will not be added" , jmxCounter); +// return null; +// } +// CompositeJmxData data = new CompositeJmxData(); +// for (int i = 0; i < attributes.length; ++i) { +// if (i > 3) break; +// if (i == 0) { +// data.setObjectName(attributes[0]); +// } +// else if (i == 1) { +// data.setAttributeName(attributes[1]); +// } +// else if (i == 2) { +// data.setDisplayName(attributes[2]); +// } +// else { +// data.setType(attributes[3]); +// } +// } +// return data; +// } +// return null; +// } } diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/HeartBeatProvider/SpringBootHeartBeatProvider.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/HeartBeatProvider/SpringBootHeartBeatProvider.java index 02b8765eddb..86149faed66 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/HeartBeatProvider/SpringBootHeartBeatProvider.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/HeartBeatProvider/SpringBootHeartBeatProvider.java @@ -1,19 +1,20 @@ package com.microsoft.applicationinsights.boot.HeartBeatProvider; -import com.microsoft.applicationinsights.internal.heartbeat.HeartBeatDefaultPayloadProviderInterface; +import com.microsoft.applicationinsights.internal.heartbeat.HeartBeatPayloadProviderInterface; import com.microsoft.applicationinsights.internal.heartbeat.HeartBeatProviderInterface; import com.microsoft.applicationinsights.internal.heartbeat.MiscUtils; import com.microsoft.applicationinsights.internal.logger.InternalLogger; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.Callable; import org.apache.commons.lang3.exception.ExceptionUtils; import org.springframework.boot.SpringBootVersion; import org.springframework.core.SpringVersion; import org.springframework.core.env.Environment; -public class SpringBootHeartBeatProvider implements HeartBeatDefaultPayloadProviderInterface { +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.Callable; + +public class SpringBootHeartBeatProvider implements HeartBeatPayloadProviderInterface { /** * Collection holding default properties for this default provider. @@ -27,6 +28,12 @@ public class SpringBootHeartBeatProvider implements HeartBeatDefaultPayloadProvi private final Environment environment; + private final String SPRING_BOOT_VERSION = "ai.spring-boot.version"; + + private final String SPRING_VERSION = "ai.spring.version"; + + + public SpringBootHeartBeatProvider(Environment environment) { defaultFields = new HashSet<>(); this.environment = environment; @@ -40,7 +47,7 @@ public String getName() { } @Override - public boolean isKeyWord(String keyword) { + public boolean isKeyword(String keyword) { return defaultFields.contains(keyword); } @@ -49,19 +56,18 @@ public Callable setDefaultPayload(final List disableFields, final HeartBeatProviderInterface provider) { return new Callable() { - // using volatile here to avoid caching in threads. - volatile boolean hasSetValues = false; - volatile Set enabledProperties = MiscUtils.except(defaultFields, disableFields); + Set enabledProperties = MiscUtils.except(disableFields, defaultFields); @Override public Boolean call() { + boolean hasSetValues = false; for (String fieldName : enabledProperties) { try { switch (fieldName) { - case "ai.spring-boot.version": + case SPRING_BOOT_VERSION: provider.addHeartBeatProperty(fieldName, getSpringBootVersion(), true); hasSetValues = true; break; - case "ai.spring.version": + case SPRING_VERSION: provider.addHeartBeatProperty(fieldName, getSpringVersion(), true); hasSetValues = true; break; @@ -86,12 +92,8 @@ public Boolean call() { * @param defaultFields collection to hold default properties. */ private void initializeDefaultFields(Set defaultFields) { - - if (defaultFields == null) { - defaultFields = new HashSet<>(); - } - defaultFields.add("ai.spring-boot.version"); - defaultFields.add("ai.spring.version"); + defaultFields.add(SPRING_BOOT_VERSION); + defaultFields.add(SPRING_VERSION); } /** diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/ConditionalOnOperatingSystem.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/ConditionalOnOperatingSystem.java deleted file mode 100644 index ad267fe2332..00000000000 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/ConditionalOnOperatingSystem.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * ApplicationInsights-Java - * Copyright (c) Microsoft Corporation - * All rights reserved. - * - * MIT License - * Permission is hereby granted, free of charge, to any person obtaining a copy of this - * software and associated documentation files (the ""Software""), to deal in the Software - * without restriction, including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, and to permit - * persons to whom the Software is furnished to do so, subject to the following conditions: - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE - * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package com.microsoft.applicationinsights.boot.conditional; - -import org.springframework.context.annotation.Conditional; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * {@link Conditional} that checks if the application is running on specific operating system. - * - * @author Arthur Gavlyukovskiy - */ -@Target({ ElementType.TYPE, ElementType.METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@Conditional(OnOperationSystemCondition.class) -public @interface ConditionalOnOperatingSystem { - - /** - * The {@link OperatingSystem operating system} that must be active. - * @return the expected operating system - */ - OperatingSystem value(); - -} diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/OnOperationSystemCondition.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/OnOperationSystemCondition.java deleted file mode 100644 index 87209a2679d..00000000000 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/OnOperationSystemCondition.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * ApplicationInsights-Java - * Copyright (c) Microsoft Corporation - * All rights reserved. - * - * MIT License - * Permission is hereby granted, free of charge, to any person obtaining a copy of this - * software and associated documentation files (the ""Software""), to deal in the Software - * without restriction, including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, and to permit - * persons to whom the Software is furnished to do so, subject to the following conditions: - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE - * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package com.microsoft.applicationinsights.boot.conditional; - -import com.microsoft.applicationinsights.internal.system.SystemInformation; -import org.springframework.boot.autoconfigure.condition.ConditionMessage; -import org.springframework.boot.autoconfigure.condition.ConditionOutcome; -import org.springframework.boot.autoconfigure.condition.SpringBootCondition; -import org.springframework.context.annotation.Condition; -import org.springframework.context.annotation.ConditionContext; -import org.springframework.core.type.AnnotatedTypeMetadata; - -import java.util.Map; - -/** - * {@link Condition} that checks if the application is running on specific operating system. - * - * @author Arthur Gavlyukovskiy - */ -public class OnOperationSystemCondition extends SpringBootCondition { - - @Override - public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { - Map attributes = metadata.getAnnotationAttributes(ConditionalOnOperatingSystem.class.getName()); - OperatingSystem operatingSystem = (OperatingSystem) attributes.get("value"); - ConditionMessage.Builder message = ConditionMessage.forCondition(ConditionalOnOperatingSystem.class); - String name = operatingSystem.name(); - if (operatingSystem == OperatingSystem.WINDOWS && SystemInformation.INSTANCE.isWindows()) { - return ConditionOutcome.match(message.foundExactly(name)); - } - if (operatingSystem == OperatingSystem.UNIX && SystemInformation.INSTANCE.isUnix()) { - return ConditionOutcome.match(message.foundExactly(name)); - } - return ConditionOutcome.noMatch(message.didNotFind(name).atAll()); - } -} diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/OperatingSystem.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/OperatingSystem.java deleted file mode 100644 index dc898443372..00000000000 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/conditional/OperatingSystem.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * ApplicationInsights-Java - * Copyright (c) Microsoft Corporation - * All rights reserved. - * - * MIT License - * Permission is hereby granted, free of charge, to any person obtaining a copy of this - * software and associated documentation files (the ""Software""), to deal in the Software - * without restriction, including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, and to permit - * persons to whom the Software is furnished to do so, subject to the following conditions: - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE - * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package com.microsoft.applicationinsights.boot.conditional; - -/** - * List of available for operating system for condition. - * - * @author Arthur Gavlyukovskiy - */ -public enum OperatingSystem { - WINDOWS, - UNIX -} diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/heartbeat/MiscUtils.java b/core/src/main/java/com/microsoft/applicationinsights/internal/heartbeat/MiscUtils.java index de913e63ca1..e7eaf6e5317 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/heartbeat/MiscUtils.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/heartbeat/MiscUtils.java @@ -9,7 +9,7 @@ * * @author Dhaval Doshi */ -class MiscUtils { +public class MiscUtils { /** * Returns a list which contains result of List - Set @@ -17,7 +17,7 @@ class MiscUtils { * @param set * @return */ - static Set except(List list2, Set set) { + public static Set except(List list2, Set set) { try { if (set == null) { throw new IllegalArgumentException("Input is null"); From 16a5a87f27be8d422d4cfcadc3468ac7e114b568 Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Fri, 20 Apr 2018 10:59:17 -0700 Subject: [PATCH 32/43] remove unused imports --- ...pplicationInsightsModuleConfiguration.java | 2 - .../boot/ApplicationInsightsProperties.java | 6 +- ...ionInsightsTelemetryAutoConfiguration.java | 145 +----------------- 3 files changed, 10 insertions(+), 143 deletions(-) diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java index e3a6a778336..a5be164edcf 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java @@ -23,8 +23,6 @@ import com.microsoft.applicationinsights.boot.ApplicationInsightsProperties.HeartBeat; import com.microsoft.applicationinsights.boot.HeartBeatProvider.SpringBootHeartBeatProvider; -import com.microsoft.applicationinsights.boot.conditional.ConditionalOnOperatingSystem; -import com.microsoft.applicationinsights.boot.conditional.OperatingSystem; import com.microsoft.applicationinsights.boot.initializer.SpringBootTelemetryInitializer; import com.microsoft.applicationinsights.extensibility.initializer.DeviceInfoContextInitializer; import com.microsoft.applicationinsights.extensibility.initializer.SdkVersionContextInitializer; diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java index 3bffcd60fdc..6ffc0d86799 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java @@ -42,14 +42,14 @@ import com.microsoft.applicationinsights.web.extensibility.modules.WebSessionTrackingTelemetryModule; import com.microsoft.applicationinsights.web.extensibility.modules.WebUserTrackingTelemetryModule; import com.microsoft.applicationinsights.web.internal.perfcounter.WebPerformanceCounterModule; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.boot.context.properties.ConfigurationProperties; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.springframework.boot.context.properties.ConfigurationProperties; - /** * {@link ConfigurationProperties} for configuring application insights. * diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java index 05420e5a264..50c315103d1 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java @@ -21,8 +21,6 @@ package com.microsoft.applicationinsights.boot; -import static org.slf4j.LoggerFactory.getLogger; - import com.microsoft.applicationinsights.TelemetryClient; import com.microsoft.applicationinsights.TelemetryConfiguration; import com.microsoft.applicationinsights.boot.ApplicationInsightsProperties.Channel.InProcess; @@ -35,17 +33,9 @@ import com.microsoft.applicationinsights.extensibility.TelemetryProcessor; import com.microsoft.applicationinsights.internal.channel.samplingV2.FixedRateSamplingTelemetryProcessor; import com.microsoft.applicationinsights.internal.channel.samplingV2.TelemetryType; -import com.microsoft.applicationinsights.internal.jmx.JmxAttributeData; import com.microsoft.applicationinsights.internal.logger.InternalLogger; -import com.microsoft.applicationinsights.internal.perfcounter.JmxMetricPerformanceCounter; import com.microsoft.applicationinsights.internal.perfcounter.PerformanceCounterContainer; import com.microsoft.applicationinsights.internal.quickpulse.QuickPulse; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.apache.commons.lang3.exception.ExceptionUtils; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -57,6 +47,13 @@ import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.Import; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.slf4j.LoggerFactory.getLogger; + /** * Auto-configuration for application insights. Configures {@link TelemetryConfiguration} * @@ -208,132 +205,4 @@ public PerformanceCounterContainer performanceCounterContainer() { } return PerformanceCounterContainer.INSTANCE; } - -// /** -// * This method is used to process and load list of JmxCounters provided in the configuration. -// * @param jmxCounterList -// */ -// private void processAndLoadJmxCounters(List jmxCounterList) { -// -// try { -// Map> data = new HashMap<>(); -// for (String jmxCounter : jmxCounterList) { -// CompositeJmxData compositeJmxData = convertToCompositeJmxData(jmxCounter); -// if (compositeJmxData == null) { -// InternalLogger.INSTANCE.warn("unable to add Jmx counter %s", jmxCounter); -// } else { -// List collection = data.get(compositeJmxData.getObjectName()); -// if (collection == null) { -// collection = new ArrayList<>(); -// data.put(compositeJmxData.getObjectName(), collection); -// } -// collection.add(new JmxAttributeData(compositeJmxData.getDisplayName(), -// compositeJmxData.getAttributeName(), compositeJmxData.getType())); -// } -// } -// -// //Register each entry in performance counter container -// for (Map.Entry> entry : data.entrySet()) { -// try { -// if (PerformanceCounterContainer.INSTANCE.register(new JmxMetricPerformanceCounter( -// entry.getKey(), entry.getKey(), entry.getValue() -// ))) { -// InternalLogger.INSTANCE.trace("Registered Jmx performance counter %s", -// entry.getKey()); -// } -// else { -// InternalLogger.INSTANCE.trace("Failed to register Jmx performance" -// + " counter %s", entry.getKey()); -// } -// } -// catch (Exception e) { -// InternalLogger.INSTANCE.warn("Failed to register Jmx performance counter," -// + " of object name %s Stack trace is %s", entry.getKey(), ExceptionUtils.getStackTrace(e)); -// } -// } -// } -// catch (Exception e) { -// InternalLogger.INSTANCE.warn("Unable to add Jmx performance counter. Exception is" -// + " %s", ExceptionUtils.getStackTrace(e)); -// } -// } -// -// /** -// * This Internal class is used to represent the Jmx Object Structure -// */ -// private class CompositeJmxData { -// String displayName; -// String objectName; -// String attributeName; -// String type; -// -// String getDisplayName() { -// return displayName; -// } -// -// void setDisplayName(String displayName) { -// this.displayName = displayName; -// } -// -// String getObjectName() { -// return objectName; -// } -// -// void setObjectName(String objectName) { -// this.objectName = objectName; -// } -// -// String getAttributeName() { -// return attributeName; -// } -// -// void setAttributeName(String attributeName) { -// this.attributeName = attributeName; -// } -// -// String getType() { -// return type; -// } -// -// void setType(String type) { -// this.type = type; -// if (this.type != null) { -// this.type = this.type.toUpperCase(); -// } -// } -// } -// -// /** -// * This converts jmxCounter String to {@link CompositeJmxData} object -// * @param jmxCounter -// * @return CompositeJmxData object -// */ -// private CompositeJmxData convertToCompositeJmxData(String jmxCounter) { -// if (jmxCounter != null && jmxCounter.length() > 0) { -// String[] attributes = jmxCounter.split("/"); -// if (attributes.length < 3) { -// InternalLogger.INSTANCE.warn("Missing either objectName or attributeName or" -// + " display name. Jmx counter %s will not be added" , jmxCounter); -// return null; -// } -// CompositeJmxData data = new CompositeJmxData(); -// for (int i = 0; i < attributes.length; ++i) { -// if (i > 3) break; -// if (i == 0) { -// data.setObjectName(attributes[0]); -// } -// else if (i == 1) { -// data.setAttributeName(attributes[1]); -// } -// else if (i == 2) { -// data.setDisplayName(attributes[2]); -// } -// else { -// data.setType(attributes[3]); -// } -// } -// return data; -// } -// return null; -// } } From 94ca1e1022a3de39a7b7c9983002e9cd1eb75653 Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Mon, 23 Apr 2018 17:04:04 -0700 Subject: [PATCH 33/43] modifying version number --- azure-application-insights-spring-boot-starter/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-application-insights-spring-boot-starter/build.gradle b/azure-application-insights-spring-boot-starter/build.gradle index b0d8206e70f..4f74f4912a6 100644 --- a/azure-application-insights-spring-boot-starter/build.gradle +++ b/azure-application-insights-spring-boot-starter/build.gradle @@ -23,7 +23,7 @@ apply from: "$buildScriptsDir/common-java.gradle" apply from: "$buildScriptsDir/publishing.gradle" archivesBaseName = 'azure-application-insights-spring-boot-starter' -version = '1.0.0' +version = '1.0.0-BETA' dependencies { compile (project(':core')) From 5e56ee336cb4db7028f5f5753fb8ec81ce03eaaf Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Tue, 24 Apr 2018 10:26:57 -0700 Subject: [PATCH 34/43] updating the archive base name for consistency, adding javadocs --- .../build.gradle | 2 +- ...pplicationInsightsModuleConfiguration.java | 36 ++++++++++++- .../boot/ApplicationInsightsProperties.java | 2 + ...ionInsightsTelemetryAutoConfiguration.java | 2 +- ...icationInsightsWebModuleConfiguration.java | 53 ++++++++++++++++--- ...cationInsightsWebMvcAutoConfiguration.java | 9 +++- .../SpringBootHeartBeatProvider.java | 18 +++++-- .../SpringBootTelemetryInitializer.java | 10 +++- 8 files changed, 113 insertions(+), 19 deletions(-) diff --git a/azure-application-insights-spring-boot-starter/build.gradle b/azure-application-insights-spring-boot-starter/build.gradle index 4f74f4912a6..fb334683d66 100644 --- a/azure-application-insights-spring-boot-starter/build.gradle +++ b/azure-application-insights-spring-boot-starter/build.gradle @@ -22,7 +22,7 @@ apply from: "$buildScriptsDir/common-java.gradle" apply from: "$buildScriptsDir/publishing.gradle" -archivesBaseName = 'azure-application-insights-spring-boot-starter' +archivesBaseName = 'applicationinsights-spring-boot-starter' version = '1.0.0-BETA' dependencies { diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java index a5be164edcf..f73d458d2c1 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java @@ -39,7 +39,11 @@ import org.springframework.core.env.Environment; /** - * {@link Configuration} for non-web applications. + *

Core Application Insights Configuration

+ *

+ * This class provides the Core Configuration for ApplicationInsights. This configuration is + * irrespective of WebApplications. {@link Configuration} for non-web applications. + *

* * @author Arthur Gavlyukovskiy, Dhaval Doshi */ @@ -48,6 +52,9 @@ @ConditionalOnProperty(value = "azure.application-insights.enabled", havingValue = "true", matchIfMissing = true) public class ApplicationInsightsModuleConfiguration { + /** + * Instance for the container of ApplicationInsights Properties + */ private ApplicationInsightsProperties applicationInsightsProperties; @Autowired @@ -55,21 +62,37 @@ public ApplicationInsightsModuleConfiguration(ApplicationInsightsProperties prop this.applicationInsightsProperties = properties; } + /** + * Bean for SdkVersionContextInitializer + * @return instance of {@link SdkVersionContextInitializer} + */ @Bean public SdkVersionContextInitializer sdkVersionContextInitializer() { return new SdkVersionContextInitializer(); } + /** + * Bean for DeviceInfoContextInitializer + * @return instance of {@link DeviceInfoContextInitializer} + */ @Bean public DeviceInfoContextInitializer deviceInfoContextInitializer() { return new DeviceInfoContextInitializer(); } + /** + * Bean for SpringBootTelemetryInitializer + * @return instance of {@link SpringBootTelemetryInitializer} + */ @Bean public SpringBootTelemetryInitializer springBootTelemetryInitializer() { return new SpringBootTelemetryInitializer(); } + /** + * Bean for ProcessPerformanceCounterModule + * @return instance of {@link ProcessPerformanceCountersModule} + */ //FIXME: This should be conditional on operating System. However, current architecture of ProcessBuiltInPerformanceCountersFactory //FIXME: does not separate this concerns therefore cannot condition as of now. @Bean @@ -85,6 +108,10 @@ public ProcessPerformanceCountersModule processPerformanceCountersModule() { } } + /** + * Bean for JvmPerformanceCounterModule + * @return instance of {@link JvmPerformanceCountersModule} + */ @Bean @DependsOn("performanceCounterContainer") @ConditionalOnProperty(value = "azure.application-insights.default.modules.JvmPerformanceCountersModule.enabled", havingValue = "true", matchIfMissing = true) @@ -99,11 +126,16 @@ public JvmPerformanceCountersModule jvmPerformanceCountersModule() { } } + /** + * Bean for HeartBeatModule. This also sets the properties for HeartBeatModule + * @param environment + * @return initialized instance with user specified properties of {@link HeartBeatModule} + */ @Bean @ConditionalOnProperty(value = "azure.application-insights.default.modules.HeartBeat.enabled", havingValue = "true", matchIfMissing = true) public HeartBeatModule heartBeatModule(Environment environment) { try { - HeartBeatModule heartBeatModule = new HeartBeatModule(null); + HeartBeatModule heartBeatModule = new HeartBeatModule(); HeartbeatDefaultPayload.addDefaultPayLoadProvider(new SpringBootHeartBeatProvider(environment)); HeartBeat heartBeat = applicationInsightsProperties.getHeartBeat(); heartBeatModule.setHeartBeatInterval(heartBeat.getHeartBeatInterval()); diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java index 6ffc0d86799..354a666c486 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java @@ -51,6 +51,8 @@ import java.util.Map; /** + *

This class is the container for Configuration Properties of Application Insights

+ * * {@link ConfigurationProperties} for configuring application insights. * * @author Arthur Gavlyukovskiy, Dhaval Doshi diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java index 50c315103d1..613bc174cfd 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java @@ -55,7 +55,7 @@ import static org.slf4j.LoggerFactory.getLogger; /** - * Auto-configuration for application insights. Configures {@link TelemetryConfiguration} + *

The central class for configuring and creating initialized {@link TelemetryConfiguration}

* * @author Arthur Gavlyukovskiy, Dhaval Doshi */ diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java index 6740612efd0..42e77421152 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebModuleConfiguration.java @@ -37,6 +37,13 @@ import org.springframework.context.annotation.DependsOn; /** + *

Web Configuration for Application Insights

+ * + *

+ * This class provides the configuration for applications of type web. The modules in this class + * will only be configured if the Spring Framework identifies them as web Application. + *

+ * * {@link Configuration} for web applications. * * @author Arthur Gavlyukovskiy @@ -46,32 +53,52 @@ @ConditionalOnWebApplication public class ApplicationInsightsWebModuleConfiguration { + /** + * Bean for WebRequestTrackingTelemetryModule + * @return instance of {@link WebRequestTrackingTelemetryModule} + */ @Bean @ConditionalOnProperty(value = "azure.application-insights.default-modules.WebRequestTrackingTelemetryModule.enabled", havingValue = "true", matchIfMissing = true) public WebRequestTrackingTelemetryModule webRequestTrackingTelemetryModule() { return new WebRequestTrackingTelemetryModule(); } - @Bean + /** + * Bean for WebSessionTrackingTelemetryModule + * @return instance of {@link WebSessionTrackingTelemetryModule} + */ + @Bean @ConditionalOnProperty(value = "azure.application-insights.default-modules.WebSessionTrackingTelemetryModule.enabled", havingValue = "true", matchIfMissing = true) public WebSessionTrackingTelemetryModule webSessionTrackingTelemetryModule() { return new WebSessionTrackingTelemetryModule(); } - @Bean + /** + * Bean for WebUserTrackingTelemetryModule + * @return instance of {@link WebUserTrackingTelemetryModule} + */ + @Bean @ConditionalOnProperty(value = "azure.application-insights.default-modules.WebUserTrackingTelemetryModule.enabled", havingValue = "true", matchIfMissing = true) public WebUserTrackingTelemetryModule webUserTrackingTelemetryModule() { return new WebUserTrackingTelemetryModule(); } - @Bean + /** + * Bean for WebPerformanceCounterModule + * @return instance of {@link WebPerformanceCounterModule} + */ + @Bean @DependsOn("performanceCounterContainer") @ConditionalOnProperty(value = "azure.application-insights.default-modules.WebPerformanceCounterModule.enabled", havingValue = "true", matchIfMissing = true) public WebPerformanceCounterModule webPerformanceCounterModule() { return new WebPerformanceCounterModule(); } - @Bean + /** + * Bean for WebOperationIdTelemetryInitializer + * @return instance of {@link WebOperationIdTelemetryInitializer} + */ + @Bean @ConditionalOnProperty(value = "azure.application-insights.default-modules.WebOperationIdTelemetryInitializer.enabled", havingValue = "true", matchIfMissing = true) public WebOperationIdTelemetryInitializer webOperationIdTelemetryInitializer() { return new WebOperationIdTelemetryInitializer(); @@ -83,19 +110,31 @@ public WebOperationNameTelemetryInitializer webOperationNameTelemetryInitializer return new WebOperationNameTelemetryInitializer(); } - @Bean + /** + * Bean for WebSessionTelemetryInitializer + * @return instance of {@link WebSessionTelemetryInitializer} + */ + @Bean @ConditionalOnProperty(value = "azure.application-insights.default-modules.WebSessionTelemetryInitializer.enabled", havingValue = "true", matchIfMissing = true) public WebSessionTelemetryInitializer webSessionTelemetryInitializer() { return new WebSessionTelemetryInitializer(); } - @Bean + /** + * Bean for WebUserTelemetryInitializer + * @return instance of {@link WebUserTelemetryInitializer} + */ + @Bean @ConditionalOnProperty(value = "azure.application-insights.default-modules.WebUserTelemetryInitializer.enabled", havingValue = "true", matchIfMissing = true) public WebUserTelemetryInitializer webUserTelemetryInitializer() { return new WebUserTelemetryInitializer(); } - @Bean + /** + * Bean for WebUserAgentTelemetryInitializer + * @return instance of {@link WebUserAgentTelemetryInitializer} + */ + @Bean @ConditionalOnProperty(value = "azure.application-insights.default-modules.WebUserAgentTelemetryInitializer.enabled", havingValue = "true", matchIfMissing = true) public WebUserAgentTelemetryInitializer webUserAgentTelemetryInitializer() { return new WebUserAgentTelemetryInitializer(); diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java index c581260ccda..a618f0b0ee6 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java @@ -38,7 +38,14 @@ import org.springframework.core.Ordered; /** - * Configuration for Auto-collection of HTTP requests. + *

Configuration for Auto-collection of HTTP requests.

+ * + *

+ * This class is responsible for configuring {@link WebRequestTrackingFilter} for auto collection + * of incoming HTTP requests + *

+ * + * @author Arthur Gavlyukovskiy */ @Configuration diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/HeartBeatProvider/SpringBootHeartBeatProvider.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/HeartBeatProvider/SpringBootHeartBeatProvider.java index 86149faed66..510e297f46a 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/HeartBeatProvider/SpringBootHeartBeatProvider.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/HeartBeatProvider/SpringBootHeartBeatProvider.java @@ -4,16 +4,24 @@ import com.microsoft.applicationinsights.internal.heartbeat.HeartBeatProviderInterface; import com.microsoft.applicationinsights.internal.heartbeat.MiscUtils; import com.microsoft.applicationinsights.internal.logger.InternalLogger; -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.springframework.boot.SpringBootVersion; -import org.springframework.core.SpringVersion; -import org.springframework.core.env.Environment; - import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.Callable; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.boot.SpringBootVersion; +import org.springframework.core.SpringVersion; +import org.springframework.core.env.Environment; +/** + *

SpringBoot Heartbeat Property Provider

+ *

+ * This class is a concrete implementation of {@link HeartBeatPayloadProviderInterface} + * It enables setting SpringBoot Metadata to heartbeat payload. + *

+ * + * @author Dhaval Doshi + */ public class SpringBootHeartBeatProvider implements HeartBeatPayloadProviderInterface { /** diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/SpringBootTelemetryInitializer.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/SpringBootTelemetryInitializer.java index c235ade349a..930d91b27e2 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/SpringBootTelemetryInitializer.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/initializer/SpringBootTelemetryInitializer.java @@ -6,12 +6,18 @@ import org.springframework.beans.factory.annotation.Value; /** + *

TelemetryInitializer to set the CloudRoleName Instance

+ * + *

+ * This Telemetry Initializer is used to auto-configure cloud_RoleName field + * to get a logical component on AppMap. + *

+ * * @author Dhaval Doshi - * This Telemetry Initializer is used to auto-configure cloud_RoleName field - * to get a logical component on AppMap. */ public class SpringBootTelemetryInitializer implements TelemetryInitializer { + /** The Logical Name of SpringBoot Application*/ @Value("${spring.application.name:application}") String appName; From 642cbe7ea3f7646d2c0dde063074ab96d7fa4541 Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Wed, 25 Apr 2018 18:11:30 -0700 Subject: [PATCH 35/43] adding null check, some fixes and reducing styling --- ...cationInsightsWebMvcAutoConfiguration.java | 1 - .../TelemetryConfiguration.java | 8 +- .../inprocess/InProcessTelemetryChannel.java | 500 +++++++++--------- .../FixedRateSamplingTelemetryProcessor.java | 9 +- 4 files changed, 249 insertions(+), 269 deletions(-) diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java index a618f0b0ee6..81ecb292fca 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsWebMvcAutoConfiguration.java @@ -61,7 +61,6 @@ public FilterRegistrationBean webRequestTrackingFilterRegistrationBean(WebReques FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(webRequestTrackingFilter); registration.addUrlPatterns("/*"); - registration.setName("webRequestTrackingFilter"); registration.setOrder(Ordered.HIGHEST_PRECEDENCE + 10); return registration; } diff --git a/core/src/main/java/com/microsoft/applicationinsights/TelemetryConfiguration.java b/core/src/main/java/com/microsoft/applicationinsights/TelemetryConfiguration.java index 9c91d9b89eb..3625e9bb023 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/TelemetryConfiguration.java +++ b/core/src/main/java/com/microsoft/applicationinsights/TelemetryConfiguration.java @@ -82,8 +82,12 @@ public static TelemetryConfiguration getActive() { * @return {@link com.microsoft.applicationinsights.TelemetryConfiguration} */ public static TelemetryConfiguration getActiveWithoutInitializingConfig() { - synchronized (s_lock) { - active = new TelemetryConfiguration(); + if (active == null) { + synchronized (s_lock) { + if (active == null) { + active = new TelemetryConfiguration(); + } + } } return active; } diff --git a/core/src/main/java/com/microsoft/applicationinsights/channel/concrete/inprocess/InProcessTelemetryChannel.java b/core/src/main/java/com/microsoft/applicationinsights/channel/concrete/inprocess/InProcessTelemetryChannel.java index 029f6849ba6..aa375c3ea02 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/channel/concrete/inprocess/InProcessTelemetryChannel.java +++ b/core/src/main/java/com/microsoft/applicationinsights/channel/concrete/inprocess/InProcessTelemetryChannel.java @@ -76,47 +76,38 @@ public final class InProcessTelemetryChannel implements TelemetryChannel { private static final int MAX_FLUSH_BUFFER_TIMEOUT_IN_SECONDS = 300; private static final String FLUSH_BUFFER_TIMEOUT_IN_SECONDS_NAME = "FlushIntervalInSeconds"; - private static final String DEVELOPER_MODE_SYSTEM_PROPRETY_NAME = - "APPLICATION_INSIGHTS_DEVELOPER_MODE"; + private final static String DEVELOPER_MODE_SYSTEM_PROPRETY_NAME = "APPLICATION_INSIGHTS_DEVELOPER_MODE"; - private static final String DEVELOPER_MODE_NAME = "DeveloperMode"; - private static final String ENDPOINT_ADDRESS_NAME = "EndpointAddress"; - private static final String MAX_TRANSMISSION_STORAGE_CAPACITY_NAME = - "MaxTransmissionStorageFilesCapacityInMB"; + private final static String DEVELOPER_MODE_NAME = "DeveloperMode"; + private final static String ENDPOINT_ADDRESS_NAME = "EndpointAddress"; + private final static String MAX_TRANSMISSION_STORAGE_CAPACITY_NAME = "MaxTransmissionStorageFilesCapacityInMB"; - private boolean developerMode = false; - private static TransmitterFactory s_transmitterFactory; + private boolean developerMode = false; + private static TransmitterFactory s_transmitterFactory; - private boolean stopped = false; + private boolean stopped = false; - private TelemetriesTransmitter telemetriesTransmitter; + private TelemetriesTransmitter telemetriesTransmitter; - private TelemetryBuffer telemetryBuffer; - private TelemetrySampler telemetrySampler; + private TelemetryBuffer telemetryBuffer; + private TelemetrySampler telemetrySampler; - private static AtomicLong itemsSent = new AtomicLong(0); + private static AtomicLong itemsSent = new AtomicLong(0); - public InProcessTelemetryChannel() { - boolean developerMode = false; - try { - String developerModeAsString = System.getProperty(DEVELOPER_MODE_SYSTEM_PROPRETY_NAME); - if (!LocalStringsUtils.isNullOrEmpty(developerModeAsString)) { - developerMode = Boolean.valueOf(developerModeAsString); - } - } catch (Exception e) { - developerMode = false; - InternalLogger.INSTANCE.trace( - "%s generated exception in parsing, stack trace is %s", - DEVELOPER_MODE_SYSTEM_PROPRETY_NAME, ExceptionUtils.getStackTrace(e)); + public InProcessTelemetryChannel() { + boolean developerMode = false; + try { + String developerModeAsString = System.getProperty(DEVELOPER_MODE_SYSTEM_PROPRETY_NAME); + if (!LocalStringsUtils.isNullOrEmpty(developerModeAsString)) { + developerMode = Boolean.valueOf(developerModeAsString); + } + } catch (Exception e) { + developerMode = false; + InternalLogger.INSTANCE.trace("%s generated exception in parsing, stack trace is %s", DEVELOPER_MODE_SYSTEM_PROPRETY_NAME, ExceptionUtils.getStackTrace(e)); + } + initialize(null, null, developerMode, createDefaultMaxTelemetryBufferCapacityEnforcer(null), + createDefaultSendIntervalInSecondsEnforcer(null), true); } - initialize( - null, - null, - developerMode, - createDefaultMaxTelemetryBufferCapacityEnforcer(null), - createDefaultSendIntervalInSecondsEnforcer(null), - true); - } /** * Ctor @@ -136,14 +127,15 @@ public InProcessTelemetryChannel( int maxTelemetryBufferCapacity, int sendIntervalInMillis) { - //Builder pattern implementation + // Builder pattern implementation this( endpointAddress, null, developerMode, maxTelemetryBufferCapacity, sendIntervalInMillis, - true, DEFAULT_MAX_INSTANT_RETRY); + true, + DEFAULT_MAX_INSTANT_RETRY); } public InProcessTelemetryChannel( @@ -152,58 +144,59 @@ public InProcessTelemetryChannel( boolean developerMode, int maxTelemetryBufferCapacity, int sendIntervalInMillis, - boolean throttling, int maxInstantRetries) { + boolean throttling, + int maxInstantRetries) { initialize( endpointAddress, maxTransmissionStorageCapacity, developerMode, createDefaultMaxTelemetryBufferCapacityEnforcer(maxTelemetryBufferCapacity), createDefaultSendIntervalInSecondsEnforcer(sendIntervalInMillis), - throttling, maxInstantRetries); + throttling, + maxInstantRetries); } - /** - * This Ctor will query the 'namesAndValues' map for data to initialize itself It will ignore data - * that is not of its interest, this Ctor is useful for building an instance from configuration - * - * @param namesAndValues - The data passed as name and value pairs - */ - public InProcessTelemetryChannel(Map namesAndValues) { - boolean developerMode = false; - String endpointAddress = null; - int maxInstantRetries = DEFAULT_MAX_INSTANT_RETRY; - - LimitsEnforcer maxTelemetryBufferCapacityEnforcer = - createDefaultMaxTelemetryBufferCapacityEnforcer(null); - - LimitsEnforcer sendIntervalInSecondsEnforcer = createDefaultSendIntervalInSecondsEnforcer(null); - - boolean throttling = true; - if (namesAndValues != null) { - throttling = Boolean.valueOf(namesAndValues.get("Throttling")); - developerMode = Boolean.valueOf(namesAndValues.get(DEVELOPER_MODE_NAME)); - try { - String instantRetryValue = namesAndValues.get(INSTANT_RETRY_NAME); - if (instantRetryValue != null) { - maxInstantRetries = Integer.parseInt(instantRetryValue); - } - - } catch (NumberFormatException e) { - InternalLogger.INSTANCE.error( - "Unable to parse configuration setting %s to integer value.%nStack Trace:%n%s", - INSTANT_RETRY_NAME, ExceptionUtils.getStackTrace(e)); - } + /** + * This Ctor will query the 'namesAndValues' map for data to initialize itself + * It will ignore data that is not of its interest, this Ctor is useful for + * building an instance from configuration + * + * @param namesAndValues + * - The data passed as name and value pairs + */ + public InProcessTelemetryChannel(Map namesAndValues) { + boolean developerMode = false; + String endpointAddress = null; + int maxInstantRetries = DEFAULT_MAX_INSTANT_RETRY; + + LimitsEnforcer maxTelemetryBufferCapacityEnforcer = createDefaultMaxTelemetryBufferCapacityEnforcer(null); + + LimitsEnforcer sendIntervalInSecondsEnforcer = createDefaultSendIntervalInSecondsEnforcer(null); + + boolean throttling = true; + if (namesAndValues != null) { + throttling = Boolean.valueOf(namesAndValues.get("Throttling")); + developerMode = Boolean.valueOf(namesAndValues.get(DEVELOPER_MODE_NAME)); + try { + String instantRetryValue = namesAndValues.get(INSTANT_RETRY_NAME); + if (instantRetryValue != null){ + maxInstantRetries = Integer.parseInt(instantRetryValue); + } + + } catch (NumberFormatException e) { + InternalLogger.INSTANCE.error("Unable to parse configuration setting %s to integer value.%nStack Trace:%n%s", INSTANT_RETRY_NAME, ExceptionUtils.getStackTrace(e)); + } if (!developerMode) { developerMode = Boolean.valueOf(System.getProperty(DEVELOPER_MODE_SYSTEM_PROPRETY_NAME)); } endpointAddress = namesAndValues.get(ENDPOINT_ADDRESS_NAME); - maxTelemetryBufferCapacityEnforcer.normalizeStringValue( - namesAndValues.get(MAX_MAX_TELEMETRY_BUFFER_CAPACITY_NAME)); - sendIntervalInSecondsEnforcer.normalizeStringValue( - namesAndValues.get(FLUSH_BUFFER_TIMEOUT_IN_SECONDS_NAME)); - } + maxTelemetryBufferCapacityEnforcer + .normalizeStringValue(namesAndValues.get(MAX_MAX_TELEMETRY_BUFFER_CAPACITY_NAME)); + sendIntervalInSecondsEnforcer + .normalizeStringValue(namesAndValues.get(FLUSH_BUFFER_TIMEOUT_IN_SECONDS_NAME)); + } String maxTransmissionStorageCapacity = namesAndValues.get(MAX_TRANSMISSION_STORAGE_CAPACITY_NAME); @@ -217,221 +210,208 @@ public InProcessTelemetryChannel(Map namesAndValues) { maxInstantRetries); } - /** Gets value indicating whether this channel is in developer mode. */ - @Override - public boolean isDeveloperMode() { - return developerMode; - } - - /** - * Sets value indicating whether this channel is in developer mode. - * - * @param developerMode True or false - */ - @Override - public void setDeveloperMode(boolean developerMode) { - if (developerMode != this.developerMode) { - this.developerMode = developerMode; - int maxTelemetriesInBatch = this.developerMode ? 1 : DEFAULT_MAX_TELEMETRY_BUFFER_CAPACITY; + /** + * Gets value indicating whether this channel is in developer mode. + */ + @Override + public boolean isDeveloperMode() { + return developerMode; + } - setMaxTelemetriesInBatch(maxTelemetriesInBatch); + /** + * Sets value indicating whether this channel is in developer mode. + * + * @param developerMode + * True or false + */ + @Override + public void setDeveloperMode(boolean developerMode) { + if (developerMode != this.developerMode) { + this.developerMode = developerMode; + int maxTelemetriesInBatch = this.developerMode ? 1 : DEFAULT_MAX_TELEMETRY_BUFFER_CAPACITY; + + setMaxTelemetriesInBatch(maxTelemetriesInBatch); + } } - } - /** Sends a Telemetry instance through the channel. */ - @Override - public void send(Telemetry telemetry) { - Preconditions.checkNotNull(telemetry, "Telemetry item must be non null"); + /** + * Sends a Telemetry instance through the channel. + */ + @Override + public void send(Telemetry telemetry) { + Preconditions.checkNotNull(telemetry, "Telemetry item must be non null"); - if (isDeveloperMode()) { - telemetry.getContext().getProperties().put("DeveloperMode", "true"); - } + if (isDeveloperMode()) { + telemetry.getContext().getProperties().put("DeveloperMode", "true"); + } - if (telemetrySampler != null) { - if (!telemetrySampler.isSampledIn(telemetry)) { - return; - } - } + if (telemetrySampler != null) { + if (!telemetrySampler.isSampledIn(telemetry)) { + return; + } + } - StringWriter writer = new StringWriter(); - JsonTelemetryDataSerializer jsonWriter = null; - try { - jsonWriter = new JsonTelemetryDataSerializer(writer); - telemetry.serialize(jsonWriter); - jsonWriter.close(); - String asJson = writer.toString(); - telemetryBuffer.add(asJson); - telemetry.reset(); - if (itemsSent.incrementAndGet() % 10000 == 0) { - InternalLogger.INSTANCE.info("items sent till now %d", itemsSent.get()); - } + StringWriter writer = new StringWriter(); + JsonTelemetryDataSerializer jsonWriter = null; + try { + jsonWriter = new JsonTelemetryDataSerializer(writer); + telemetry.serialize(jsonWriter); + jsonWriter.close(); + String asJson = writer.toString(); + telemetryBuffer.add(asJson); + telemetry.reset(); + if (itemsSent.incrementAndGet() % 10000 == 0) { + InternalLogger.INSTANCE.info("items sent till now %d", itemsSent.get()); + } + + } catch (IOException e) { + InternalLogger.INSTANCE.error("Failed to serialize Telemetry"); + InternalLogger.INSTANCE.trace("Stack trace is %s", ExceptionUtils.getStackTrace(e)); + return; + } - } catch (IOException e) { - InternalLogger.INSTANCE.error("Failed to serialize Telemetry"); - InternalLogger.INSTANCE.trace("Stack trace is %s", ExceptionUtils.getStackTrace(e)); - return; + if (isDeveloperMode()) { + writeTelemetryToDebugOutput(telemetry); + } } - if (isDeveloperMode()) { - writeTelemetryToDebugOutput(telemetry); + /** + * Stops on going work + */ + @Override + public synchronized void stop(long timeout, TimeUnit timeUnit) { + try { + if (stopped) { + return; + } + + telemetriesTransmitter.stop(timeout, timeUnit); + stopped = true; + } catch (ThreadDeath td) { + throw td; + } catch (Throwable t) { + try { + InternalLogger.INSTANCE.error("Exception generated while stopping telemetry transmitter"); + InternalLogger.INSTANCE.trace("Stack trace generated is %s", ExceptionUtils.getStackTrace(t)); + } catch (ThreadDeath td) { + throw td; + } catch (Throwable t2) { + // chomp + } + } } - } - /** Stops on going work */ - @Override - public synchronized void stop(long timeout, TimeUnit timeUnit) { - try { - if (stopped) { - return; - } + /** + * Flushes the data that the channel might have internally. + */ + @Override + public void flush() { + telemetryBuffer.flush(); + } - telemetriesTransmitter.stop(timeout, timeUnit); - stopped = true; - } catch (ThreadDeath td) { - throw td; - } catch (Throwable t) { - try { - InternalLogger.INSTANCE.error("Exception generated while stopping telemetry transmitter"); - InternalLogger.INSTANCE.trace( - "Stack trace generated is %s", ExceptionUtils.getStackTrace(t)); - } catch (ThreadDeath td) { - throw td; - } catch (Throwable t2) { - // chomp - } + /** + * Sets an optional Sampler that can sample out telemetries Currently, we don't + * allow to replace a valid telemtry sampler. + * + * @param telemetrySampler + * - The sampler + */ + @Override + public void setSampler(TelemetrySampler telemetrySampler) { + if (this.telemetrySampler == null) { + this.telemetrySampler = telemetrySampler; + } } - } - /** Flushes the data that the channel might have internally. */ - @Override - public void flush() { - telemetryBuffer.flush(); - } + /** + * Sets the buffer size + * + * @param maxTelemetriesInBatch + * should be between MIN_MAX_TELEMETRY_BUFFER_CAPACITY and + * MAX_MAX_TELEMETRY_BUFFER_CAPACITY inclusive if the number is lower + * than the minimum then the minimum will be used if the number is + * higher than the maximum then the maximum will be used + */ + public void setMaxTelemetriesInBatch(int maxTelemetriesInBatch) { + telemetryBuffer.setMaxTelemetriesInBatch(maxTelemetriesInBatch); + } - /** - * Sets an optional Sampler that can sample out telemetries Currently, we don't allow to replace a - * valid telemtry sampler. - * - * @param telemetrySampler - The sampler - */ - @Override - public void setSampler(TelemetrySampler telemetrySampler) { - if (this.telemetrySampler == null) { - this.telemetrySampler = telemetrySampler; + /** + * Sets the time tow wait before flushing the internal buffer + * + * @param transmitBufferTimeoutInSeconds + * should be between MIN_FLUSH_BUFFER_TIMEOUT_IN_SECONDS and + * MAX_FLUSH_BUFFER_TIMEOUT_IN_SECONDS inclusive if the number is + * lower than the minimum then the minimum will be used if the number + * is higher than the maximum then the maximum will be used + */ + public void setTransmitBufferTimeoutInSeconds(int transmitBufferTimeoutInSeconds) { + telemetryBuffer.setTransmitBufferTimeoutInSeconds(transmitBufferTimeoutInSeconds); } - } - /** - * Sets the buffer size - * - * @param maxTelemetriesInBatch should be between MIN_MAX_TELEMETRY_BUFFER_CAPACITY and - * MAX_MAX_TELEMETRY_BUFFER_CAPACITY inclusive if the number is lower than the minimum then - * the minimum will be used if the number is higher than the maximum then the maximum will be - * used - */ - public void setMaxTelemetriesInBatch(int maxTelemetriesInBatch) { - telemetryBuffer.setMaxTelemetriesInBatch(maxTelemetriesInBatch); - } + private void writeTelemetryToDebugOutput(Telemetry telemetry) { + InternalLogger.INSTANCE.trace("InProcessTelemetryChannel sending telemetry"); + } - /** - * Sets the time tow wait before flushing the internal buffer - * - * @param transmitBufferTimeoutInSeconds should be between MIN_FLUSH_BUFFER_TIMEOUT_IN_SECONDS and - * MAX_FLUSH_BUFFER_TIMEOUT_IN_SECONDS inclusive if the number is lower than the minimum then - * the minimum will be used if the number is higher than the maximum then the maximum will be - * used - */ - public void setTransmitBufferTimeoutInSeconds(int transmitBufferTimeoutInSeconds) { - telemetryBuffer.setTransmitBufferTimeoutInSeconds(transmitBufferTimeoutInSeconds); - } + private synchronized void initialize(String endpointAddress, String maxTransmissionStorageCapacity, + boolean developerMode, LimitsEnforcer maxTelemetryBufferCapacityEnforcer, + LimitsEnforcer sendIntervalInSeconds, boolean throttling) { + initialize(endpointAddress, maxTransmissionStorageCapacity, developerMode, maxTelemetryBufferCapacityEnforcer, + sendIntervalInSeconds, throttling, DEFAULT_MAX_INSTANT_RETRY); + } - private void writeTelemetryToDebugOutput(Telemetry telemetry) { - InternalLogger.INSTANCE.trace("InProcessTelemetryChannel sending telemetry"); - } + private synchronized void initialize(String endpointAddress, String maxTransmissionStorageCapacity, + boolean developerMode, LimitsEnforcer maxTelemetryBufferCapacityEnforcer, + LimitsEnforcer sendIntervalInSeconds, boolean throttling, int maxInstantRetry) { + makeSureEndpointAddressIsValid(endpointAddress); - private synchronized void initialize( - String endpointAddress, - String maxTransmissionStorageCapacity, - boolean developerMode, - LimitsEnforcer maxTelemetryBufferCapacityEnforcer, - LimitsEnforcer sendIntervalInSeconds, - boolean throttling) { - initialize( - endpointAddress, - maxTransmissionStorageCapacity, - developerMode, - maxTelemetryBufferCapacityEnforcer, - sendIntervalInSeconds, - throttling, - DEFAULT_MAX_INSTANT_RETRY); - } + if (s_transmitterFactory == null) { + s_transmitterFactory = new InProcessTelemetryChannelFactory(); + } - private synchronized void initialize( - String endpointAddress, - String maxTransmissionStorageCapacity, - boolean developerMode, - LimitsEnforcer maxTelemetryBufferCapacityEnforcer, - LimitsEnforcer sendIntervalInSeconds, - boolean throttling, - int maxInstantRetry) { - makeSureEndpointAddressIsValid(endpointAddress); + telemetriesTransmitter = s_transmitterFactory.create(endpointAddress, maxTransmissionStorageCapacity, + throttling, maxInstantRetry); + telemetryBuffer = new TelemetryBuffer(telemetriesTransmitter, maxTelemetryBufferCapacityEnforcer, + sendIntervalInSeconds); - if (s_transmitterFactory == null) { - s_transmitterFactory = new InProcessTelemetryChannelFactory(); + setDeveloperMode(developerMode); } - telemetriesTransmitter = - s_transmitterFactory.create( - endpointAddress, maxTransmissionStorageCapacity, throttling, maxInstantRetry); - telemetryBuffer = - new TelemetryBuffer( - telemetriesTransmitter, maxTelemetryBufferCapacityEnforcer, sendIntervalInSeconds); - - setDeveloperMode(developerMode); - } - - /** - * The method will throw IllegalArgumentException if the endpointAddress is not a valid uri Please - * note that a null or empty string is valid as far as the class is concerned and thus considered - * valid - * - * @param endpointAddress - */ - private void makeSureEndpointAddressIsValid(String endpointAddress) { - if (Strings.isNullOrEmpty(endpointAddress)) { - return; - } + /** + * The method will throw IllegalArgumentException if the endpointAddress is not + * a valid uri Please note that a null or empty string is valid as far as the + * class is concerned and thus considered valid + * + * @param endpointAddress + */ + private void makeSureEndpointAddressIsValid(String endpointAddress) { + if (Strings.isNullOrEmpty(endpointAddress)) { + return; + } - URI uri = Sanitizer.sanitizeUri(endpointAddress); - if (uri == null) { - String errorMessage = - String.format("Endpoint address %s is not a valid uri", endpointAddress); - InternalLogger.INSTANCE.error(errorMessage); - throw new IllegalArgumentException(errorMessage); + URI uri = Sanitizer.sanitizeUri(endpointAddress); + if (uri == null) { + String errorMessage = String.format("Endpoint address %s is not a valid uri", endpointAddress); + InternalLogger.INSTANCE.error(errorMessage); + throw new IllegalArgumentException(errorMessage); + } } - } - private LimitsEnforcer createDefaultMaxTelemetryBufferCapacityEnforcer(Integer currentValue) { - LimitsEnforcer maxItemsInBatchEnforcer = - LimitsEnforcer.createWithClosestLimitOnError( - MAX_MAX_TELEMETRY_BUFFER_CAPACITY_NAME, - MIN_MAX_TELEMETRY_BUFFER_CAPACITY, - MAX_MAX_TELEMETRY_BUFFER_CAPACITY, - DEFAULT_MAX_TELEMETRY_BUFFER_CAPACITY, - currentValue == null ? DEFAULT_MAX_TELEMETRY_BUFFER_CAPACITY : currentValue); + private LimitsEnforcer createDefaultMaxTelemetryBufferCapacityEnforcer(Integer currentValue) { + LimitsEnforcer maxItemsInBatchEnforcer = LimitsEnforcer.createWithClosestLimitOnError( + MAX_MAX_TELEMETRY_BUFFER_CAPACITY_NAME, MIN_MAX_TELEMETRY_BUFFER_CAPACITY, + MAX_MAX_TELEMETRY_BUFFER_CAPACITY, DEFAULT_MAX_TELEMETRY_BUFFER_CAPACITY, + currentValue == null ? DEFAULT_MAX_TELEMETRY_BUFFER_CAPACITY : currentValue); - return maxItemsInBatchEnforcer; - } + return maxItemsInBatchEnforcer; + } - private LimitsEnforcer createDefaultSendIntervalInSecondsEnforcer(Integer currentValue) { - LimitsEnforcer sendIntervalInSecondsEnforcer = - LimitsEnforcer.createWithClosestLimitOnError( - FLUSH_BUFFER_TIMEOUT_IN_SECONDS_NAME, - MIN_FLUSH_BUFFER_TIMEOUT_IN_SECONDS, - MAX_FLUSH_BUFFER_TIMEOUT_IN_SECONDS, - DEFAULT_FLUSH_BUFFER_TIMEOUT_IN_SECONDS, - currentValue == null ? DEFAULT_FLUSH_BUFFER_TIMEOUT_IN_SECONDS : currentValue); + private LimitsEnforcer createDefaultSendIntervalInSecondsEnforcer(Integer currentValue) { + LimitsEnforcer sendIntervalInSecondsEnforcer = LimitsEnforcer.createWithClosestLimitOnError( + FLUSH_BUFFER_TIMEOUT_IN_SECONDS_NAME, MIN_FLUSH_BUFFER_TIMEOUT_IN_SECONDS, + MAX_FLUSH_BUFFER_TIMEOUT_IN_SECONDS, DEFAULT_FLUSH_BUFFER_TIMEOUT_IN_SECONDS, + currentValue == null ? DEFAULT_FLUSH_BUFFER_TIMEOUT_IN_SECONDS : currentValue); - return sendIntervalInSecondsEnforcer; - } + return sendIntervalInSecondsEnforcer; + } } diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/FixedRateSamplingTelemetryProcessor.java b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/FixedRateSamplingTelemetryProcessor.java index 4d536ea345f..c0448fba36f 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/FixedRateSamplingTelemetryProcessor.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/FixedRateSamplingTelemetryProcessor.java @@ -11,14 +11,11 @@ import com.microsoft.applicationinsights.telemetry.SupportSampling; import com.microsoft.applicationinsights.telemetry.Telemetry; import com.microsoft.applicationinsights.telemetry.TraceTelemetry; -import org.apache.commons.lang3.exception.ExceptionUtils; - import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; - -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; /** * This processor is used to Perform Sampling on User specified sampling rate @@ -47,7 +44,7 @@ @BuiltInProcessor("FixedRateSamplingTelemetryProcessor") public final class FixedRateSamplingTelemetryProcessor implements TelemetryProcessor { - public static final double DEFAULT_SAMPLING_PERCENTAGE = 100.; + public static final double DEFAULT_SAMPLING_PERCENTAGE = 100.0; private static Map allowedTypes = new HashMap<>(); static { @@ -104,7 +101,7 @@ private void setIncludedOrExcludedTypes(String value, Set typeSet) { if (telemetryType != null) { typeSet.add(allowedTypes.get(telemetryType)); } else { - InternalLogger.INSTANCE.error("Telemetry type " + value + " is either not allowed to sample or is empty"); + InternalLogger.INSTANCE.error("Telemetry type %s is either not allowed to sample or is empty", value); } } From 62c50fe77617b3de5e0812e000b61c13c2728b23 Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Thu, 26 Apr 2018 09:36:16 -0700 Subject: [PATCH 36/43] fix test and intermediate commit --- .../FixedRateSamplingTelemetryProcessor.java | 24 ++++++++++----- .../TelemetryConfigurationFactoryTest.java | 29 +++++++++++-------- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/FixedRateSamplingTelemetryProcessor.java b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/FixedRateSamplingTelemetryProcessor.java index c0448fba36f..899f03682e0 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/FixedRateSamplingTelemetryProcessor.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/FixedRateSamplingTelemetryProcessor.java @@ -11,11 +11,12 @@ import com.microsoft.applicationinsights.telemetry.SupportSampling; import com.microsoft.applicationinsights.telemetry.Telemetry; import com.microsoft.applicationinsights.telemetry.TraceTelemetry; +import org.apache.commons.lang3.exception.ExceptionUtils; + import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; -import org.apache.commons.lang3.exception.ExceptionUtils; /** * This processor is used to Perform Sampling on User specified sampling rate @@ -45,15 +46,22 @@ public final class FixedRateSamplingTelemetryProcessor implements TelemetryProcessor { public static final double DEFAULT_SAMPLING_PERCENTAGE = 100.0; - private static Map allowedTypes = new HashMap<>(); + private static Map allowedTypes = new HashMap<>(); + + private static final String dependencyTelemetryName = "Dependency"; + private static final String eventTelemetryName = "Event"; + private static final String exceptionTelemetryName = "Exception"; + private static final String pageViewTelemetryName = "PageView"; + private static final String requestTelemetryName = "Request"; + private static final String traceTelemetryName = "Trace"; static { - allowedTypes.put(TelemetryType.Dependency, RemoteDependencyTelemetry.class); - allowedTypes.put(TelemetryType.Event, EventTelemetry.class); - allowedTypes.put(TelemetryType.Exception, ExceptionTelemetry.class); - allowedTypes.put(TelemetryType.PageView, PageViewTelemetry.class); - allowedTypes.put(TelemetryType.Request, RequestTelemetry.class); - allowedTypes.put(TelemetryType.Trace, TraceTelemetry.class); + allowedTypes.put(dependencyTelemetryName, RemoteDependencyTelemetry.class); + allowedTypes.put(eventTelemetryName, EventTelemetry.class); + allowedTypes.put(exceptionTelemetryName, ExceptionTelemetry.class); + allowedTypes.put(pageViewTelemetryName, PageViewTelemetry.class); + allowedTypes.put(requestTelemetryName, RequestTelemetry.class); + allowedTypes.put(traceTelemetryName, TraceTelemetry.class); } private Set excludedTypes; diff --git a/core/src/test/java/com/microsoft/applicationinsights/internal/config/TelemetryConfigurationFactoryTest.java b/core/src/test/java/com/microsoft/applicationinsights/internal/config/TelemetryConfigurationFactoryTest.java index 8b05850874b..d512f9ec160 100644 --- a/core/src/test/java/com/microsoft/applicationinsights/internal/config/TelemetryConfigurationFactoryTest.java +++ b/core/src/test/java/com/microsoft/applicationinsights/internal/config/TelemetryConfigurationFactoryTest.java @@ -21,33 +21,31 @@ package com.microsoft.applicationinsights.internal.config; -import java.io.InputStream; -import java.lang.reflect.Field; -import java.util.*; - import com.microsoft.applicationinsights.TelemetryConfiguration; import com.microsoft.applicationinsights.channel.concrete.inprocess.InProcessTelemetryChannel; import com.microsoft.applicationinsights.extensibility.TelemetryModule; import com.microsoft.applicationinsights.extensibility.TelemetryProcessor; -import com.microsoft.applicationinsights.internal.channel.stdout.StdOutChannel; - import com.microsoft.applicationinsights.internal.annotation.PerformanceModule; +import com.microsoft.applicationinsights.internal.channel.stdout.StdOutChannel; import com.microsoft.applicationinsights.internal.perfcounter.PerformanceCounterConfigurationAware; import com.microsoft.applicationinsights.internal.processor.RequestTelemetryFilter; import com.microsoft.applicationinsights.internal.processor.SyntheticSourceFilter; import com.microsoft.applicationinsights.internal.reflect.ClassDataUtils; import com.microsoft.applicationinsights.internal.reflect.ClassDataVerifier; - +import org.junit.After; +import org.junit.Assert; +import org.junit.Test; import org.mockito.Mockito; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; -import org.junit.Test; -import org.junit.Assert; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.notNull; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; public final class TelemetryConfigurationFactoryTest { @@ -533,4 +531,11 @@ private void ikeyTest(String configurationIkey, String expectedIkey) { assertEquals(mockConfiguration.getInstrumentationKey(), expectedIkey); assertTrue(mockConfiguration.getChannel() instanceof InProcessTelemetryChannel); } + + @After + public void tearDown() throws Exception { + Method method = TelemetryConfiguration.class.getDeclaredMethod("setActiveAsNull"); + method.setAccessible(true); + method.invoke(null); + } } From 613e59db83291f071d187f938f0ae782f3890a9d Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Thu, 3 May 2018 20:48:50 -0700 Subject: [PATCH 37/43] removing TelemetryType enum for better maintanability, refactoring starter accordingly, making HeartBeatPayloadProviderInterface bean, fixing critical issue with sampling configuration --- ...pplicationInsightsModuleConfiguration.java | 42 ++++++++++++++++--- .../boot/ApplicationInsightsProperties.java | 35 ++++++++++------ ...ionInsightsTelemetryAutoConfiguration.java | 28 ++++--------- ...sightsTelemetryAutoConfigurationTests.java | 3 +- .../FixedRateSamplingTelemetryProcessor.java | 15 ++++--- .../channel/samplingV2/TelemetryType.java | 19 --------- 6 files changed, 78 insertions(+), 64 deletions(-) delete mode 100644 core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/TelemetryType.java diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java index f73d458d2c1..9a8d63c6882 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsModuleConfiguration.java @@ -22,15 +22,21 @@ package com.microsoft.applicationinsights.boot; import com.microsoft.applicationinsights.boot.ApplicationInsightsProperties.HeartBeat; +import com.microsoft.applicationinsights.boot.ApplicationInsightsProperties.TelemetryProcessor.Sampling; import com.microsoft.applicationinsights.boot.HeartBeatProvider.SpringBootHeartBeatProvider; import com.microsoft.applicationinsights.boot.initializer.SpringBootTelemetryInitializer; +import com.microsoft.applicationinsights.extensibility.TelemetryProcessor; import com.microsoft.applicationinsights.extensibility.initializer.DeviceInfoContextInitializer; import com.microsoft.applicationinsights.extensibility.initializer.SdkVersionContextInitializer; +import com.microsoft.applicationinsights.internal.channel.samplingV2.FixedRateSamplingTelemetryProcessor; import com.microsoft.applicationinsights.internal.heartbeat.HeartBeatModule; +import com.microsoft.applicationinsights.internal.heartbeat.HeartBeatPayloadProviderInterface; +import com.microsoft.applicationinsights.internal.heartbeat.HeartBeatProviderInterface; import com.microsoft.applicationinsights.internal.heartbeat.HeartbeatDefaultPayload; import com.microsoft.applicationinsights.internal.perfcounter.JvmPerformanceCountersModule; import com.microsoft.applicationinsights.internal.perfcounter.ProcessPerformanceCountersModule; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -126,17 +132,23 @@ public JvmPerformanceCountersModule jvmPerformanceCountersModule() { } } + @Bean + @ConditionalOnMissingBean + public HeartBeatPayloadProviderInterface heartBeatProviderInterface(Environment environment) { + return new SpringBootHeartBeatProvider(environment); + } + /** * Bean for HeartBeatModule. This also sets the properties for HeartBeatModule - * @param environment + * @param heartBeatPayloadProviderInterface * @return initialized instance with user specified properties of {@link HeartBeatModule} */ @Bean - @ConditionalOnProperty(value = "azure.application-insights.default.modules.HeartBeat.enabled", havingValue = "true", matchIfMissing = true) - public HeartBeatModule heartBeatModule(Environment environment) { + @ConditionalOnProperty(value = "azure.application-insights.heart-beat.enabled", havingValue = "true", matchIfMissing = true) + public HeartBeatModule heartBeatModule(HeartBeatPayloadProviderInterface heartBeatPayloadProviderInterface) { try { HeartBeatModule heartBeatModule = new HeartBeatModule(); - HeartbeatDefaultPayload.addDefaultPayLoadProvider(new SpringBootHeartBeatProvider(environment)); + HeartbeatDefaultPayload.addDefaultPayLoadProvider(heartBeatPayloadProviderInterface); HeartBeat heartBeat = applicationInsightsProperties.getHeartBeat(); heartBeatModule.setHeartBeatInterval(heartBeat.getHeartBeatInterval()); if (heartBeat.getExcludedHeartBeatPropertiesList().size() > 0) { @@ -148,8 +160,28 @@ public HeartBeatModule heartBeatModule(Environment environment) { return heartBeatModule; } catch (Exception e) { - throw new IllegalStateException("could not configure Heartbeat, please set 'azure.application-insights.default.modules.HearBeat.enabled'" + throw new IllegalStateException("could not configure Heartbeat, please set 'azure.application-insights.heart-beat.enabled'" + " to false ", e); } } + + /** + * Bean for FixedRateSamplingTelemetryProcessor. This bean helps in configuring the fixed rate sampling. + * @return instance of {@link FixedRateSamplingTelemetryProcessor} + */ + @Bean + @ConditionalOnProperty(value = "azure.application-insights.telemetry-processor.sampling.enabled", havingValue = "true") + public TelemetryProcessor fixedRateSamplingTelemetryProcessor() { + Sampling sampling = applicationInsightsProperties.getTelemetryProcessor().getSampling(); + FixedRateSamplingTelemetryProcessor processor = new FixedRateSamplingTelemetryProcessor(); + processor.setSamplingPercentage(String.valueOf(sampling.getPercentage())); + for (String include : sampling.getInclude()) { + processor.addToIncludedType(include); + } + for (String exclude : sampling.getExclude()) { + processor.addToExcludedType(exclude); + } + return processor; + } + } diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java index 354a666c486..2c8ce00f790 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsProperties.java @@ -25,7 +25,6 @@ import com.microsoft.applicationinsights.internal.channel.common.TransmissionFileSystemOutput; import com.microsoft.applicationinsights.internal.channel.common.TransmissionNetworkOutput; import com.microsoft.applicationinsights.internal.channel.samplingV2.FixedRateSamplingTelemetryProcessor; -import com.microsoft.applicationinsights.internal.channel.samplingV2.TelemetryType; import com.microsoft.applicationinsights.internal.heartbeat.HeartBeatProvider; import com.microsoft.applicationinsights.internal.jmx.JmxAttributeData; import com.microsoft.applicationinsights.internal.logger.InternalLogger; @@ -42,13 +41,12 @@ import com.microsoft.applicationinsights.web.extensibility.modules.WebSessionTrackingTelemetryModule; import com.microsoft.applicationinsights.web.extensibility.modules.WebUserTrackingTelemetryModule; import com.microsoft.applicationinsights.web.internal.perfcounter.WebPerformanceCounterModule; -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.springframework.boot.context.properties.ConfigurationProperties; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.boot.context.properties.ConfigurationProperties; /** *

This class is the container for Configuration Properties of Application Insights

@@ -278,6 +276,9 @@ public void setSampling(Sampling sampling) { } static class Sampling { + + private boolean enabled = false; + /** * Percent of telemetry events that will be sent to Application Insights. Percentage must be * close to 100/N where N is an integer. E.g. 50 (=100/2), 33.33 (=100/3), 25 (=100/4), 20, 1 @@ -285,9 +286,17 @@ static class Sampling { */ private double percentage = FixedRateSamplingTelemetryProcessor.DEFAULT_SAMPLING_PERCENTAGE; /** If set only telemetry of specified types will be included. */ - private List include = new ArrayList<>(); + private List include = new ArrayList<>(); /** If set telemetry of specified type will be excluded. */ - private List exclude = new ArrayList<>(); + private List exclude = new ArrayList<>(); + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } public double getPercentage() { return percentage; @@ -297,19 +306,19 @@ public void setPercentage(double percentage) { this.percentage = percentage; } - public List getInclude() { + public List getInclude() { return include; } - public void setInclude(List include) { + public void setInclude(List include) { this.include = include; } - public List getExclude() { + public List getExclude() { return exclude; } - public void setExclude(List exclude) { + public void setExclude(List exclude) { this.exclude = exclude; } } @@ -409,7 +418,7 @@ static class HeartBeat { /** * Switch to enable / disable heartbeat */ - boolean isEnabled = false; + boolean enabled = false; /** * The heartbeat interval in seconds. @@ -427,11 +436,11 @@ static class HeartBeat { List excludedHeartBeatPropertiesList = new ArrayList<>(); public boolean isEnabled() { - return isEnabled; + return enabled; } public void setEnabled(boolean enabled) { - isEnabled = enabled; + this.enabled = enabled; } public long getHeartBeatInterval() { diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java index 613bc174cfd..800e4caaa25 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfiguration.java @@ -21,6 +21,8 @@ package com.microsoft.applicationinsights.boot; +import static org.slf4j.LoggerFactory.getLogger; + import com.microsoft.applicationinsights.TelemetryClient; import com.microsoft.applicationinsights.TelemetryConfiguration; import com.microsoft.applicationinsights.boot.ApplicationInsightsProperties.Channel.InProcess; @@ -32,10 +34,13 @@ import com.microsoft.applicationinsights.extensibility.TelemetryModule; import com.microsoft.applicationinsights.extensibility.TelemetryProcessor; import com.microsoft.applicationinsights.internal.channel.samplingV2.FixedRateSamplingTelemetryProcessor; -import com.microsoft.applicationinsights.internal.channel.samplingV2.TelemetryType; import com.microsoft.applicationinsights.internal.logger.InternalLogger; import com.microsoft.applicationinsights.internal.perfcounter.PerformanceCounterContainer; import com.microsoft.applicationinsights.internal.quickpulse.QuickPulse; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -47,13 +52,6 @@ import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.Import; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static org.slf4j.LoggerFactory.getLogger; - /** *

The central class for configuring and creating initialized {@link TelemetryConfiguration}

* @@ -153,19 +151,7 @@ public TelemetryClient telemetryClient(TelemetryConfiguration configuration) { return new TelemetryClient(configuration); } - @Bean - public FixedRateSamplingTelemetryProcessor fixedRateSamplingTelemetryProcessor() { - Sampling sampling = applicationInsightsProperties.getTelemetryProcessor().getSampling(); - FixedRateSamplingTelemetryProcessor processor = new FixedRateSamplingTelemetryProcessor(); - processor.setSamplingPercentage(String.valueOf(sampling.getPercentage())); - for (TelemetryType include : sampling.getInclude()) { - processor.addToIncludedType(include.name()); - } - for (TelemetryType exclude : sampling.getExclude()) { - processor.addToExcludedType(exclude.name()); - } - return processor; - } + @Bean @ConditionalOnMissingBean diff --git a/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java b/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java index d1b4135d576..316e9bfc8bb 100644 --- a/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java +++ b/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsTelemetryAutoConfigurationTests.java @@ -166,7 +166,8 @@ public void shouldBeAbleToConfigureSamplingTelemetryProcessor() { EnvironmentTestUtils.addEnvironment(context, "azure.application-insights.instrumentation-key: 00000000-0000-0000-0000-000000000000", "azure.application-insights.telemetry-processor.sampling.percentage=50", - "azure.application-insights.telemetry-processor.sampling.include=Request"); + "azure.application-insights.telemetry-processor.sampling.include=Request", + "azure.application-insights.telemetry-processor.sampling.enabled=true"); context.register(PropertyPlaceholderAutoConfiguration.class, ApplicationInsightsTelemetryAutoConfiguration.class); context.refresh(); diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/FixedRateSamplingTelemetryProcessor.java b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/FixedRateSamplingTelemetryProcessor.java index 899f03682e0..57921a3d046 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/FixedRateSamplingTelemetryProcessor.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/FixedRateSamplingTelemetryProcessor.java @@ -11,6 +11,7 @@ import com.microsoft.applicationinsights.telemetry.SupportSampling; import com.microsoft.applicationinsights.telemetry.Telemetry; import com.microsoft.applicationinsights.telemetry.TraceTelemetry; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; import java.util.HashMap; @@ -104,12 +105,16 @@ public Set getIncludedTypes() { private void setIncludedOrExcludedTypes(String value, Set typeSet) { - value = value.trim(); - TelemetryType telemetryType = TelemetryType.valueOfOrNull(value); - if (telemetryType != null) { - typeSet.add(allowedTypes.get(telemetryType)); + + if (!StringUtils.isEmpty(value)) { + value = value.trim(); + if (!StringUtils.isEmpty(value) && allowedTypes.containsKey(value)) { + typeSet.add(allowedTypes.get(value)); + } else { + InternalLogger.INSTANCE.error("Item %s is either not allowed to sample or is empty", value); + } } else { - InternalLogger.INSTANCE.error("Telemetry type %s is either not allowed to sample or is empty", value); + InternalLogger.INSTANCE.error("Telemetry type %s is empty", value); } } diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/TelemetryType.java b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/TelemetryType.java deleted file mode 100644 index 8eea6f8daa9..00000000000 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/TelemetryType.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.microsoft.applicationinsights.internal.channel.samplingV2; - -public enum TelemetryType { - Dependency, - Event, - Exception, - PageView, - Request, - Trace; - - static TelemetryType valueOfOrNull(String name) { - try { - return valueOf(name); - } - catch (IllegalArgumentException e) { - return null; - } - } -} From 1a24b0a130e67e6a4fbd9deafde72efcb34f376a Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Thu, 3 May 2018 22:55:26 -0700 Subject: [PATCH 38/43] Revert "improving the way to locate agent and registering web app" This reverts commit bc19586a6b01cc338ce4bedeff3566a00868c9a8. --- .../common/CommonUtils.java | 54 +++++++------------ .../internal/WebRequestTrackingFilter.java | 29 ++++++---- 2 files changed, 40 insertions(+), 43 deletions(-) diff --git a/core/src/main/java/com/microsoft/applicationinsights/common/CommonUtils.java b/core/src/main/java/com/microsoft/applicationinsights/common/CommonUtils.java index 93dafbd5588..9e30be1607c 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/common/CommonUtils.java +++ b/core/src/main/java/com/microsoft/applicationinsights/common/CommonUtils.java @@ -22,44 +22,30 @@ package com.microsoft.applicationinsights.common; import com.microsoft.applicationinsights.internal.logger.InternalLogger; +import org.apache.commons.lang3.exception.ExceptionUtils; + import java.net.InetAddress; import java.net.UnknownHostException; -import org.apache.commons.lang3.exception.ExceptionUtils; -/** Created by oriy on 11/2/2016. */ -public class CommonUtils { - public static boolean isNullOrEmpty(String string) { - return string == null || string.length() == 0; - } - public static String getHostName() { - try { - InetAddress addr; - addr = InetAddress.getLocalHost(); - return addr.getCanonicalHostName(); - } catch (UnknownHostException ex) { - // optional parameter. do nothing if unresolvable - InternalLogger.INSTANCE.trace( - "Unresolvable host error. Stack trace generated is %s", ExceptionUtils.getStackTrace(ex)); - return null; +/** + * Created by oriy on 11/2/2016. + */ +public class CommonUtils { + public static boolean isNullOrEmpty(String string) { + return string == null || string.length() == 0; } - } - - /** - * This method is used to test if the given class is loaded in the specified ClassLoader - * @param classSignature Fully Qualified signature of class - * @param classLoader ClassLoader under consideration - * @return true if class is loaded otherwise false - */ - public static boolean isClassPresentOnClassPath(String classSignature, ClassLoader classLoader) { - - try { - Class.forName(classSignature, false, classLoader); - return true; - } catch (ClassNotFoundException e) { - InternalLogger.INSTANCE.info( - "Specified class %s is not present on the classpath", classSignature); - return false; + public static String getHostName(){ + try + { + InetAddress addr; + addr = InetAddress.getLocalHost(); + return addr.getCanonicalHostName(); + } + catch (UnknownHostException ex) { + // optional parameter. do nothing if unresolvable + InternalLogger.INSTANCE.trace("Unresolvable host error. Stack trace generated is %s", ExceptionUtils.getStackTrace(ex)); + return null; + } } - } } diff --git a/web/src/main/java/com/microsoft/applicationinsights/web/internal/WebRequestTrackingFilter.java b/web/src/main/java/com/microsoft/applicationinsights/web/internal/WebRequestTrackingFilter.java index 4b5a4877bfb..90eaa090384 100644 --- a/web/src/main/java/com/microsoft/applicationinsights/web/internal/WebRequestTrackingFilter.java +++ b/web/src/main/java/com/microsoft/applicationinsights/web/internal/WebRequestTrackingFilter.java @@ -62,8 +62,6 @@ public final class WebRequestTrackingFilter implements Filter { private boolean agentIsUp = false; private final LinkedList cleaners = new LinkedList(); private String appName; - private static final String AGENT_LOCATOR_INTERFACE_NAME = "com.microsoft.applicationinsights." - + "agent.internal.coresync.AgentNotificationsHandler"; // endregion Members @@ -232,20 +230,33 @@ public WebRequestTrackingFilter() { } private synchronized void initialize(FilterConfig filterConfig) { + try { - //If Agent Jar is not present in the class path skip the process - if (!CommonUtils.isClassPresentOnClassPath(AGENT_LOCATOR_INTERFACE_NAME, - this.getClass().getClassLoader())) { - InternalLogger.INSTANCE.info("Agent was not found. Skipping the agent registration"); - return; - } + //if agent is not installed (jar not loaded), can skip the entire registration process + try { + AgentConnector test = AgentConnector.INSTANCE; + } catch (ThreadDeath td) { + throw td; + } catch (Throwable t) { + try { + InternalLogger.INSTANCE.info("Agent was not found. Skipping the agent registration"); + return; + } catch (ThreadDeath td) { + throw td; + } catch (Throwable t2) { + // chomp + } + } - try { ServletContext context = filterConfig.getServletContext(); + String name = getName(context); + String key = registerWebApp(appName); setKey(key); + InternalLogger.INSTANCE.info("Successfully registered the filter '%s'", FILTER_NAME); + } catch (ThreadDeath td) { throw td; } catch (Throwable t) { From b9936e6468b447cccc8ba66a96c44ca37b4e5600 Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Sun, 13 May 2018 13:06:19 -0700 Subject: [PATCH 39/43] modularizing way to specify version number of starter, adding starter version number to HB telemetry --- .../build.gradle | 20 +++++++++++++++++- .../gradle.properties | 1 + .../SpringBootHeartBeatProvider.java | 21 ++++++++++++++++++- .../internal/util/PropertyHelper.java | 16 ++++++++++++++ 4 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 azure-application-insights-spring-boot-starter/gradle.properties diff --git a/azure-application-insights-spring-boot-starter/build.gradle b/azure-application-insights-spring-boot-starter/build.gradle index fb334683d66..b0ed36614ed 100644 --- a/azure-application-insights-spring-boot-starter/build.gradle +++ b/azure-application-insights-spring-boot-starter/build.gradle @@ -1,3 +1,5 @@ +import com.microsoft.applicationinsights.build.tasks.PropsFileGen + /* * ApplicationInsights-Java * Copyright (c) Microsoft Corporation @@ -23,7 +25,23 @@ apply from: "$buildScriptsDir/common-java.gradle" apply from: "$buildScriptsDir/publishing.gradle" archivesBaseName = 'applicationinsights-spring-boot-starter' -version = '1.0.0-BETA' +version = project.properties['spring.boot.starter.version-number'] + +def starterVersionFileDir = "$project.buildDir/src/generated/main/resources" +task generateVersionProperties(type: PropsFileGen) { + targetFile = new File(starterVersionFileDir, "starter-version.properties") + property "version", project.version +} + +processResources.dependsOn generateVersionProperties + +sourceSets { + main { + resources { + srcDir starterVersionFileDir + } + } +} dependencies { compile (project(':core')) diff --git a/azure-application-insights-spring-boot-starter/gradle.properties b/azure-application-insights-spring-boot-starter/gradle.properties new file mode 100644 index 00000000000..44fa15e3ccf --- /dev/null +++ b/azure-application-insights-spring-boot-starter/gradle.properties @@ -0,0 +1 @@ +spring.boot.starter.version-number=1.0.0-BETA \ No newline at end of file diff --git a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/HeartBeatProvider/SpringBootHeartBeatProvider.java b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/HeartBeatProvider/SpringBootHeartBeatProvider.java index 510e297f46a..feeb194440a 100644 --- a/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/HeartBeatProvider/SpringBootHeartBeatProvider.java +++ b/azure-application-insights-spring-boot-starter/src/main/java/com/microsoft/applicationinsights/boot/HeartBeatProvider/SpringBootHeartBeatProvider.java @@ -4,8 +4,10 @@ import com.microsoft.applicationinsights.internal.heartbeat.HeartBeatProviderInterface; import com.microsoft.applicationinsights.internal.heartbeat.MiscUtils; import com.microsoft.applicationinsights.internal.logger.InternalLogger; +import com.microsoft.applicationinsights.internal.util.PropertyHelper; import java.util.HashSet; import java.util.List; +import java.util.Properties; import java.util.Set; import java.util.concurrent.Callable; import org.apache.commons.lang3.exception.ExceptionUtils; @@ -40,6 +42,8 @@ public class SpringBootHeartBeatProvider implements HeartBeatPayloadProviderInte private final String SPRING_VERSION = "ai.spring.version"; + private final String SPRING_BOOT_STARTER_VERSION = "ai.spring.boot.starter.version"; + public SpringBootHeartBeatProvider(Environment environment) { @@ -79,6 +83,8 @@ public Boolean call() { provider.addHeartBeatProperty(fieldName, getSpringVersion(), true); hasSetValues = true; break; + case SPRING_BOOT_STARTER_VERSION: + provider.addHeartBeatProperty(fieldName, getSpringBootStarterVersionNumber(), true); default: //We won't accept unknown properties in default providers. InternalLogger.INSTANCE.trace("Encountered unknown default property"); @@ -102,6 +108,7 @@ public Boolean call() { private void initializeDefaultFields(Set defaultFields) { defaultFields.add(SPRING_BOOT_VERSION); defaultFields.add(SPRING_VERSION); + defaultFields.add(SPRING_BOOT_STARTER_VERSION); } /** @@ -114,10 +121,22 @@ private String getSpringBootVersion() { /** * Gets the Spring Framework version - * @return returns the SpringFrameWork version String + * @return the SpringFrameWork version String */ private String getSpringVersion() { return SpringVersion.getVersion(); } + /** + * Gets the AI SpringBoot starter version number + * @return the AI SpringBoot starter version number + */ + private String getSpringBootStarterVersionNumber() { + Properties starterVersionProperties = PropertyHelper.getStarterVersionProperties(); + if (starterVersionProperties != null) { + return starterVersionProperties.getProperty("version"); + } + return "undefined"; + } + } diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/util/PropertyHelper.java b/core/src/main/java/com/microsoft/applicationinsights/internal/util/PropertyHelper.java index 3d0dbc09031..62a49065178 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/util/PropertyHelper.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/util/PropertyHelper.java @@ -33,6 +33,7 @@ */ public final class PropertyHelper { public final static String SDK_VERSION_FILE_NAME = "sdk-version.properties"; + final static String STARTER_VERSION_FILE_NAME = "starter-version.properties"; /** * Reads the properties from a properties file. @@ -74,6 +75,21 @@ public static Properties getSdkVersionProperties() { return null; } + /** + * A method that loads the properties file that contains the AI SpringBootStarter version number + * @return The properties or null if not found. + */ + public static Properties getStarterVersionProperties() { + try { + return getProperties(STARTER_VERSION_FILE_NAME); + } + catch (IOException e) { + InternalLogger.INSTANCE.trace("Could not find starter version file: %s," + + "stack trace is: ", SDK_VERSION_FILE_NAME, ExceptionUtils.getStackTrace(e)); + } + return null; + } + private PropertyHelper() { } } From 58b902816a53e8888518ff19f2f9d56dc71b67ec Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Mon, 14 May 2018 15:07:31 -0700 Subject: [PATCH 40/43] reverting a file and fixing dual initialization --- .../initializer/SdkVersionContextInitializer.java | 4 +++- .../FixedRateSamplingTelemetryProcessor.java | 12 ------------ 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/com/microsoft/applicationinsights/extensibility/initializer/SdkVersionContextInitializer.java b/core/src/main/java/com/microsoft/applicationinsights/extensibility/initializer/SdkVersionContextInitializer.java index 152039997b8..c2cc91cd642 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/extensibility/initializer/SdkVersionContextInitializer.java +++ b/core/src/main/java/com/microsoft/applicationinsights/extensibility/initializer/SdkVersionContextInitializer.java @@ -21,9 +21,11 @@ package com.microsoft.applicationinsights.extensibility.initializer; -import com.microsoft.applicationinsights.extensibility.ContextInitializer; +import com.microsoft.applicationinsights.internal.logger.InternalLogger; import com.microsoft.applicationinsights.internal.util.PropertyHelper; import com.microsoft.applicationinsights.telemetry.TelemetryContext; +import com.microsoft.applicationinsights.extensibility.ContextInitializer; + import java.util.Properties; /** diff --git a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/FixedRateSamplingTelemetryProcessor.java b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/FixedRateSamplingTelemetryProcessor.java index dadec9f97b0..48bd2e87dd2 100644 --- a/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/FixedRateSamplingTelemetryProcessor.java +++ b/core/src/main/java/com/microsoft/applicationinsights/internal/channel/samplingV2/FixedRateSamplingTelemetryProcessor.java @@ -84,18 +84,6 @@ public FixedRateSamplingTelemetryProcessor() { this.samplingPercentage = DEFAULT_SAMPLING_PERCENTAGE; this.includedTypes = new HashSet<>(); this.excludedTypes = new HashSet<>(); - try { - this.allowedTypes = new HashMap() {{ - put(dependencyTelemetryName, com.microsoft.applicationinsights.telemetry.RemoteDependencyTelemetry.class); - put(eventTelemetryName, com.microsoft.applicationinsights.telemetry.EventTelemetry.class); - put(exceptionTelemetryName, com.microsoft.applicationinsights.telemetry.ExceptionTelemetry.class); - put(pageViewTelemetryName, com.microsoft.applicationinsights.telemetry.PageViewTelemetry.class); - put(requestTelemetryName, com.microsoft.applicationinsights.telemetry.RequestTelemetry.class); - put(traceTelemetryName, com.microsoft.applicationinsights.telemetry.TraceTelemetry.class); - }}; - } catch (Exception e) { - InternalLogger.INSTANCE.trace("Unable to locate telemetry classes. stack trace is %s", ExceptionUtils.getStackTrace(e)); - } } /** From 4a843ba477bfd7820e1090b8abdaacd0cb6eca1d Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Mon, 14 May 2018 18:07:58 -0700 Subject: [PATCH 41/43] adding the configuration parity tests --- ...icationInsightsStarterCoreParityTests.java | 75 +++++++++++++++++++ .../test/resources/ApplicationInsights.xml | 33 ++++++++ 2 files changed, 108 insertions(+) create mode 100644 azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsStarterCoreParityTests.java create mode 100644 azure-application-insights-spring-boot-starter/src/test/resources/ApplicationInsights.xml diff --git a/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsStarterCoreParityTests.java b/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsStarterCoreParityTests.java new file mode 100644 index 00000000000..cb74ddb5c0b --- /dev/null +++ b/azure-application-insights-spring-boot-starter/src/test/java/com/microsoft/applicationinsights/boot/ApplicationInsightsStarterCoreParityTests.java @@ -0,0 +1,75 @@ +package com.microsoft.applicationinsights.boot; + +import com.microsoft.applicationinsights.TelemetryClient; +import com.microsoft.applicationinsights.TelemetryConfiguration; +import com.microsoft.applicationinsights.internal.logger.InternalLogger; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@SpringBootTest( + properties = { + "spring.application.name: test-application", + "azure.application-insights.instrumentation-key: 00000000-0000-0000-0000-000000000000" + }, + classes = { + PropertyPlaceholderAutoConfiguration.class, + ApplicationInsightsTelemetryAutoConfiguration.class, + ApplicationInsightsWebMvcAutoConfiguration.class + } +) +@RunWith(SpringRunner.class) +public class ApplicationInsightsStarterCoreParityTests { + + //Instance from Spring Bean Factory + @Autowired + TelemetryClient telemetryClient; + + @Test + public void shouldHaveIdenticalConfiguration() throws Exception{ + Field field = telemetryClient.getClass().getDeclaredField("configuration"); + field.setAccessible(true); + TelemetryConfiguration config1 = (TelemetryConfiguration)field.get(telemetryClient); + + //needed for clearing down the active instance and get the new config. + tearDown(); + + //Instance created from XML config. + TelemetryClient t2 = new TelemetryClient(); + + Field field2 = t2.getClass().getDeclaredField("configuration"); + field2.setAccessible(true); + TelemetryConfiguration config2 = (TelemetryConfiguration)field2.get(t2); + + Assert.assertNotEquals(config1, config2); + //There is one additional TelemetryInitializer in case of SpringBoot(For Cloud_RoleName) + Assert.assertEquals(config1.getTelemetryInitializers().size(), config2.getTelemetryInitializers().size() + 1); + Assert.assertEquals(config1.getTelemetryModules().size(), config2.getTelemetryModules().size()); + Assert.assertEquals(config1.getContextInitializers().size(), config2.getContextInitializers().size()); + Assert.assertEquals(config1.getTelemetryProcessors().size(), config2.getTelemetryProcessors().size()); + Assert.assertEquals(config1.getInstrumentationKey(), config2.getInstrumentationKey()); + Assert.assertEquals(config1.isTrackingDisabled(), config2.isTrackingDisabled()); + } + + @AfterClass + public static void tearDown() throws Exception { + Method method = TelemetryConfiguration.class.getDeclaredMethod("setActiveAsNull"); + method.setAccessible(true); + method.invoke(null); + + //InternalLogger needs to be shutdown + Field field = InternalLogger.class.getDeclaredField("initialized"); + field.setAccessible(true); + field.set(InternalLogger.INSTANCE, false); + System.out.println("Exiting core parity tests"); + } + + +} diff --git a/azure-application-insights-spring-boot-starter/src/test/resources/ApplicationInsights.xml b/azure-application-insights-spring-boot-starter/src/test/resources/ApplicationInsights.xml new file mode 100644 index 00000000000..5c85a0210c7 --- /dev/null +++ b/azure-application-insights-spring-boot-starter/src/test/resources/ApplicationInsights.xml @@ -0,0 +1,33 @@ + + + + + + + 00000000-0000-0000-0000-000000000000 + + + true + JavaSDKLog + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From abba801f2a1f33a7f07eea271de83d22056bd7a0 Mon Sep 17 00:00:00 2001 From: dhaval24 Date: Wed, 16 May 2018 16:11:53 -0700 Subject: [PATCH 42/43] updating readme with migration steps --- .../README.md | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/azure-application-insights-spring-boot-starter/README.md b/azure-application-insights-spring-boot-starter/README.md index 38268f18506..72bd7a6b218 100644 --- a/azure-application-insights-spring-boot-starter/README.md +++ b/azure-application-insights-spring-boot-starter/README.md @@ -129,6 +129,9 @@ azure.application-insights.logger.type=console # Logging level [all, trace, info, warn, error, off]. Default value: error. azure.application-insights.logger.level=error +# Enable/Disable QuickPulse (Live Metrics). Default value: True +azure.application-insights.quick-pulse.enabled=true + # Enable/Disable developer mode, all telemetry will be sent immediately without batching. Significantly affects performance and should be used only in developer environment. Default value: false. azure.application-insights.channel.in-process.developer-mode=false # Endpoint address, Default value: https://dc.services.visualstudio.com/v2/track. @@ -170,13 +173,29 @@ azure.application-insights.heart-beat.heart-beat-interval=900 #If set of properties are specified they would be excluded from Heartbeat payload azure.application-insights.heart-beat.excluded-heart-beat-properties-list= #If set of HeartBeat providers are specified they would be excluded -azure.application-insights.heart-beat.excluded-heart-beat-provider-list +azure.application-insights.heart-beat.excluded-heart-beat-provider-list= ``` -###Completely disable Application Insights using `application.properties` +### Completely disable Application Insights using `application.properties` ```properties azure.application-insights.enabled=false azure.application-insights.web.enabled=false ``` Note: Do not configure `azure.application-insights.instrumentation-key` property for optimal performance and avoiding any Application Insights beans creation by Spring. + + +## Migrating from XML based configuration ## +1. Please remove ApplicationInsights.xml file from the project resources or class path. +2. Add applicationinsights-spring-boot-starter-.jar file to pom.xml or build.gradle (you do not need to specify applicationinsights-core and web jars independently). + The starter takes are of it for you. +3. Please configure springboot Application.properties file with Application Insights Instrumentation key. +4. Compile the project and execute it from your IDE or command line using java -jar applicationjarname +5. To specify AI properties using command line please refer to SpringBoot Documentation. +6. To use [ApplicationInsigts Java agent](https://docs.microsoft.com/en-us/azure/application-insights/app-insights-java-agent) please follow official documentation +4. To get an initialized instance of TelemetryClient please use Spring autowired annotation. This will provide a fully initialized instance of TelemetryClient. + +```Java +@Autowired +TelemetryClient client; +``` \ No newline at end of file From 0f6735600a2aebae3fcd3a39b157867055916872 Mon Sep 17 00:00:00 2001 From: Dhaval Doshi Date: Wed, 16 May 2018 16:23:37 -0700 Subject: [PATCH 43/43] Smoke Tests for SpringBoot Application using SpringBoot AI Starter (#665) * smoke test for SpringBoot * smoke test app springboot * trying java 7 * trying source and target compatibility * fixing assert * enabling the temporarily disbabled smoke tests * Reverting temporary adjustments --- settings.gradle | 3 ++ test/smoke/build.gradle | 1 + .../smoketest/AiSmokeTest.java | 1 + .../testApps/SpringBootTest/build.gradle | 32 +++++++++++++++ .../src/main/java/com/SpringBootApp.java | 18 +++++++++ .../controller/TestController.java | 39 +++++++++++++++++++ .../src/main/resources/application.properties | 5 +++ .../smoketest/SpringbootSmokeTest.java | 37 ++++++++++++++++++ .../src/smokeTest/resources/appServers.txt | 1 + 9 files changed, 137 insertions(+) create mode 100644 test/smoke/testApps/SpringBootTest/build.gradle create mode 100644 test/smoke/testApps/SpringBootTest/src/main/java/com/SpringBootApp.java create mode 100644 test/smoke/testApps/SpringBootTest/src/main/java/com/springbootstartertest/controller/TestController.java create mode 100644 test/smoke/testApps/SpringBootTest/src/main/resources/application.properties create mode 100644 test/smoke/testApps/SpringBootTest/src/smokeTest/java/com/springbootstartertest/smoketest/SpringbootSmokeTest.java create mode 100644 test/smoke/testApps/SpringBootTest/src/smokeTest/resources/appServers.txt diff --git a/settings.gradle b/settings.gradle index e691ff3d666..3645ec1c991 100644 --- a/settings.gradle +++ b/settings.gradle @@ -60,3 +60,6 @@ if (System.env.'COLLECTD_HOME') { include 'collectd' } +include ':test:smoke:testApps:SpringBootTest' + + diff --git a/test/smoke/build.gradle b/test/smoke/build.gradle index d565b81acd4..7c4f4a0cec6 100644 --- a/test/smoke/build.gradle +++ b/test/smoke/build.gradle @@ -22,6 +22,7 @@ subprojects { aiLog4j1_2Jar = project(':logging:log4j1_2') aiLo4j2Jar = project(':logging:log4j2') aiLogbackJar = project(':logging:logback') + springBootStarterJar = project(':azure-application-insights-spring-boot-starter') } } diff --git a/test/smoke/framework/testCore/src/main/java/com/microsoft/applicationinsights/smoketest/AiSmokeTest.java b/test/smoke/framework/testCore/src/main/java/com/microsoft/applicationinsights/smoketest/AiSmokeTest.java index 1e43b88f172..e75ae5fe2c3 100644 --- a/test/smoke/framework/testCore/src/main/java/com/microsoft/applicationinsights/smoketest/AiSmokeTest.java +++ b/test/smoke/framework/testCore/src/main/java/com/microsoft/applicationinsights/smoketest/AiSmokeTest.java @@ -310,6 +310,7 @@ protected void callTargetUriAndWaitForTelemetry() throws Exception { } System.out.println("Calling "+targetUri+" ..."); String url = getBaseUrl()+targetUri; + System.out.println("calling " + url); final String content; switch(httpMethod) { case "GET": diff --git a/test/smoke/testApps/SpringBootTest/build.gradle b/test/smoke/testApps/SpringBootTest/build.gradle new file mode 100644 index 00000000000..6ad8a668e7f --- /dev/null +++ b/test/smoke/testApps/SpringBootTest/build.gradle @@ -0,0 +1,32 @@ +apply plugin: 'war' + +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath 'org.springframework.boot:spring-boot-gradle-plugin:1.5.9.RELEASE' + } +} + +apply plugin: 'org.springframework.boot' + +compileJava.sourceCompatibility = 1.7 +compileJava.targetCompatibility = 1.7 +compileSmokeTestJava.sourceCompatibility = 1.8 +compileSmokeTestJava.targetCompatibility = 1.8 + +dependencies { + compile springBootStarterJar + compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '1.5.9.RELEASE' + compile group: 'org.springframework.boot', name: 'spring-boot-starter-tomcat', version: '1.5.9.RELEASE' + testCompile group: 'junit', name: 'junit', version: '4.12' +} + +configurations { + smokeTestCompile.exclude group:'org.springframework.boot' + smokeTestRuntime.exclude group:'org.springframework.boot' +} + +ext.testAppArtifactDir = war.destinationDir +ext.testAppArtifactFilename = war.archiveName \ No newline at end of file diff --git a/test/smoke/testApps/SpringBootTest/src/main/java/com/SpringBootApp.java b/test/smoke/testApps/SpringBootTest/src/main/java/com/SpringBootApp.java new file mode 100644 index 00000000000..2e1dd842b30 --- /dev/null +++ b/test/smoke/testApps/SpringBootTest/src/main/java/com/SpringBootApp.java @@ -0,0 +1,18 @@ +package com; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.support.SpringBootServletInitializer; + +@SpringBootApplication +public class SpringBootApp extends SpringBootServletInitializer { + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder applicationBuilder) { + return applicationBuilder.sources(SpringBootApp.class); + } + public static void main(String[] args) { + SpringApplication.run(SpringBootApp.class, args); + } +} diff --git a/test/smoke/testApps/SpringBootTest/src/main/java/com/springbootstartertest/controller/TestController.java b/test/smoke/testApps/SpringBootTest/src/main/java/com/springbootstartertest/controller/TestController.java new file mode 100644 index 00000000000..db0efc0555e --- /dev/null +++ b/test/smoke/testApps/SpringBootTest/src/main/java/com/springbootstartertest/controller/TestController.java @@ -0,0 +1,39 @@ +package com.springbootstartertest.controller; + +import com.microsoft.applicationinsights.TelemetryClient; +import java.util.HashMap; +import java.util.Map; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class TestController { + + @Autowired + TelemetryClient client; + + @GetMapping("/") + public String rootPage() { + return "OK"; + } + + @GetMapping("/basic/trackEvent") + public String trackEventSpringBoot() { + Map properties = new HashMap() { + { + put("key", "value"); + } + }; + Map metrics = new HashMap() { + { + put("key", 1d); + } + }; + + //Event + client.trackEvent("EventDataTest"); + client.trackEvent("EventDataPropertyTest", properties, metrics); + return "hello"; + } +} diff --git a/test/smoke/testApps/SpringBootTest/src/main/resources/application.properties b/test/smoke/testApps/SpringBootTest/src/main/resources/application.properties new file mode 100644 index 00000000000..741e0983b10 --- /dev/null +++ b/test/smoke/testApps/SpringBootTest/src/main/resources/application.properties @@ -0,0 +1,5 @@ +spring.application.name=SpringBootTest +azure.application-insights.channel.in-process.endpoint-address=http://fakeingestion:60606/v2/track +azure.application-insights.instrumentation-key=00000000-0000-0000-0000-cba987654321 +azure.application-insights.logger.level=TRACE +azure.application-insights.default-modules.ProcessPerformanceCountersModule.enabled=false diff --git a/test/smoke/testApps/SpringBootTest/src/smokeTest/java/com/springbootstartertest/smoketest/SpringbootSmokeTest.java b/test/smoke/testApps/SpringBootTest/src/smokeTest/java/com/springbootstartertest/smoketest/SpringbootSmokeTest.java new file mode 100644 index 00000000000..872cedfaf28 --- /dev/null +++ b/test/smoke/testApps/SpringBootTest/src/smokeTest/java/com/springbootstartertest/smoketest/SpringbootSmokeTest.java @@ -0,0 +1,37 @@ +package com.springbootstartertest.smoketest; + +import static org.junit.Assert.assertEquals; + +import com.microsoft.applicationinsights.internal.schemav2.EventData; +import com.microsoft.applicationinsights.smoketest.AiSmokeTest; +import com.microsoft.applicationinsights.smoketest.TargetUri; +import org.junit.Test; + +public class SpringbootSmokeTest extends AiSmokeTest{ + + @Test + @TargetUri("/basic/trackEvent") + public void trackEvent() throws Exception { + assertEquals(1, mockedIngestion.getCountForType("RequestData")); + assertEquals(2, mockedIngestion.getCountForType("EventData")); + int totalItems = mockedIngestion.getItemCount(); + int expectedItems = 3; + assertEquals(String.format("There were %d extra telemetry items received.", expectedItems - totalItems), + expectedItems, totalItems); + + // TODO get event data envelope and verify value + EventData d = getTelemetryDataForType(0, "EventData"); + final String name = "EventDataTest"; + assertEquals(name, d.getName()); + + EventData d2 = getTelemetryDataForType(1, "EventData"); + + final String expectedName = "EventDataPropertyTest"; + final String expectedProperties = "value"; + final Double expectedMetric = 1d; + + assertEquals(expectedName, d2.getName()); + assertEquals(expectedProperties, d2.getProperties().get("key")); + assertEquals(expectedMetric, d2.getMeasurements().get("key")); + } +} diff --git a/test/smoke/testApps/SpringBootTest/src/smokeTest/resources/appServers.txt b/test/smoke/testApps/SpringBootTest/src/smokeTest/resources/appServers.txt new file mode 100644 index 00000000000..ec0fa258a85 --- /dev/null +++ b/test/smoke/testApps/SpringBootTest/src/smokeTest/resources/appServers.txt @@ -0,0 +1 @@ +tomcat8 \ No newline at end of file