diff --git a/custom/src/main/java/com/solarwinds/opentelemetry/extensions/SolarwindsAgentListener.java b/custom/src/main/java/com/solarwinds/opentelemetry/extensions/SolarwindsAgentListener.java index 2b869eef..3b83921a 100644 --- a/custom/src/main/java/com/solarwinds/opentelemetry/extensions/SolarwindsAgentListener.java +++ b/custom/src/main/java/com/solarwinds/opentelemetry/extensions/SolarwindsAgentListener.java @@ -20,24 +20,19 @@ import static com.solarwinds.opentelemetry.extensions.config.provider.AutoConfigurationCustomizerProviderImpl.setAgentEnabled; import com.google.auto.service.AutoService; -import com.solarwinds.joboe.config.ConfigGroup; import com.solarwinds.joboe.config.ConfigManager; import com.solarwinds.joboe.config.ConfigProperty; -import com.solarwinds.joboe.config.InvalidConfigException; +import com.solarwinds.joboe.config.JavaRuntimeVersionChecker; import com.solarwinds.joboe.core.ReporterFactory; import com.solarwinds.joboe.core.profiler.Profiler; import com.solarwinds.joboe.core.profiler.ProfilerSetting; -import com.solarwinds.joboe.core.rpc.ClientException; import com.solarwinds.joboe.core.rpc.ClientManagerProvider; import com.solarwinds.joboe.core.rpc.RpcClientManager; import com.solarwinds.joboe.core.util.DaemonThreadFactory; import com.solarwinds.joboe.core.util.HostInfoUtils; import com.solarwinds.joboe.logging.Logger; import com.solarwinds.joboe.logging.LoggerFactory; -import com.solarwinds.joboe.metrics.MetricsCollector; -import com.solarwinds.joboe.metrics.MetricsMonitor; import com.solarwinds.joboe.metrics.SystemMonitorController; -import com.solarwinds.joboe.metrics.SystemMonitorFactoryImpl; import com.solarwinds.joboe.sampling.SettingsManager; import com.solarwinds.opentelemetry.core.AgentState; import com.solarwinds.opentelemetry.extensions.config.HttpSettingsFetcher; @@ -117,29 +112,11 @@ private void executeStartupTasks() { SamplingConfigProvider.getSamplingConfiguration()); logger.debug("Initialized HostUtils"); - logger.info("Starting System monitor"); - SystemMonitorController.startWithBuilder( - () -> - new SystemMonitorFactoryImpl( - ConfigManager.getConfigs(ConfigGroup.MONITOR)) { - @Override - protected MetricsMonitor buildMetricsMonitor() { - try { - MetricsCollector metricsCollector = - new MetricsCollector(configs, null); - - return MetricsMonitor.buildInstance(configs, metricsCollector); - } catch (InvalidConfigException | ClientException e) { - logger.debug(String.format("Error creating MetricsCollector: %s", e)); - } - return null; - } - }.buildMonitors()); - logger.debug("Started System monitor"); - ProfilerSetting profilerSetting = (ProfilerSetting) ConfigManager.getConfig(ConfigProperty.PROFILER); - if (profilerSetting != null && profilerSetting.isEnabled()) { + if (JavaRuntimeVersionChecker.isJdkVersionSupported() + && profilerSetting != null + && profilerSetting.isEnabled()) { logger.debug("Profiler is enabled, local settings : " + profilerSetting); Profiler.initialize( profilerSetting, @@ -148,7 +125,7 @@ protected MetricsMonitor buildMetricsMonitor() { RpcClientManager.getClient( RpcClientManager.OperationType.PROFILING))); } else { - logger.debug("Profiler is disabled, local settings : " + profilerSetting); + logger.info("Profiler is disabled, local settings : " + profilerSetting); } // now wait for all the latches (for now there's only one for settings) diff --git a/custom/src/main/java/com/solarwinds/opentelemetry/extensions/SolarwindsTracerProviderCustomizer.java b/custom/src/main/java/com/solarwinds/opentelemetry/extensions/SolarwindsTracerProviderCustomizer.java index 7a4645a3..b7931a3a 100644 --- a/custom/src/main/java/com/solarwinds/opentelemetry/extensions/SolarwindsTracerProviderCustomizer.java +++ b/custom/src/main/java/com/solarwinds/opentelemetry/extensions/SolarwindsTracerProviderCustomizer.java @@ -18,6 +18,7 @@ import static com.solarwinds.opentelemetry.extensions.config.provider.AutoConfigurationCustomizerProviderImpl.isAgentEnabled; +import com.solarwinds.joboe.config.JavaRuntimeVersionChecker; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder; import java.util.function.BiFunction; @@ -29,9 +30,12 @@ public class SolarwindsTracerProviderCustomizer public SdkTracerProviderBuilder apply( SdkTracerProviderBuilder tracerProvider, ConfigProperties config) { if (isAgentEnabled()) { + if (JavaRuntimeVersionChecker.isJdkVersionSupported()) { + tracerProvider.addSpanProcessor(new SolarwindsProfilingSpanProcessor()); + } + tracerProvider .setSampler(new SolarwindsSampler()) - .addSpanProcessor(new SolarwindsProfilingSpanProcessor()) .addSpanProcessor(new InboundMeasurementMetricsGenerator()); } diff --git a/custom/src/main/java/com/solarwinds/opentelemetry/extensions/config/DeclarativeLoader.java b/custom/src/main/java/com/solarwinds/opentelemetry/extensions/config/DeclarativeLoader.java index 3e8d36ee..0b522e66 100644 --- a/custom/src/main/java/com/solarwinds/opentelemetry/extensions/config/DeclarativeLoader.java +++ b/custom/src/main/java/com/solarwinds/opentelemetry/extensions/config/DeclarativeLoader.java @@ -41,10 +41,9 @@ public void beforeAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemet AutoConfigureUtil.getConfigProvider(autoConfiguredOpenTelemetrySdk); if (configProvider != null) { - boolean jdkVersionSupported = JavaRuntimeVersionChecker.isJdkVersionSupported(); DeclarativeConfigProperties instrumentationConfig = configProvider.getInstrumentationConfig(); - if (instrumentationConfig != null && jdkVersionSupported) { + if (instrumentationConfig != null) { DeclarativeConfigProperties solarwinds = instrumentationConfig .getStructured("java", DeclarativeConfigProperties.empty()) @@ -64,13 +63,11 @@ public void beforeAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemet } } - if (!jdkVersionSupported) { + if (!JavaRuntimeVersionChecker.isJdkVersionSupported()) { logger.warn( String.format( - "Unsupported Java runtime version: %s. The lowest Java version supported is %s.", + "Profiling is not supported for Java runtime version: %s . The lowest Java version supported for profiling is %s.", System.getProperty("java.version"), JavaRuntimeVersionChecker.minVersionSupported)); - - logger.warn("Solarwinds' extension is disabled"); } } } diff --git a/custom/src/main/java/com/solarwinds/opentelemetry/extensions/config/provider/AutoConfigurationCustomizerProviderImpl.java b/custom/src/main/java/com/solarwinds/opentelemetry/extensions/config/provider/AutoConfigurationCustomizerProviderImpl.java index 855568bb..d1448d0b 100644 --- a/custom/src/main/java/com/solarwinds/opentelemetry/extensions/config/provider/AutoConfigurationCustomizerProviderImpl.java +++ b/custom/src/main/java/com/solarwinds/opentelemetry/extensions/config/provider/AutoConfigurationCustomizerProviderImpl.java @@ -56,14 +56,12 @@ public static void setAgentEnabled(boolean agentEnabled) { @Override public void customize(@Nonnull AutoConfigurationCustomizer autoConfiguration) { try { - agentEnabled = JavaRuntimeVersionChecker.isJdkVersionSupported(); - if (agentEnabled) { - ConfigurationLoader.load(); - logger.debug("Loaded via normal config"); - } else { + ConfigurationLoader.load(); + logger.debug("Loaded via normal config"); + if (!JavaRuntimeVersionChecker.isJdkVersionSupported()) { logger.warn( String.format( - "Unsupported Java runtime version: %s. The lowest Java version supported is %s.", + "Profiling is not supported for Java runtime version: %s . The lowest Java version supported for profiling is %s.", System.getProperty("java.version"), JavaRuntimeVersionChecker.minVersionSupported)); } diff --git a/custom/src/main/java/com/solarwinds/opentelemetry/extensions/config/provider/CustomConfigCustomizerProvider.java b/custom/src/main/java/com/solarwinds/opentelemetry/extensions/config/provider/CustomConfigCustomizerProvider.java index 6098a3b9..02f84a50 100644 --- a/custom/src/main/java/com/solarwinds/opentelemetry/extensions/config/provider/CustomConfigCustomizerProvider.java +++ b/custom/src/main/java/com/solarwinds/opentelemetry/extensions/config/provider/CustomConfigCustomizerProvider.java @@ -17,6 +17,7 @@ package com.solarwinds.opentelemetry.extensions.config.provider; import com.google.auto.service.AutoService; +import com.solarwinds.joboe.config.JavaRuntimeVersionChecker; import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizer; import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalResourceDetectionModel; @@ -80,15 +81,17 @@ private void addResourceDetector(ResourceModel resourceModel) { } private void addProcessors(TracerProviderModel model) { - List processors = - Collections.singletonList( - new SpanProcessorModel() - .withAdditionalProperty( - ProfilingSpanProcessorComponentProvider.COMPONENT_NAME, - Collections.emptyMap())); + if (JavaRuntimeVersionChecker.isJdkVersionSupported()) { + List processors = + Collections.singletonList( + new SpanProcessorModel() + .withAdditionalProperty( + ProfilingSpanProcessorComponentProvider.COMPONENT_NAME, + Collections.emptyMap())); - ArrayList allProcessors = new ArrayList<>(model.getProcessors()); - allProcessors.addAll(processors); - model.withProcessors(allProcessors); + ArrayList allProcessors = new ArrayList<>(model.getProcessors()); + allProcessors.addAll(processors); + model.withProcessors(allProcessors); + } } } diff --git a/custom/src/test/java/com/solarwinds/opentelemetry/extensions/SolarwindsTracerProviderCustomizerTest.java b/custom/src/test/java/com/solarwinds/opentelemetry/extensions/SolarwindsTracerProviderCustomizerTest.java new file mode 100644 index 00000000..47c93314 --- /dev/null +++ b/custom/src/test/java/com/solarwinds/opentelemetry/extensions/SolarwindsTracerProviderCustomizerTest.java @@ -0,0 +1,127 @@ +/* + * © SolarWinds Worldwide, LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.solarwinds.opentelemetry.extensions; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.solarwinds.joboe.config.JavaRuntimeVersionChecker; +import com.solarwinds.opentelemetry.extensions.config.provider.AutoConfigurationCustomizerProviderImpl; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder; +import io.opentelemetry.sdk.trace.SpanProcessor; +import io.opentelemetry.sdk.trace.samplers.Sampler; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class SolarwindsTracerProviderCustomizerTest { + + @InjectMocks private SolarwindsTracerProviderCustomizer tested; + + @Mock private SdkTracerProviderBuilder tracerProviderBuilderMock; + + @Mock private ConfigProperties configPropertiesMock; + + private MockedStatic + autoConfigurationCustomizerProviderImplMockedStatic; + + @BeforeEach + void setUp() { + autoConfigurationCustomizerProviderImplMockedStatic = + mockStatic(AutoConfigurationCustomizerProviderImpl.class); + } + + @AfterEach + void tearDown() { + autoConfigurationCustomizerProviderImplMockedStatic.close(); + } + + @Test + void verifyThatProfilingSpanProcessorIsAddedWhenAgentEnabledAndJdkVersionSupported() { + try (MockedStatic javaRuntimeVersionCheckerMockedStatic = + mockStatic(JavaRuntimeVersionChecker.class)) { + + autoConfigurationCustomizerProviderImplMockedStatic + .when(AutoConfigurationCustomizerProviderImpl::isAgentEnabled) + .thenReturn(true); + + javaRuntimeVersionCheckerMockedStatic + .when(JavaRuntimeVersionChecker::isJdkVersionSupported) + .thenReturn(true); + + when(tracerProviderBuilderMock.addSpanProcessor(any(SpanProcessor.class))) + .thenReturn(tracerProviderBuilderMock); + when(tracerProviderBuilderMock.setSampler(any(Sampler.class))) + .thenReturn(tracerProviderBuilderMock); + + tested.apply(tracerProviderBuilderMock, configPropertiesMock); + + // Should add SolarwindsProfilingSpanProcessor and InboundMeasurementMetricsGenerator + verify(tracerProviderBuilderMock, times(2)).addSpanProcessor(any(SpanProcessor.class)); + verify(tracerProviderBuilderMock).setSampler(any(Sampler.class)); + } + } + + @Test + void verifyThatProfilingSpanProcessorIsNotAddedWhenJdkVersionNotSupported() { + try (MockedStatic javaRuntimeVersionCheckerMockedStatic = + mockStatic(JavaRuntimeVersionChecker.class)) { + + autoConfigurationCustomizerProviderImplMockedStatic + .when(AutoConfigurationCustomizerProviderImpl::isAgentEnabled) + .thenReturn(true); + + javaRuntimeVersionCheckerMockedStatic + .when(JavaRuntimeVersionChecker::isJdkVersionSupported) + .thenReturn(false); + + when(tracerProviderBuilderMock.addSpanProcessor(any(SpanProcessor.class))) + .thenReturn(tracerProviderBuilderMock); + when(tracerProviderBuilderMock.setSampler(any(Sampler.class))) + .thenReturn(tracerProviderBuilderMock); + + tested.apply(tracerProviderBuilderMock, configPropertiesMock); + + // Should only add InboundMeasurementMetricsGenerator, not SolarwindsProfilingSpanProcessor + verify(tracerProviderBuilderMock, times(1)).addSpanProcessor(any(SpanProcessor.class)); + verify(tracerProviderBuilderMock).setSampler(any(Sampler.class)); + } + } + + @Test + void verifyThatNoProcessorsAddedWhenAgentDisabled() { + autoConfigurationCustomizerProviderImplMockedStatic + .when(AutoConfigurationCustomizerProviderImpl::isAgentEnabled) + .thenReturn(false); + + tested.apply(tracerProviderBuilderMock, configPropertiesMock); + + verify(tracerProviderBuilderMock, never()).addSpanProcessor(any(SpanProcessor.class)); + verify(tracerProviderBuilderMock, never()).setSampler(any(Sampler.class)); + } +} diff --git a/custom/src/test/java/com/solarwinds/opentelemetry/extensions/config/provider/CustomConfigCustomizerProviderTest.java b/custom/src/test/java/com/solarwinds/opentelemetry/extensions/config/provider/CustomConfigCustomizerProviderTest.java index 42bf71ea..af2b007c 100644 --- a/custom/src/test/java/com/solarwinds/opentelemetry/extensions/config/provider/CustomConfigCustomizerProviderTest.java +++ b/custom/src/test/java/com/solarwinds/opentelemetry/extensions/config/provider/CustomConfigCustomizerProviderTest.java @@ -16,9 +16,13 @@ package com.solarwinds.opentelemetry.extensions.config.provider; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mockStatic; +import com.solarwinds.joboe.config.JavaRuntimeVersionChecker; import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizer; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanProcessorModel; @@ -31,6 +35,7 @@ import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.MockedStatic; import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) @@ -45,25 +50,87 @@ class CustomConfigCustomizerProviderTest { functionArgumentCaptor; @Test - void testCustomize() { - OpenTelemetryConfigurationModel openTelemetryConfigurationModel = - new OpenTelemetryConfigurationModel(); - - doNothing() - .when(declarativeConfigurationCustomizerMock) - .addModelCustomizer(functionArgumentCaptor.capture()); - - tested.customize(declarativeConfigurationCustomizerMock); - functionArgumentCaptor.getValue().apply(openTelemetryConfigurationModel); - - TracerProviderModel tracerProvider = openTelemetryConfigurationModel.getTracerProvider(); - assertNotNull(tracerProvider); - - List processors = tracerProvider.getProcessors(); - assertNotNull( - processors - .get(0) - .getAdditionalProperties() - .get(ProfilingSpanProcessorComponentProvider.COMPONENT_NAME)); + void verifyThatProfilingProcessorIsAddedWhenJdkVersionIsSupported() { + try (MockedStatic javaRuntimeVersionCheckerMockedStatic = + mockStatic(JavaRuntimeVersionChecker.class)) { + javaRuntimeVersionCheckerMockedStatic + .when(JavaRuntimeVersionChecker::isJdkVersionSupported) + .thenReturn(true); + + OpenTelemetryConfigurationModel openTelemetryConfigurationModel = + new OpenTelemetryConfigurationModel(); + + doNothing() + .when(declarativeConfigurationCustomizerMock) + .addModelCustomizer(functionArgumentCaptor.capture()); + + tested.customize(declarativeConfigurationCustomizerMock); + functionArgumentCaptor.getValue().apply(openTelemetryConfigurationModel); + + TracerProviderModel tracerProvider = openTelemetryConfigurationModel.getTracerProvider(); + assertNotNull(tracerProvider); + + List processors = tracerProvider.getProcessors(); + assertNotNull( + processors + .get(0) + .getAdditionalProperties() + .get(ProfilingSpanProcessorComponentProvider.COMPONENT_NAME)); + } + } + + @Test + void verifyThatProfilingProcessorIsNotAddedWhenJdkVersionIsNotSupported() { + try (MockedStatic javaRuntimeVersionCheckerMockedStatic = + mockStatic(JavaRuntimeVersionChecker.class)) { + javaRuntimeVersionCheckerMockedStatic + .when(JavaRuntimeVersionChecker::isJdkVersionSupported) + .thenReturn(false); + + OpenTelemetryConfigurationModel openTelemetryConfigurationModel = + new OpenTelemetryConfigurationModel(); + + doNothing() + .when(declarativeConfigurationCustomizerMock) + .addModelCustomizer(functionArgumentCaptor.capture()); + + tested.customize(declarativeConfigurationCustomizerMock); + functionArgumentCaptor.getValue().apply(openTelemetryConfigurationModel); + + TracerProviderModel tracerProvider = openTelemetryConfigurationModel.getTracerProvider(); + assertNotNull(tracerProvider); + + List processors = tracerProvider.getProcessors(); + assertTrue(processors.isEmpty()); + } + } + + @Test + void verifyThatResourceDetectorIsAlwaysAdded() { + try (MockedStatic javaRuntimeVersionCheckerMockedStatic = + mockStatic(JavaRuntimeVersionChecker.class)) { + javaRuntimeVersionCheckerMockedStatic + .when(JavaRuntimeVersionChecker::isJdkVersionSupported) + .thenReturn(false); + + OpenTelemetryConfigurationModel openTelemetryConfigurationModel = + new OpenTelemetryConfigurationModel(); + + doNothing() + .when(declarativeConfigurationCustomizerMock) + .addModelCustomizer(functionArgumentCaptor.capture()); + + tested.customize(declarativeConfigurationCustomizerMock); + functionArgumentCaptor.getValue().apply(openTelemetryConfigurationModel); + + assertNotNull(openTelemetryConfigurationModel.getResource()); + assertNotNull(openTelemetryConfigurationModel.getResource().getDetectionDevelopment()); + assertFalse( + openTelemetryConfigurationModel + .getResource() + .getDetectionDevelopment() + .getDetectors() + .isEmpty()); + } } } diff --git a/custom/src/test/java/com/solarwinds/opentelemetry/extensions/provider/AutoConfigurationCustomizerProviderImplTest.java b/custom/src/test/java/com/solarwinds/opentelemetry/extensions/provider/AutoConfigurationCustomizerProviderImplTest.java index fb1d6ef6..5e31b7a5 100644 --- a/custom/src/test/java/com/solarwinds/opentelemetry/extensions/provider/AutoConfigurationCustomizerProviderImplTest.java +++ b/custom/src/test/java/com/solarwinds/opentelemetry/extensions/provider/AutoConfigurationCustomizerProviderImplTest.java @@ -25,6 +25,10 @@ import com.solarwinds.opentelemetry.extensions.config.provider.AutoConfigurationCustomizerProviderImpl; import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Field; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -34,10 +38,28 @@ @ExtendWith(MockitoExtension.class) class AutoConfigurationCustomizerProviderImplTest { + private static final MethodHandle AGENT_ENABLED_SETTER; + + static { + try { + Field field = AutoConfigurationCustomizerProviderImpl.class.getDeclaredField("agentEnabled"); + field.setAccessible(true); + AGENT_ENABLED_SETTER = MethodHandles.lookup().unreflectSetter(field); + } catch (ReflectiveOperationException e) { + throw new ExceptionInInitializerError(e); + } + } + @InjectMocks private AutoConfigurationCustomizerProviderImpl tested; @Mock private AutoConfigurationCustomizer autoConfigurationCustomizerMock; + @AfterEach + void teardown() throws Throwable { + // Reset the static agentEnabled field to true so it doesn't affect other tests + AGENT_ENABLED_SETTER.invokeExact(true); + } + @Test void verifyThatWhenDisabledItIsNeverEnabled() { AutoConfigurationCustomizerProviderImpl.setAgentEnabled(false);