From bf446976123f26eea3587a517cc817068733f50b Mon Sep 17 00:00:00 2001 From: robsunday Date: Tue, 7 Jul 2026 12:21:54 +0200 Subject: [PATCH 1/4] Snapshot Profiler Configuration refactoring --- ...DeclarativeEffectiveConfigFileFactory.java | 3 +- .../EnvVarsEffectiveConfigFileFactory.java | 3 +- ...arativeEffectiveConfigFileFactoryTest.java | 8 +- ...EnvVarsEffectiveConfigFileFactoryTest.java | 5 + .../SnapshotProfilingConfiguration.java | 189 ++++++++++++++++-- ...filingConfigurationCustomizerProvider.java | 11 +- ...shotProfilingDeclarativeConfiguration.java | 104 ---------- ...filingDeclarativeConfigurationFactory.java | 75 +++++++ ...SnapshotProfilingEnvVarsConfiguration.java | 114 ----------- ...tProfilingEnvVarsConfigurationFactory.java | 77 +++++++ .../SnapshotProfilingSdkCustomizer.java | 32 ++- ...ofilingSpanProcessorComponentProvider.java | 3 +- .../snapshot/StackTraceExporterActivator.java | 24 ++- .../profiler/JfrAgentListenerTest.java | 4 +- ...ngConfigurationCustomizerProviderTest.java | 2 +- .../SnapshotProfilingConfigurationTest.java | 83 ++++++++ ...gDeclarativeConfigurationFactoryTest.java} | 22 +- ...ilingEnvVarsConfigurationFactoryTest.java} | 109 +++++----- .../StackTraceExporterActivatorTest.java | 140 +++++++------ 19 files changed, 598 insertions(+), 410 deletions(-) delete mode 100644 profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingDeclarativeConfiguration.java create mode 100644 profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingDeclarativeConfigurationFactory.java delete mode 100644 profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingEnvVarsConfiguration.java create mode 100644 profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingEnvVarsConfigurationFactory.java create mode 100644 profiler/src/test/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingConfigurationTest.java rename profiler/src/test/java/com/splunk/opentelemetry/profiler/snapshot/{SnapshotProfilingDeclarativeConfigurationTest.java => SnapshotProfilingDeclarativeConfigurationFactoryTest.java} (87%) rename profiler/src/test/java/com/splunk/opentelemetry/profiler/snapshot/{SnapshotProfilingEnvVarsConfigurationTest.java => SnapshotProfilingEnvVarsConfigurationFactoryTest.java} (66%) diff --git a/opamp/src/main/java/com/splunk/opentelemetry/opamp/effectiveconfig/DeclarativeEffectiveConfigFileFactory.java b/opamp/src/main/java/com/splunk/opentelemetry/opamp/effectiveconfig/DeclarativeEffectiveConfigFileFactory.java index 7fe5d6ebe..44521465a 100644 --- a/opamp/src/main/java/com/splunk/opentelemetry/opamp/effectiveconfig/DeclarativeEffectiveConfigFileFactory.java +++ b/opamp/src/main/java/com/splunk/opentelemetry/opamp/effectiveconfig/DeclarativeEffectiveConfigFileFactory.java @@ -20,7 +20,6 @@ import com.splunk.opentelemetry.opamp.DeclarativeConfigurationInterceptor; import com.splunk.opentelemetry.profiler.ProfilerConfiguration; import com.splunk.opentelemetry.profiler.snapshot.SnapshotProfilingConfiguration; -import com.splunk.opentelemetry.profiler.snapshot.SnapshotProfilingDeclarativeConfiguration; import io.opentelemetry.sdk.autoconfigure.declarativeconfig.model.LogRecordExporterModel; import io.opentelemetry.sdk.autoconfigure.declarativeconfig.model.LoggerProviderModel; import io.opentelemetry.sdk.autoconfigure.declarativeconfig.model.MeterProviderModel; @@ -71,7 +70,7 @@ public String createEffectiveConfigContent() { } ProfilerConfiguration profilerConfiguration = ProfilerConfiguration.SUPPLIER.get(); SnapshotProfilingConfiguration snapshotConfiguration = - SnapshotProfilingDeclarativeConfiguration.SUPPLIER.get(); + SnapshotProfilingConfiguration.SUPPLIER.get(); return processModel(model, profilerConfiguration, snapshotConfiguration); } diff --git a/opamp/src/main/java/com/splunk/opentelemetry/opamp/effectiveconfig/EnvVarsEffectiveConfigFileFactory.java b/opamp/src/main/java/com/splunk/opentelemetry/opamp/effectiveconfig/EnvVarsEffectiveConfigFileFactory.java index 687fda85a..358117c22 100644 --- a/opamp/src/main/java/com/splunk/opentelemetry/opamp/effectiveconfig/EnvVarsEffectiveConfigFileFactory.java +++ b/opamp/src/main/java/com/splunk/opentelemetry/opamp/effectiveconfig/EnvVarsEffectiveConfigFileFactory.java @@ -18,7 +18,6 @@ import com.splunk.opentelemetry.profiler.ProfilerConfiguration; import com.splunk.opentelemetry.profiler.snapshot.SnapshotProfilingConfiguration; -import com.splunk.opentelemetry.profiler.snapshot.SnapshotProfilingEnvVarsConfiguration; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; class EnvVarsEffectiveConfigFileFactory implements EffectiveConfigFactory { @@ -50,7 +49,7 @@ public String createEffectiveConfigContent() { private void addSplunkEnvVars(EffectiveConfigBuilder builder) { ProfilerConfiguration profilerConfiguration = ProfilerConfiguration.SUPPLIER.get(); SnapshotProfilingConfiguration snapshotConfiguration = - new SnapshotProfilingEnvVarsConfiguration(config); + SnapshotProfilingConfiguration.SUPPLIER.get(); builder .add("SPLUNK_PROFILER_ENABLED", profilerConfiguration.isEnabled()) diff --git a/opamp/src/test/java/com/splunk/opentelemetry/opamp/effectiveconfig/DeclarativeEffectiveConfigFileFactoryTest.java b/opamp/src/test/java/com/splunk/opentelemetry/opamp/effectiveconfig/DeclarativeEffectiveConfigFileFactoryTest.java index 091c6bf7a..43ed0936e 100644 --- a/opamp/src/test/java/com/splunk/opentelemetry/opamp/effectiveconfig/DeclarativeEffectiveConfigFileFactoryTest.java +++ b/opamp/src/test/java/com/splunk/opentelemetry/opamp/effectiveconfig/DeclarativeEffectiveConfigFileFactoryTest.java @@ -26,7 +26,7 @@ import com.splunk.opentelemetry.profiler.ProfilerConfiguration; import com.splunk.opentelemetry.profiler.ProfilerDeclarativeConfigurationFactory; import com.splunk.opentelemetry.profiler.snapshot.SnapshotProfilingConfiguration; -import com.splunk.opentelemetry.profiler.snapshot.SnapshotProfilingDeclarativeConfiguration; +import com.splunk.opentelemetry.profiler.snapshot.SnapshotProfilingDeclarativeConfigurationFactory; import com.splunk.opentelemetry.testing.declarativeconfig.DeclarativeConfigTestUtil; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import io.opentelemetry.instrumentation.testing.internal.AutoCleanupExtension; @@ -58,7 +58,7 @@ class DeclarativeEffectiveConfigFileFactoryTest { void afterEach() { DeclarativeConfigurationInterceptor.reset(); ProfilerConfiguration.SUPPLIER.reset(); - SnapshotProfilingDeclarativeConfiguration.SUPPLIER.reset(); + SnapshotProfilingConfiguration.SUPPLIER.reset(); } @Test @@ -399,8 +399,8 @@ public static void main(String[] args) throws Exception { getDistributionConfig(model).getStructured("profiling", empty()); ProfilerConfiguration.SUPPLIER.configure( ProfilerDeclarativeConfigurationFactory.create(profilingConfig)); - SnapshotProfilingDeclarativeConfiguration.SUPPLIER.configure( - new SnapshotProfilingDeclarativeConfiguration(profilingConfig)); + SnapshotProfilingConfiguration.SUPPLIER.configure( + SnapshotProfilingDeclarativeConfigurationFactory.create(profilingConfig)); DeclarativeConfigurationBuilder builder = new DeclarativeConfigurationBuilder(); new DeclarativeConfigurationInterceptor().customize(builder); diff --git a/opamp/src/test/java/com/splunk/opentelemetry/opamp/effectiveconfig/EnvVarsEffectiveConfigFileFactoryTest.java b/opamp/src/test/java/com/splunk/opentelemetry/opamp/effectiveconfig/EnvVarsEffectiveConfigFileFactoryTest.java index 5e2c4d578..a83dd1cb1 100644 --- a/opamp/src/test/java/com/splunk/opentelemetry/opamp/effectiveconfig/EnvVarsEffectiveConfigFileFactoryTest.java +++ b/opamp/src/test/java/com/splunk/opentelemetry/opamp/effectiveconfig/EnvVarsEffectiveConfigFileFactoryTest.java @@ -20,6 +20,8 @@ import com.splunk.opentelemetry.profiler.ProfilerConfiguration; import com.splunk.opentelemetry.profiler.ProfilerEnvVarsConfigurationFactory; +import com.splunk.opentelemetry.profiler.snapshot.SnapshotProfilingConfiguration; +import com.splunk.opentelemetry.profiler.snapshot.SnapshotProfilingEnvVarsConfigurationFactory; import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; import java.io.IOException; import java.io.StringReader; @@ -33,6 +35,7 @@ class EnvVarsEffectiveConfigFileFactoryTest { @AfterEach void tearDown() { ProfilerConfiguration.SUPPLIER.reset(); + SnapshotProfilingConfiguration.SUPPLIER.reset(); } @Test @@ -163,6 +166,8 @@ void buildFileContent_usesSignalSpecificProtocolWhenResolvingEndpoints() throws private static Properties createFileContent(Map configMap) throws IOException { DefaultConfigProperties config = DefaultConfigProperties.createFromMap(configMap); ProfilerConfiguration.SUPPLIER.configure(ProfilerEnvVarsConfigurationFactory.create(config)); + SnapshotProfilingConfiguration.SUPPLIER.configure( + SnapshotProfilingEnvVarsConfigurationFactory.create(config)); String fileContent = new EnvVarsEffectiveConfigFileFactory(config).createEffectiveConfigContent(); diff --git a/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingConfiguration.java b/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingConfiguration.java index 868e9c16f..baf0781cc 100644 --- a/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingConfiguration.java +++ b/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingConfiguration.java @@ -16,32 +16,124 @@ package com.splunk.opentelemetry.profiler.snapshot; +import com.splunk.opentelemetry.profiler.util.OptionalConfigurableSupplier; import java.time.Duration; +import java.util.Objects; import java.util.logging.Logger; +import javax.annotation.Nullable; -public interface SnapshotProfilingConfiguration { - double MAX_SELECTION_PROBABILITY = 1.0; - double DEFAULT_SELECTION_PROBABILITY = 0.01; - int DEFAULT_STACK_DEPTH = 1024; - long DEFAULT_SAMPLING_INTERVAL = 10; - long DEFAULT_EXPORT_INTERVAL = 5000; - int DEFAULT_STAGING_CAPACITY = 2000; +public class SnapshotProfilingConfiguration { + public static final OptionalConfigurableSupplier SUPPLIER = + new OptionalConfigurableSupplier<>(); - void log(); + private static final Logger logger = + Logger.getLogger(SnapshotProfilingConfiguration.class.getName()); - boolean isEnabled(); + static final double MAX_SELECTION_PROBABILITY = 1.0; + static final double DEFAULT_SELECTION_PROBABILITY = 0.01; + static final int DEFAULT_STACK_DEPTH = 1024; + static final long DEFAULT_SAMPLING_INTERVAL = 10; + static final long DEFAULT_EXPORT_INTERVAL = 5000; + static final int DEFAULT_STAGING_CAPACITY = 2000; - double getSnapshotSelectionProbability(); + private final boolean enabled; + private final double snapshotSelectionProbability; + private final int stackDepth; + private final Duration samplingInterval; + private final Duration exportInterval; + private final int stagingCapacity; + @Nullable private final Object configProperties; - int getStackDepth(); + private SnapshotProfilingConfiguration(Builder builder) { + enabled = builder.enabled; + snapshotSelectionProbability = builder.snapshotSelectionProbability; + stackDepth = builder.stackDepth; + samplingInterval = builder.samplingInterval; + exportInterval = builder.exportInterval; + stagingCapacity = builder.stagingCapacity; + configProperties = builder.configProperties; + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder(this); + } + + public void log() { + logger.info("Snapshot Profiler Configuration:"); + logger.info("--------------------------------"); + + log("Enabled", isEnabled()); + log("SelectionProbability", getSnapshotSelectionProbability()); + log("StackDepth", getStackDepth()); + log("SamplingInterval", getSamplingInterval().toMillis() + "ms"); + log("ExportInterval", getExportInterval().toMillis() + "ms"); + log("StagingCapacity", getStagingCapacity()); + + logger.info("--------------------------------"); + } + + public boolean isEnabled() { + return enabled; + } + + public double getSnapshotSelectionProbability() { + return snapshotSelectionProbability; + } + + public int getStackDepth() { + return stackDepth; + } + + public Duration getSamplingInterval() { + return samplingInterval; + } + + public Duration getExportInterval() { + return exportInterval; + } - Duration getSamplingInterval(); + public int getStagingCapacity() { + return stagingCapacity; + } - Duration getExportInterval(); + @Nullable + public Object getConfigProperties() { + return configProperties; + } - int getStagingCapacity(); + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof SnapshotProfilingConfiguration)) { + return false; + } + SnapshotProfilingConfiguration that = (SnapshotProfilingConfiguration) other; + return enabled == that.enabled + && Double.compare(that.snapshotSelectionProbability, snapshotSelectionProbability) == 0 + && stackDepth == that.stackDepth + && stagingCapacity == that.stagingCapacity + && Objects.equals(samplingInterval, that.samplingInterval) + && Objects.equals(exportInterval, that.exportInterval) + && Objects.equals(configProperties, that.configProperties); + } - Object getConfigProperties(); + @Override + public int hashCode() { + return Objects.hash( + enabled, + snapshotSelectionProbability, + stackDepth, + samplingInterval, + exportInterval, + stagingCapacity, + configProperties); + } static double validateSelectionProbability(double selectionProbability, Logger logger) { if (selectionProbability > MAX_SELECTION_PROBABILITY) { @@ -55,7 +147,7 @@ static double validateSelectionProbability(double selectionProbability, Logger l } if (selectionProbability <= 0) { logger.warning( - "Snapshot selection probability must be greater than 0. Using default snapshot" + "Snapshot selection probability must be greater than 0. Using default snapshot " + "selection probability of '" + DEFAULT_SELECTION_PROBABILITY + "' instead."); @@ -63,4 +155,69 @@ static double validateSelectionProbability(double selectionProbability, Logger l } return selectionProbability; } + + private static void log(String key, Object value) { + logger.info(String.format("%24s : %s", key, value)); + } + + public static class Builder { + private boolean enabled; + private double snapshotSelectionProbability = DEFAULT_SELECTION_PROBABILITY; + private int stackDepth = DEFAULT_STACK_DEPTH; + private Duration samplingInterval = Duration.ofMillis(DEFAULT_SAMPLING_INTERVAL); + private Duration exportInterval = Duration.ofMillis(DEFAULT_EXPORT_INTERVAL); + private int stagingCapacity = DEFAULT_STAGING_CAPACITY; + @Nullable private Object configProperties; + + private Builder() {} + + private Builder(SnapshotProfilingConfiguration config) { + enabled = config.enabled; + snapshotSelectionProbability = config.snapshotSelectionProbability; + stackDepth = config.stackDepth; + samplingInterval = config.samplingInterval; + exportInterval = config.exportInterval; + stagingCapacity = config.stagingCapacity; + configProperties = config.configProperties; + } + + public SnapshotProfilingConfiguration build() { + return new SnapshotProfilingConfiguration(this); + } + + public Builder setEnabled(boolean enabled) { + this.enabled = enabled; + return this; + } + + public Builder setSnapshotSelectionProbability(double snapshotSelectionProbability) { + this.snapshotSelectionProbability = snapshotSelectionProbability; + return this; + } + + public Builder setStackDepth(int stackDepth) { + this.stackDepth = stackDepth; + return this; + } + + public Builder setSamplingInterval(Duration samplingInterval) { + this.samplingInterval = Objects.requireNonNull(samplingInterval); + return this; + } + + public Builder setExportInterval(Duration exportInterval) { + this.exportInterval = Objects.requireNonNull(exportInterval); + return this; + } + + public Builder setStagingCapacity(int stagingCapacity) { + this.stagingCapacity = stagingCapacity; + return this; + } + + public Builder setConfigProperties(@Nullable Object configProperties) { + this.configProperties = configProperties; + return this; + } + } } diff --git a/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingConfigurationCustomizerProvider.java b/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingConfigurationCustomizerProvider.java index 2374e0b32..84d6d737b 100644 --- a/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingConfigurationCustomizerProvider.java +++ b/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingConfigurationCustomizerProvider.java @@ -46,8 +46,8 @@ public void customize(DeclarativeConfigurationCustomizer configurationCustomizer @VisibleForTesting OpenTelemetryConfigurationModel customizeModel(OpenTelemetryConfigurationModel model) { - SnapshotProfilingDeclarativeConfiguration snapshotProfiling = getSnapshotProfilingConfig(model); - SnapshotProfilingDeclarativeConfiguration.SUPPLIER.configure(snapshotProfiling); + SnapshotProfilingConfiguration snapshotProfiling = getSnapshotProfilingConfig(model); + SnapshotProfilingConfiguration.SUPPLIER.configure(snapshotProfiling); if (snapshotProfiling.isEnabled()) { initActiveSpansTracking(); @@ -58,8 +58,7 @@ OpenTelemetryConfigurationModel customizeModel(OpenTelemetryConfigurationModel m return model; } - private void initStackTraceSampler( - SnapshotProfilingDeclarativeConfiguration snapshotProfilingConfig) { + private void initStackTraceSampler(SnapshotProfilingConfiguration snapshotProfilingConfig) { StackTraceSamplerInitializer.setupStackTraceSampler(snapshotProfilingConfig); } @@ -87,11 +86,11 @@ private void initActiveSpansTracking() { contextStorageWrapper.wrapContextStorage(registry); } - private static SnapshotProfilingDeclarativeConfiguration getSnapshotProfilingConfig( + private static SnapshotProfilingConfiguration getSnapshotProfilingConfig( OpenTelemetryConfigurationModel model) { DeclarativeConfigProperties profilingConfig = getDistributionConfig(model).getStructured("profiling", empty()); - return new SnapshotProfilingDeclarativeConfiguration(profilingConfig); + return SnapshotProfilingDeclarativeConfigurationFactory.create(profilingConfig); } @VisibleForTesting diff --git a/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingDeclarativeConfiguration.java b/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingDeclarativeConfiguration.java deleted file mode 100644 index 46b6f9640..000000000 --- a/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingDeclarativeConfiguration.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright Splunk Inc. - * - * 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.splunk.opentelemetry.profiler.snapshot; - -import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty; - -import com.splunk.opentelemetry.profiler.util.OptionalConfigurableSupplier; -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import java.time.Duration; -import java.util.logging.Logger; - -public class SnapshotProfilingDeclarativeConfiguration implements SnapshotProfilingConfiguration { - public static final OptionalConfigurableSupplier - SUPPLIER = new OptionalConfigurableSupplier<>(); - - private static final Logger logger = - Logger.getLogger(SnapshotProfilingDeclarativeConfiguration.class.getName()); - private final DeclarativeConfigProperties profilingConfig; - - private static final String ROOT_NODE_NAME = "callgraphs"; - - public SnapshotProfilingDeclarativeConfiguration(DeclarativeConfigProperties profilingConfig) { - this.profilingConfig = profilingConfig; - } - - @Override - public void log() { - logger.info("Snapshot Profiler Configuration:"); - logger.info("--------------------------------"); - - log("Enabled", isEnabled()); - log("SelectionProbability", getSnapshotSelectionProbability()); - log("StackDepth", getStackDepth()); - log("SamplingInterval", getSamplingInterval().toMillis() + "ms"); - log("ExportInterval", getExportInterval().toMillis() + "ms"); - log("StagingCapacity", getStagingCapacity()); - - logger.info("--------------------------------"); - } - - @Override - public boolean isEnabled() { - return (profilingConfig != null) && profilingConfig.getPropertyKeys().contains(ROOT_NODE_NAME); - } - - @Override - public double getSnapshotSelectionProbability() { - double selectionProbability = - getConfigRoot().getDouble("selection_probability", DEFAULT_SELECTION_PROBABILITY); - return SnapshotProfilingConfiguration.validateSelectionProbability( - selectionProbability, logger); - } - - @Override - public int getStackDepth() { - return getConfigRoot().getInt("stack_depth", DEFAULT_STACK_DEPTH); - } - - @Override - public Duration getSamplingInterval() { - return getDuration("sampling_interval", DEFAULT_SAMPLING_INTERVAL); - } - - @Override - public Duration getExportInterval() { - return getDuration("export_interval", DEFAULT_EXPORT_INTERVAL); - } - - @Override - public int getStagingCapacity() { - return getConfigRoot().getInt("staging_capacity", DEFAULT_STAGING_CAPACITY); - } - - @Override - public Object getConfigProperties() { - return profilingConfig; - } - - private DeclarativeConfigProperties getConfigRoot() { - return profilingConfig.getStructured(ROOT_NODE_NAME, empty()); - } - - private void log(String key, Object value) { - logger.info(String.format("%24s : %s", key, value)); - } - - private Duration getDuration(String key, long defaultValue) { - return Duration.ofMillis(getConfigRoot().getLong(key, defaultValue)); - } -} diff --git a/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingDeclarativeConfigurationFactory.java b/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingDeclarativeConfigurationFactory.java new file mode 100644 index 000000000..5d09b0725 --- /dev/null +++ b/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingDeclarativeConfigurationFactory.java @@ -0,0 +1,75 @@ +/* + * Copyright Splunk Inc. + * + * 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.splunk.opentelemetry.profiler.snapshot; + +import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import java.time.Duration; +import java.util.logging.Logger; + +public final class SnapshotProfilingDeclarativeConfigurationFactory { + private static final Logger logger = + Logger.getLogger(SnapshotProfilingDeclarativeConfigurationFactory.class.getName()); + + private static final String ROOT_NODE_NAME = "callgraphs"; + + private SnapshotProfilingDeclarativeConfigurationFactory() {} + + public static SnapshotProfilingConfiguration create(DeclarativeConfigProperties profilingConfig) { + DeclarativeConfigProperties config = profilingConfig == null ? empty() : profilingConfig; + DeclarativeConfigProperties configRoot = getConfigRoot(config); + + return SnapshotProfilingConfiguration.builder() + .setEnabled(config.getPropertyKeys().contains(ROOT_NODE_NAME)) + .setSnapshotSelectionProbability(getSnapshotSelectionProbability(configRoot)) + .setStackDepth( + configRoot.getInt("stack_depth", SnapshotProfilingConfiguration.DEFAULT_STACK_DEPTH)) + .setSamplingInterval( + getDuration( + configRoot, + "sampling_interval", + SnapshotProfilingConfiguration.DEFAULT_SAMPLING_INTERVAL)) + .setExportInterval( + getDuration( + configRoot, + "export_interval", + SnapshotProfilingConfiguration.DEFAULT_EXPORT_INTERVAL)) + .setStagingCapacity( + configRoot.getInt( + "staging_capacity", SnapshotProfilingConfiguration.DEFAULT_STAGING_CAPACITY)) + .setConfigProperties(config) + .build(); + } + + private static DeclarativeConfigProperties getConfigRoot(DeclarativeConfigProperties config) { + return config.getStructured(ROOT_NODE_NAME, empty()); + } + + private static double getSnapshotSelectionProbability(DeclarativeConfigProperties configRoot) { + double selectionProbability = + configRoot.getDouble( + "selection_probability", SnapshotProfilingConfiguration.DEFAULT_SELECTION_PROBABILITY); + return SnapshotProfilingConfiguration.validateSelectionProbability( + selectionProbability, logger); + } + + private static Duration getDuration( + DeclarativeConfigProperties config, String key, long defaultValue) { + return Duration.ofMillis(config.getLong(key, defaultValue)); + } +} diff --git a/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingEnvVarsConfiguration.java b/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingEnvVarsConfiguration.java deleted file mode 100644 index ca87acee8..000000000 --- a/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingEnvVarsConfiguration.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright Splunk Inc. - * - * 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.splunk.opentelemetry.profiler.snapshot; - -import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; -import java.time.Duration; -import java.util.logging.Logger; - -public class SnapshotProfilingEnvVarsConfiguration implements SnapshotProfilingConfiguration { - private static final Logger logger = - Logger.getLogger(SnapshotProfilingEnvVarsConfiguration.class.getName()); - - private final ConfigProperties properties; - - // Visible for tests - public static final String CONFIG_KEY_ENABLE_SNAPSHOT_PROFILER = - "splunk.snapshot.profiler.enabled"; - public static final String SELECTION_PROBABILITY_KEY = "splunk.snapshot.selection.probability"; - public static final String STACK_DEPTH_KEY = "splunk.snapshot.profiler.max.stack.depth"; - public static final String SAMPLING_INTERVAL_KEY = "splunk.snapshot.sampling.interval"; - public static final String EXPORT_INTERVAL_KEY = "splunk.snapshot.profiler.export.interval"; - public static final String STAGING_CAPACITY_KEY = "splunk.snapshot.profiler.staging.capacity"; - - public SnapshotProfilingEnvVarsConfiguration(ConfigProperties properties) { - this.properties = properties; - } - - @Override - public void log() { - logger.fine("Snapshot Profiler Configuration:"); - logger.fine("-------------------------------------------------------"); - - log(CONFIG_KEY_ENABLE_SNAPSHOT_PROFILER, isEnabled()); - log(SELECTION_PROBABILITY_KEY, getSnapshotSelectionProbability()); - log(STACK_DEPTH_KEY, getStackDepth()); - log(SAMPLING_INTERVAL_KEY, getSamplingInterval().toMillis() + "ms"); - log(EXPORT_INTERVAL_KEY, getExportInterval().toMillis() + "ms"); - log(STAGING_CAPACITY_KEY, getStagingCapacity()); - logger.fine("-------------------------------------------------------"); - } - - @Override - public boolean isEnabled() { - return properties.getBoolean(CONFIG_KEY_ENABLE_SNAPSHOT_PROFILER, false); - } - - @Override - public double getSnapshotSelectionProbability() { - String selectionProbabilityPropertyValue = - properties.getString( - SELECTION_PROBABILITY_KEY, String.valueOf(DEFAULT_SELECTION_PROBABILITY)); - try { - double selectionProbability = Double.parseDouble(selectionProbabilityPropertyValue); - return SnapshotProfilingConfiguration.validateSelectionProbability( - selectionProbability, logger); - } catch (NumberFormatException e) { - logger.warning( - "Invalid snapshot selection probability: '" - + selectionProbabilityPropertyValue - + "', using default probability of '" - + DEFAULT_SELECTION_PROBABILITY - + "'"); - return DEFAULT_SELECTION_PROBABILITY; - } - } - - @Override - public int getStackDepth() { - return properties.getInt(STACK_DEPTH_KEY, DEFAULT_STACK_DEPTH); - } - - @Override - public Duration getSamplingInterval() { - return properties.getDuration( - SAMPLING_INTERVAL_KEY, Duration.ofMillis(DEFAULT_SAMPLING_INTERVAL)); - } - - @Override - public Duration getExportInterval() { - return properties.getDuration(EXPORT_INTERVAL_KEY, Duration.ofMillis(DEFAULT_EXPORT_INTERVAL)); - } - - @Override - public int getStagingCapacity() { - return properties.getInt(STAGING_CAPACITY_KEY, DEFAULT_STAGING_CAPACITY); - } - - @Override - public Object getConfigProperties() { - return properties; - } - - private void log(String key, Object value) { - logger.fine(" " + pad(key) + " : " + value); - } - - private String pad(String str) { - return String.format("%42s", str); - } -} diff --git a/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingEnvVarsConfigurationFactory.java b/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingEnvVarsConfigurationFactory.java new file mode 100644 index 000000000..a1b6136d7 --- /dev/null +++ b/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingEnvVarsConfigurationFactory.java @@ -0,0 +1,77 @@ +/* + * Copyright Splunk Inc. + * + * 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.splunk.opentelemetry.profiler.snapshot; + +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import java.time.Duration; +import java.util.logging.Logger; + +public final class SnapshotProfilingEnvVarsConfigurationFactory { + private static final Logger logger = + Logger.getLogger(SnapshotProfilingEnvVarsConfigurationFactory.class.getName()); + + // Visible for tests + static final String CONFIG_KEY_ENABLE_SNAPSHOT_PROFILER = "splunk.snapshot.profiler.enabled"; + static final String SELECTION_PROBABILITY_KEY = "splunk.snapshot.selection.probability"; + static final String STACK_DEPTH_KEY = "splunk.snapshot.profiler.max.stack.depth"; + static final String SAMPLING_INTERVAL_KEY = "splunk.snapshot.sampling.interval"; + static final String EXPORT_INTERVAL_KEY = "splunk.snapshot.profiler.export.interval"; + static final String STAGING_CAPACITY_KEY = "splunk.snapshot.profiler.staging.capacity"; + + private SnapshotProfilingEnvVarsConfigurationFactory() {} + + public static SnapshotProfilingConfiguration create(ConfigProperties properties) { + return SnapshotProfilingConfiguration.builder() + .setEnabled(properties.getBoolean(CONFIG_KEY_ENABLE_SNAPSHOT_PROFILER, false)) + .setSnapshotSelectionProbability(getSnapshotSelectionProbability(properties)) + .setStackDepth( + properties.getInt(STACK_DEPTH_KEY, SnapshotProfilingConfiguration.DEFAULT_STACK_DEPTH)) + .setSamplingInterval( + properties.getDuration( + SAMPLING_INTERVAL_KEY, + Duration.ofMillis(SnapshotProfilingConfiguration.DEFAULT_SAMPLING_INTERVAL))) + .setExportInterval( + properties.getDuration( + EXPORT_INTERVAL_KEY, + Duration.ofMillis(SnapshotProfilingConfiguration.DEFAULT_EXPORT_INTERVAL))) + .setStagingCapacity( + properties.getInt( + STAGING_CAPACITY_KEY, SnapshotProfilingConfiguration.DEFAULT_STAGING_CAPACITY)) + .setConfigProperties(properties) + .build(); + } + + private static double getSnapshotSelectionProbability(ConfigProperties properties) { + String selectionProbabilityPropertyValue = + properties.getString( + SELECTION_PROBABILITY_KEY, + String.valueOf(SnapshotProfilingConfiguration.DEFAULT_SELECTION_PROBABILITY)); + try { + double selectionProbability = Double.parseDouble(selectionProbabilityPropertyValue); + return SnapshotProfilingConfiguration.validateSelectionProbability( + selectionProbability, logger); + } catch (NumberFormatException e) { + logger.warning( + "Invalid snapshot selection probability: '" + + selectionProbabilityPropertyValue + + "', using default probability of '" + + SnapshotProfilingConfiguration.DEFAULT_SELECTION_PROBABILITY + + "'"); + return SnapshotProfilingConfiguration.DEFAULT_SELECTION_PROBABILITY; + } + } +} diff --git a/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingSdkCustomizer.java b/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingSdkCustomizer.java index e1a8b4a8c..8bfcd76fa 100644 --- a/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingSdkCustomizer.java +++ b/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingSdkCustomizer.java @@ -44,8 +44,7 @@ public SnapshotProfilingSdkCustomizer() { private static Function stackTraceSamplerProvider() { return properties -> { - SnapshotProfilingEnvVarsConfiguration configuration = - new SnapshotProfilingEnvVarsConfiguration(properties); + SnapshotProfilingConfiguration configuration = SnapshotProfilingConfiguration.SUPPLIER.get(); Duration samplingPeriod = configuration.getSamplingInterval(); StagingArea.SUPPLIER.configure(createStagingArea(configuration)); return new PeriodicStackTraceSampler( @@ -53,8 +52,7 @@ private static Function stackTraceSamplerPr }; } - private static StagingArea createStagingArea( - SnapshotProfilingEnvVarsConfiguration configuration) { + private static StagingArea createStagingArea(SnapshotProfilingConfiguration configuration) { Duration interval = configuration.getExportInterval(); int capacity = configuration.getStagingCapacity(); return new PeriodicallyExportingStagingArea(StackTraceExporter.SUPPLIER, interval, capacity); @@ -79,6 +77,9 @@ private SnapshotProfilingSdkCustomizer( @Override public void customize(AutoConfigurationCustomizer autoConfigurationCustomizer) { + // initializeSnapshotProfilingConfiguration must be executed first + autoConfigurationCustomizer.addPropertiesCustomizer(initializeSnapshotProfilingConfiguration()); + autoConfigurationCustomizer .addTracerProviderCustomizer(snapshotProfilingSpanProcessor(registry)) .addPropertiesCustomizer(setupStackTraceSampler()) @@ -86,10 +87,19 @@ public void customize(AutoConfigurationCustomizer autoConfigurationCustomizer) { .addTracerProviderCustomizer(addShutdownHook()); } + private Function> + initializeSnapshotProfilingConfiguration() { + return properties -> { + SnapshotProfilingConfiguration.SUPPLIER.configure( + SnapshotProfilingEnvVarsConfigurationFactory.create(properties)); + return Collections.emptyMap(); + }; + } + private BiFunction addShutdownHook() { return (builder, properties) -> { - if (snapshotProfilingEnabled(properties)) { + if (snapshotProfilingEnabled()) { builder.addSpanProcessor(new SdkShutdownHook()); } return builder; @@ -99,9 +109,9 @@ public void customize(AutoConfigurationCustomizer autoConfigurationCustomizer) { private BiFunction snapshotProfilingSpanProcessor(TraceRegistry registry) { return (builder, properties) -> { - if (snapshotProfilingEnabled(properties)) { + if (snapshotProfilingEnabled()) { double selectionProbability = - new SnapshotProfilingEnvVarsConfiguration(properties).getSnapshotSelectionProbability(); + SnapshotProfilingConfiguration.SUPPLIER.get().getSnapshotSelectionProbability(); return builder.addSpanProcessor( new SnapshotProfilingSpanProcessor( @@ -117,7 +127,7 @@ private boolean includeTraceContextPropagator(Set configuredPropagators) private Function> setupStackTraceSampler() { return properties -> { - if (snapshotProfilingEnabled(properties)) { + if (snapshotProfilingEnabled()) { StackTraceSampler sampler = samplerProvider.apply(properties); ConfigurableSupplier supplier = StackTraceSampler.SUPPLIER; supplier.configure(sampler); @@ -129,14 +139,14 @@ private Function> setupStackTraceSampler() private Function> startTrackingActiveSpans( TraceRegistry registry) { return properties -> { - if (snapshotProfilingEnabled(properties)) { + if (snapshotProfilingEnabled()) { contextStorageWrapper.wrapContextStorage(registry); } return Collections.emptyMap(); }; } - private boolean snapshotProfilingEnabled(ConfigProperties properties) { - return new SnapshotProfilingEnvVarsConfiguration(properties).isEnabled(); + private boolean snapshotProfilingEnabled() { + return SnapshotProfilingConfiguration.SUPPLIER.get().isEnabled(); } } diff --git a/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingSpanProcessorComponentProvider.java b/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingSpanProcessorComponentProvider.java index a0b0d0b8a..f76757f71 100644 --- a/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingSpanProcessorComponentProvider.java +++ b/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingSpanProcessorComponentProvider.java @@ -48,8 +48,7 @@ public String getName() { public SnapshotProfilingSpanProcessor create( DeclarativeConfigProperties declarativeConfigProperties) { double selectionProbability = - new SnapshotProfilingDeclarativeConfiguration(declarativeConfigProperties) - .getSnapshotSelectionProbability(); + SnapshotProfilingConfiguration.SUPPLIER.get().getSnapshotSelectionProbability(); return new SnapshotProfilingSpanProcessor( traceRegistry, new TraceIdBasedSnapshotSelector(selectionProbability)); } diff --git a/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/StackTraceExporterActivator.java b/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/StackTraceExporterActivator.java index 226831cba..1a0bd3770 100644 --- a/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/StackTraceExporterActivator.java +++ b/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/StackTraceExporterActivator.java @@ -16,8 +16,6 @@ package com.splunk.opentelemetry.profiler.snapshot; -import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty; - import com.google.auto.service.AutoService; import com.google.common.annotations.VisibleForTesting; import com.splunk.opentelemetry.profiler.OtelLoggerFactory; @@ -26,8 +24,10 @@ import io.opentelemetry.javaagent.extension.AgentListener; import io.opentelemetry.sdk.autoconfigure.AutoConfigureUtil; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; +import io.opentelemetry.sdk.autoconfigure.declarativeconfig.YamlDeclarativeConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.resources.Resource; +import java.util.Collections; @AutoService(AgentListener.class) public class StackTraceExporterActivator implements AgentListener { @@ -47,7 +47,7 @@ public StackTraceExporterActivator() { @Override public void afterAgent(AutoConfiguredOpenTelemetrySdk sdk) { - SnapshotProfilingConfiguration configuration = getSnapshotProfilingConfiguration(sdk); + SnapshotProfilingConfiguration configuration = SnapshotProfilingConfiguration.SUPPLIER.get(); if (!configuration.isEnabled()) { return; } @@ -66,7 +66,7 @@ private Logger buildLogger(AutoConfiguredOpenTelemetrySdk sdk, Object configProp Resource resource = AutoConfigureUtil.getResource(sdk); if (configProperties instanceof DeclarativeConfigProperties) { DeclarativeConfigProperties exporterConfig = - ((DeclarativeConfigProperties) configProperties).getStructured("exporter", empty()); + getExporterConfig((DeclarativeConfigProperties) configProperties); return otelLoggerFactory.build(exporterConfig, resource); } if (configProperties instanceof ConfigProperties) { @@ -76,13 +76,15 @@ private Logger buildLogger(AutoConfiguredOpenTelemetrySdk sdk, Object configProp "Unsupported config properties type: " + configProperties.getClass().getName()); } - private static SnapshotProfilingConfiguration getSnapshotProfilingConfiguration( - AutoConfiguredOpenTelemetrySdk sdk) { - if (SnapshotProfilingDeclarativeConfiguration.SUPPLIER.isConfigured()) { - return SnapshotProfilingDeclarativeConfiguration.SUPPLIER.get(); - } else { - ConfigProperties configProperties = AutoConfigureUtil.getConfig(sdk); - return new SnapshotProfilingEnvVarsConfiguration(configProperties); + private static DeclarativeConfigProperties getExporterConfig( + DeclarativeConfigProperties configProperties) { + DeclarativeConfigProperties exporterConfig = configProperties.getStructured("exporter"); + if (exporterConfig != null) { + return exporterConfig; } + // DeclarativeConfigProperties.empty() would drop the component loader that discovers OTLP + // sender providers. + return YamlDeclarativeConfigProperties.create( + Collections.emptyMap(), configProperties.getComponentLoader()); } } diff --git a/profiler/src/test/java/com/splunk/opentelemetry/profiler/JfrAgentListenerTest.java b/profiler/src/test/java/com/splunk/opentelemetry/profiler/JfrAgentListenerTest.java index 3d7d28fe2..2db8bc81a 100644 --- a/profiler/src/test/java/com/splunk/opentelemetry/profiler/JfrAgentListenerTest.java +++ b/profiler/src/test/java/com/splunk/opentelemetry/profiler/JfrAgentListenerTest.java @@ -22,7 +22,7 @@ import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; -import com.splunk.opentelemetry.profiler.snapshot.SnapshotProfilingDeclarativeConfiguration; +import com.splunk.opentelemetry.profiler.snapshot.SnapshotProfilingConfiguration; import io.opentelemetry.instrumentation.testing.internal.AutoCleanupExtension; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; import java.io.IOException; @@ -44,7 +44,7 @@ class JfrAgentListenerTest { @AfterEach void resetDeclarativeConfigSuppliers() { ProfilerConfiguration.SUPPLIER.reset(); - SnapshotProfilingDeclarativeConfiguration.SUPPLIER.reset(); + SnapshotProfilingConfiguration.SUPPLIER.reset(); } @Test diff --git a/profiler/src/test/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingConfigurationCustomizerProviderTest.java b/profiler/src/test/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingConfigurationCustomizerProviderTest.java index dc3374189..ecb07ab81 100644 --- a/profiler/src/test/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingConfigurationCustomizerProviderTest.java +++ b/profiler/src/test/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingConfigurationCustomizerProviderTest.java @@ -40,7 +40,7 @@ class SnapshotProfilingConfigurationCustomizerProviderTest { @AfterEach void resetSuppliers() { - SnapshotProfilingDeclarativeConfiguration.SUPPLIER.reset(); + SnapshotProfilingConfiguration.SUPPLIER.reset(); StackTraceSampler.SUPPLIER.reset(); StagingArea.SUPPLIER.reset(); SpanTracker.SUPPLIER.reset(); diff --git a/profiler/src/test/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingConfigurationTest.java b/profiler/src/test/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingConfigurationTest.java new file mode 100644 index 000000000..60c7d9bcf --- /dev/null +++ b/profiler/src/test/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingConfigurationTest.java @@ -0,0 +1,83 @@ +/* + * Copyright Splunk Inc. + * + * 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.splunk.opentelemetry.profiler.snapshot; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.Duration; +import org.junit.jupiter.api.Test; + +class SnapshotProfilingConfigurationTest { + + @Test + void toBuilder_shouldCopyExistingConfigurationWithoutMutation() { + Object configProperties = new Object(); + SnapshotProfilingConfiguration original = + SnapshotProfilingConfiguration.builder() + .setEnabled(true) + .setSnapshotSelectionProbability(0.25) + .setStackDepth(73) + .setSamplingInterval(Duration.ofMillis(1410)) + .setExportInterval(Duration.ofSeconds(30)) + .setStagingCapacity(321) + .setConfigProperties(configProperties) + .build(); + + SnapshotProfilingConfiguration copy = original.toBuilder().build(); + + assertThat(copy).isNotSameAs(original); + assertThat(copy).isEqualTo(original); + assertThat(copy.hashCode()).isEqualTo(original.hashCode()); + assertThat(copy.getConfigProperties()).isSameAs(configProperties); + } + + @Test + void toBuilder_shouldCopyExistingConfigurationAndAllowMutation() { + Object configProperties = new Object(); + Object mutatedConfigProperties = new Object(); + SnapshotProfilingConfiguration original = + SnapshotProfilingConfiguration.builder() + .setEnabled(false) + .setSnapshotSelectionProbability(0.25) + .setStackDepth(73) + .setSamplingInterval(Duration.ofMillis(1410)) + .setExportInterval(Duration.ofSeconds(30)) + .setStagingCapacity(321) + .setConfigProperties(configProperties) + .build(); + + SnapshotProfilingConfiguration copy = + original.toBuilder() + .setEnabled(true) + .setSnapshotSelectionProbability(0.5) + .setStackDepth(142) + .setSamplingInterval(Duration.ofMillis(2500)) + .setExportInterval(Duration.ofSeconds(60)) + .setStagingCapacity(654) + .setConfigProperties(mutatedConfigProperties) + .build(); + + assertThat(copy).isNotEqualTo(original); + assertThat(copy.isEnabled()).isTrue(); + assertThat(copy.getSnapshotSelectionProbability()).isEqualTo(0.5); + assertThat(copy.getStackDepth()).isEqualTo(142); + assertThat(copy.getSamplingInterval()).isEqualTo(Duration.ofMillis(2500)); + assertThat(copy.getExportInterval()).isEqualTo(Duration.ofSeconds(60)); + assertThat(copy.getStagingCapacity()).isEqualTo(654); + assertThat(copy.getConfigProperties()).isSameAs(mutatedConfigProperties); + } +} diff --git a/profiler/src/test/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingDeclarativeConfigurationTest.java b/profiler/src/test/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingDeclarativeConfigurationFactoryTest.java similarity index 87% rename from profiler/src/test/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingDeclarativeConfigurationTest.java rename to profiler/src/test/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingDeclarativeConfigurationFactoryTest.java index 7c58b4ff0..afcf10f9b 100644 --- a/profiler/src/test/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingDeclarativeConfigurationTest.java +++ b/profiler/src/test/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingDeclarativeConfigurationFactoryTest.java @@ -25,7 +25,7 @@ import java.time.Duration; import org.junit.jupiter.api.Test; -class SnapshotProfilingDeclarativeConfigurationTest { +class SnapshotProfilingDeclarativeConfigurationFactoryTest { @Test void shouldMapYamlToConfiguration() { // given @@ -47,8 +47,8 @@ void shouldMapYamlToConfiguration() { DeclarativeConfigProperties profilingConfig = getProfilingConfig(model); // when - SnapshotProfilingDeclarativeConfiguration config = - new SnapshotProfilingDeclarativeConfiguration(profilingConfig); + SnapshotProfilingConfiguration config = + SnapshotProfilingDeclarativeConfigurationFactory.create(profilingConfig); // then assertThat(config.isEnabled()).isTrue(); @@ -75,8 +75,8 @@ void shouldEnableSnapshotProfilingWithDefaults() { DeclarativeConfigProperties snapshotProfilingConfig = getProfilingConfig(model); // when - SnapshotProfilingDeclarativeConfiguration config = - new SnapshotProfilingDeclarativeConfiguration(snapshotProfilingConfig); + SnapshotProfilingConfiguration config = + SnapshotProfilingDeclarativeConfigurationFactory.create(snapshotProfilingConfig); // then assertThat(config.isEnabled()).isTrue(); @@ -102,8 +102,8 @@ void shouldDisableSnapshotProfiling() { DeclarativeConfigProperties profilingConfig = getProfilingConfig(model); // when - SnapshotProfilingDeclarativeConfiguration config = - new SnapshotProfilingDeclarativeConfiguration(profilingConfig); + SnapshotProfilingConfiguration config = + SnapshotProfilingDeclarativeConfigurationFactory.create(profilingConfig); // then assertThat(config.isEnabled()).isFalse(); @@ -126,8 +126,8 @@ void shouldReturnValidSelectionInterval_aboveMax() { DeclarativeConfigProperties profilingConfig = getProfilingConfig(model); // when - SnapshotProfilingDeclarativeConfiguration config = - new SnapshotProfilingDeclarativeConfiguration(profilingConfig); + SnapshotProfilingConfiguration config = + SnapshotProfilingDeclarativeConfigurationFactory.create(profilingConfig); // then assertThat(config.getSnapshotSelectionProbability()) @@ -151,8 +151,8 @@ void shouldReturnValidSelectionInterval_tooLow() { DeclarativeConfigProperties profilingConfig = getProfilingConfig(model); // when - SnapshotProfilingDeclarativeConfiguration config = - new SnapshotProfilingDeclarativeConfiguration(profilingConfig); + SnapshotProfilingConfiguration config = + SnapshotProfilingDeclarativeConfigurationFactory.create(profilingConfig); // then assertThat(config.isEnabled()).isTrue(); diff --git a/profiler/src/test/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingEnvVarsConfigurationTest.java b/profiler/src/test/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingEnvVarsConfigurationFactoryTest.java similarity index 66% rename from profiler/src/test/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingEnvVarsConfigurationTest.java rename to profiler/src/test/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingEnvVarsConfigurationFactoryTest.java index 1463c4ec4..f741e65d3 100644 --- a/profiler/src/test/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingEnvVarsConfigurationTest.java +++ b/profiler/src/test/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingEnvVarsConfigurationFactoryTest.java @@ -26,11 +26,11 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -class SnapshotProfilingEnvVarsConfigurationTest { +class SnapshotProfilingEnvVarsConfigurationFactoryTest { private static final ComponentLoader COMPONENT_LOADER = ComponentLoader.forClassLoader( - SnapshotProfilingEnvVarsConfigurationTest.class.getClassLoader()); + SnapshotProfilingEnvVarsConfigurationFactoryTest.class.getClassLoader()); @ParameterizedTest @ValueSource(booleans = {true, false}) @@ -39,10 +39,10 @@ void shouldSupportEnabledAndDisabledSnapshotProfiler(boolean enabled) { var properties = DefaultConfigProperties.create( Map.of( - SnapshotProfilingEnvVarsConfiguration.CONFIG_KEY_ENABLE_SNAPSHOT_PROFILER, + SnapshotProfilingEnvVarsConfigurationFactory.CONFIG_KEY_ENABLE_SNAPSHOT_PROFILER, String.valueOf(enabled)), COMPONENT_LOADER); - var configuration = new SnapshotProfilingEnvVarsConfiguration(properties); + var configuration = SnapshotProfilingEnvVarsConfigurationFactory.create(properties); // when boolean actual = configuration.isEnabled(); @@ -58,10 +58,10 @@ void shouldReturnValidSelectionProbability(double selectionRate) { var properties = DefaultConfigProperties.create( Map.of( - SnapshotProfilingEnvVarsConfiguration.SELECTION_PROBABILITY_KEY, + SnapshotProfilingEnvVarsConfigurationFactory.SELECTION_PROBABILITY_KEY, String.valueOf(selectionRate)), COMPONENT_LOADER); - var configuration = new SnapshotProfilingEnvVarsConfiguration(properties); + var configuration = SnapshotProfilingEnvVarsConfigurationFactory.create(properties); // when double actualSelectionRate = configuration.getSnapshotSelectionProbability(); @@ -77,10 +77,10 @@ void shouldReturnMaxSelectionProbabilityWhenAboveMax(double selectionRate) { var properties = DefaultConfigProperties.create( Map.of( - SnapshotProfilingEnvVarsConfiguration.SELECTION_PROBABILITY_KEY, + SnapshotProfilingEnvVarsConfigurationFactory.SELECTION_PROBABILITY_KEY, String.valueOf(selectionRate)), COMPONENT_LOADER); - var configuration = new SnapshotProfilingEnvVarsConfiguration(properties); + var configuration = SnapshotProfilingEnvVarsConfigurationFactory.create(properties); // when double actualSelectionRate = configuration.getSnapshotSelectionProbability(); @@ -94,9 +94,9 @@ void shouldFallbackSelectionProbabilityToDefaultWhenZero() { // given var properties = DefaultConfigProperties.create( - Map.of(SnapshotProfilingEnvVarsConfiguration.SELECTION_PROBABILITY_KEY, "0"), + Map.of(SnapshotProfilingEnvVarsConfigurationFactory.SELECTION_PROBABILITY_KEY, "0"), COMPONENT_LOADER); - var configuration = new SnapshotProfilingEnvVarsConfiguration(properties); + var configuration = SnapshotProfilingEnvVarsConfigurationFactory.create(properties); // when double actualSelectionRate = configuration.getSnapshotSelectionProbability(); @@ -110,9 +110,11 @@ void shouldReturnDefaultSelectionProbabilityWhenNotANumber() { // given var properties = DefaultConfigProperties.create( - Map.of(SnapshotProfilingEnvVarsConfiguration.SELECTION_PROBABILITY_KEY, "not-a-number"), + Map.of( + SnapshotProfilingEnvVarsConfigurationFactory.SELECTION_PROBABILITY_KEY, + "not-a-number"), COMPONENT_LOADER); - var configuration = new SnapshotProfilingEnvVarsConfiguration(properties); + var configuration = SnapshotProfilingEnvVarsConfigurationFactory.create(properties); // when double actualSelectionRate = configuration.getSnapshotSelectionProbability(); @@ -127,9 +129,11 @@ void shouldReturnStackDepth() { int depth = 123; var properties = DefaultConfigProperties.create( - Map.of(SnapshotProfilingEnvVarsConfiguration.STACK_DEPTH_KEY, String.valueOf(depth)), + Map.of( + SnapshotProfilingEnvVarsConfigurationFactory.STACK_DEPTH_KEY, + String.valueOf(depth)), COMPONENT_LOADER); - var configuration = new SnapshotProfilingEnvVarsConfiguration(properties); + var configuration = SnapshotProfilingEnvVarsConfigurationFactory.create(properties); // when int actualDepth = configuration.getStackDepth(); @@ -145,10 +149,10 @@ void shouldReturnSamplingInterval() { var properties = DefaultConfigProperties.create( Map.of( - SnapshotProfilingEnvVarsConfiguration.SAMPLING_INTERVAL_KEY, + SnapshotProfilingEnvVarsConfigurationFactory.SAMPLING_INTERVAL_KEY, samplingInterval + "ms"), COMPONENT_LOADER); - var configuration = new SnapshotProfilingEnvVarsConfiguration(properties); + var configuration = SnapshotProfilingEnvVarsConfigurationFactory.create(properties); // when Duration actual = configuration.getSamplingInterval(); @@ -164,9 +168,10 @@ void shouldReturnExportInterval() { var properties = DefaultConfigProperties.create( Map.of( - SnapshotProfilingEnvVarsConfiguration.EXPORT_INTERVAL_KEY, exportInterval + "ms"), + SnapshotProfilingEnvVarsConfigurationFactory.EXPORT_INTERVAL_KEY, + exportInterval + "ms"), COMPONENT_LOADER); - var configuration = new SnapshotProfilingEnvVarsConfiguration(properties); + var configuration = SnapshotProfilingEnvVarsConfigurationFactory.create(properties); // when Duration actual = configuration.getExportInterval(); @@ -182,10 +187,10 @@ void shouldReturnStagingCapacity() { var properties = DefaultConfigProperties.create( Map.of( - SnapshotProfilingEnvVarsConfiguration.STAGING_CAPACITY_KEY, + SnapshotProfilingEnvVarsConfigurationFactory.STAGING_CAPACITY_KEY, String.valueOf(capacity)), COMPONENT_LOADER); - var configuration = new SnapshotProfilingEnvVarsConfiguration(properties); + var configuration = SnapshotProfilingEnvVarsConfigurationFactory.create(properties); // when int actual = configuration.getStagingCapacity(); @@ -204,13 +209,13 @@ void isSnapshotProfilingEnabled(boolean enabled) { DeclarativeConfigPropertiesBridgeBuilder builder = new DeclarativeConfigPropertiesBridgeBuilder(); builder.addOverride( - SnapshotProfilingEnvVarsConfiguration.CONFIG_KEY_ENABLE_SNAPSHOT_PROFILER, enabled); + SnapshotProfilingEnvVarsConfigurationFactory.CONFIG_KEY_ENABLE_SNAPSHOT_PROFILER, enabled); // when var properties = builder.buildFromInstrumentationConfig(null); // then - assertThat(new SnapshotProfilingEnvVarsConfiguration(properties).isSnapshotProfilingEnabled()) + assertThat(SnapshotProfilingEnvVarsConfigurationFactory.create(properties).isSnapshotProfilingEnabled()) .isEqualTo(enabled); } @@ -220,13 +225,13 @@ void getConfiguredSnapshotProfilerStackDepth(int depth) { // given DeclarativeConfigPropertiesBridgeBuilder builder = new DeclarativeConfigPropertiesBridgeBuilder(); - builder.addOverride(SnapshotProfilingEnvVarsConfiguration.STACK_DEPTH_KEY, depth); + builder.addOverride(SnapshotProfilingEnvVarsConfigurationFactory.STACK_DEPTH_KEY, depth); // when var properties = builder.buildFromInstrumentationConfig(null); // then - assertThat(new SnapshotProfilingEnvVarsConfiguration(properties).getStackDepth()) + assertThat(SnapshotProfilingEnvVarsConfigurationFactory.create(properties).getStackDepth()) .isEqualTo(depth); } @@ -237,13 +242,13 @@ void getConfiguredSnapshotProfilerSamplingInterval(long milliseconds) { DeclarativeConfigPropertiesBridgeBuilder builder = new DeclarativeConfigPropertiesBridgeBuilder(); builder.addOverride( - SnapshotProfilingEnvVarsConfiguration.SAMPLING_INTERVAL_KEY, milliseconds); + SnapshotProfilingEnvVarsConfigurationFactory.SAMPLING_INTERVAL_KEY, milliseconds); // when var properties = builder.buildFromInstrumentationConfig(null); // then - assertThat(new SnapshotProfilingEnvVarsConfiguration(properties).getSamplingInterval()) + assertThat(SnapshotProfilingEnvVarsConfigurationFactory.create(properties).getSamplingInterval()) .isEqualTo(Duration.ofMillis(milliseconds)); } @@ -253,13 +258,13 @@ void getConfiguredSnapshotProfilerEmptyStagingInterval(long milliseconds) { // given DeclarativeConfigPropertiesBridgeBuilder builder = new DeclarativeConfigPropertiesBridgeBuilder(); - builder.addOverride(SnapshotProfilingEnvVarsConfiguration.EXPORT_INTERVAL_KEY, milliseconds); + builder.addOverride(SnapshotProfilingEnvVarsConfigurationFactory.EXPORT_INTERVAL_KEY, milliseconds); // when var properties = builder.buildFromInstrumentationConfig(null); // then - assertThat(new SnapshotProfilingEnvVarsConfiguration(properties).getExportInterval()) + assertThat(SnapshotProfilingEnvVarsConfigurationFactory.create(properties).getExportInterval()) .isEqualTo(Duration.ofMillis(milliseconds)); } @@ -269,13 +274,13 @@ void getConfiguredSnapshotProfilerStagingCapacity(int value) { // given DeclarativeConfigPropertiesBridgeBuilder builder = new DeclarativeConfigPropertiesBridgeBuilder(); - builder.addOverride(SnapshotProfilingEnvVarsConfiguration.STAGING_CAPACITY_KEY, value); + builder.addOverride(SnapshotProfilingEnvVarsConfigurationFactory.STAGING_CAPACITY_KEY, value); // when var properties = builder.buildFromInstrumentationConfig(null); // then - assertThat(new SnapshotProfilingEnvVarsConfiguration(properties).getStagingCapacity()) + assertThat(SnapshotProfilingEnvVarsConfigurationFactory.create(properties).getStagingCapacity()) .isEqualTo(value); } } @@ -285,7 +290,7 @@ class LoggingTest { @RegisterExtension private final LogCapturer log = LogCapturer.create() - .captureForType(SnapshotProfilingEnvVarsConfiguration.class, Level.DEBUG); + .captureForType(SnapshotProfilingEnvVarsConfigurationFactory.class, Level.DEBUG); @Test void includeSnapshotProfilingHeading() { @@ -293,7 +298,7 @@ void includeSnapshotProfilingHeading() { var properties = DefaultConfigProperties.create(Collections.emptyMap(), COMPONENT_LOADER); // when - new SnapshotProfilingEnvVarsConfiguration(properties).log(); + SnapshotProfilingEnvVarsConfigurationFactory.create(properties).log(); // then log.assertContains("-----------------------"); @@ -307,14 +312,14 @@ void includeSnapshotProfilingEnabled(boolean enabled) { var properties = DefaultConfigProperties.create( Map.of( - SnapshotProfilingEnvVarsConfiguration.CONFIG_KEY_ENABLE_SNAPSHOT_PROFILER, + SnapshotProfilingEnvVarsConfigurationFactory.CONFIG_KEY_ENABLE_SNAPSHOT_PROFILER, String.valueOf(enabled)), COMPONENT_LOADER); // when - new SnapshotProfilingEnvVarsConfiguration(properties).log(); + SnapshotProfilingEnvVarsConfigurationFactory.create(properties).log(); // then log.assertContains( - SnapshotProfilingEnvVarsConfiguration.CONFIG_KEY_ENABLE_SNAPSHOT_PROFILER + SnapshotProfilingEnvVarsConfigurationFactory.CONFIG_KEY_ENABLE_SNAPSHOT_PROFILER + " : " + enabled); } @@ -326,14 +331,14 @@ void includeSnapshotProfilingSelectionRate(double rate) { var properties = DefaultConfigProperties.create( Map.of( - SnapshotProfilingEnvVarsConfiguration.SELECTION_PROBABILITY_KEY, + SnapshotProfilingEnvVarsConfigurationFactory.SELECTION_PROBABILITY_KEY, String.valueOf(rate)), COMPONENT_LOADER); // when - new SnapshotProfilingEnvVarsConfiguration(properties).log(); + SnapshotProfilingEnvVarsConfigurationFactory.create(properties).log(); // then log.assertContains( - SnapshotProfilingEnvVarsConfiguration.SELECTION_PROBABILITY_KEY + " : " + rate); + SnapshotProfilingEnvVarsConfigurationFactory.SELECTION_PROBABILITY_KEY + " : " + rate); } @ParameterizedTest @@ -342,12 +347,12 @@ void includeSnapshotProfilingStackTraceDepth(int depth) { // given var properties = DefaultConfigProperties.create( - Map.of(SnapshotProfilingEnvVarsConfiguration.STACK_DEPTH_KEY, String.valueOf(depth)), + Map.of(SnapshotProfilingEnvVarsConfigurationFactory.STACK_DEPTH_KEY, String.valueOf(depth)), COMPONENT_LOADER); // when - new SnapshotProfilingEnvVarsConfiguration(properties).log(); + SnapshotProfilingEnvVarsConfigurationFactory.create(properties).log(); // then - log.assertContains(SnapshotProfilingEnvVarsConfiguration.STACK_DEPTH_KEY + " : " + depth); + log.assertContains(SnapshotProfilingEnvVarsConfigurationFactory.STACK_DEPTH_KEY + " : " + depth); } @ParameterizedTest @@ -356,17 +361,17 @@ void includeSnapshotProfilingSamplingInterval(String interval) { // given var properties = DefaultConfigProperties.create( - Map.of(SnapshotProfilingEnvVarsConfiguration.SAMPLING_INTERVAL_KEY, interval), + Map.of(SnapshotProfilingEnvVarsConfigurationFactory.SAMPLING_INTERVAL_KEY, interval), COMPONENT_LOADER); // when - new SnapshotProfilingEnvVarsConfiguration(properties).log(); + SnapshotProfilingEnvVarsConfigurationFactory.create(properties).log(); // then var duration = - properties.getDuration(SnapshotProfilingEnvVarsConfiguration.SAMPLING_INTERVAL_KEY); + properties.getDuration(SnapshotProfilingEnvVarsConfigurationFactory.SAMPLING_INTERVAL_KEY); log.assertContains( - SnapshotProfilingEnvVarsConfiguration.SAMPLING_INTERVAL_KEY + " : " + duration); + SnapshotProfilingEnvVarsConfigurationFactory.SAMPLING_INTERVAL_KEY + " : " + duration); } @ParameterizedTest @@ -375,17 +380,17 @@ void includeSnapshotProfilingExportInterval(String interval) { // given var properties = DefaultConfigProperties.create( - Map.of(SnapshotProfilingEnvVarsConfiguration.EXPORT_INTERVAL_KEY, interval), + Map.of(SnapshotProfilingEnvVarsConfigurationFactory.EXPORT_INTERVAL_KEY, interval), COMPONENT_LOADER); // when - new SnapshotProfilingEnvVarsConfiguration(properties).log(); + SnapshotProfilingEnvVarsConfigurationFactory.create(properties).log(); // then var duration = - properties.getDuration(SnapshotProfilingEnvVarsConfiguration.EXPORT_INTERVAL_KEY); + properties.getDuration(SnapshotProfilingEnvVarsConfigurationFactory.EXPORT_INTERVAL_KEY); log.assertContains( - SnapshotProfilingEnvVarsConfiguration.EXPORT_INTERVAL_KEY + " : " + duration); + SnapshotProfilingEnvVarsConfigurationFactory.EXPORT_INTERVAL_KEY + " : " + duration); } @ParameterizedTest @@ -395,14 +400,14 @@ void includeSnapshotProfilingStagingCapacity(int capacity) { var properties = DefaultConfigProperties.create( Map.of( - SnapshotProfilingEnvVarsConfiguration.STAGING_CAPACITY_KEY, + SnapshotProfilingEnvVarsConfigurationFactory.STAGING_CAPACITY_KEY, String.valueOf(capacity)), COMPONENT_LOADER); // when - new SnapshotProfilingEnvVarsConfiguration(properties).log(); + SnapshotProfilingEnvVarsConfigurationFactory.create(properties).log(); // then log.assertContains( - SnapshotProfilingEnvVarsConfiguration.STAGING_CAPACITY_KEY + " : " + capacity); + SnapshotProfilingEnvVarsConfigurationFactory.STAGING_CAPACITY_KEY + " : " + capacity); } }*/ } diff --git a/profiler/src/test/java/com/splunk/opentelemetry/profiler/snapshot/StackTraceExporterActivatorTest.java b/profiler/src/test/java/com/splunk/opentelemetry/profiler/snapshot/StackTraceExporterActivatorTest.java index 339a468eb..f5d3d153b 100644 --- a/profiler/src/test/java/com/splunk/opentelemetry/profiler/snapshot/StackTraceExporterActivatorTest.java +++ b/profiler/src/test/java/com/splunk/opentelemetry/profiler/snapshot/StackTraceExporterActivatorTest.java @@ -16,106 +16,102 @@ package com.splunk.opentelemetry.profiler.snapshot; -import static com.splunk.opentelemetry.testing.declarativeconfig.DeclarativeConfigTestUtil.createAutoConfiguredSdk; import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotSame; import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; -import io.opentelemetry.instrumentation.testing.internal.AutoCleanupExtension; +import com.splunk.opentelemetry.profiler.OtelLoggerFactory; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.common.ComponentLoader; import io.opentelemetry.sdk.autoconfigure.OpenTelemetrySdkExtension; -import java.io.IOException; -import java.nio.file.Path; +import io.opentelemetry.sdk.autoconfigure.declarativeconfig.YamlDeclarativeConfigProperties; +import io.opentelemetry.sdk.common.export.HttpSenderProvider; +import io.opentelemetry.sdk.testing.exporter.InMemoryLogRecordExporter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; -import org.junit.jupiter.api.io.TempDir; class StackTraceExporterActivatorTest { + @RegisterExtension + public final OpenTelemetrySdkExtension sdk = OpenTelemetrySdkExtension.configure().build(); + @AfterEach void tearDown() { SpanTracker.SUPPLIER.reset(); StackTraceSampler.SUPPLIER.reset(); StagingArea.SUPPLIER.reset(); - SnapshotProfilingDeclarativeConfiguration.SUPPLIER.reset(); + SnapshotProfilingConfiguration.SUPPLIER.reset(); StackTraceExporter.SUPPLIER.reset(); } - @Nested - class SnapshotProfilingEnabled { - @RegisterExtension - public final OpenTelemetrySdkExtension s = - OpenTelemetrySdkExtension.configure() - .withProperty("splunk.snapshot.profiler.enabled", "true") - .with(new StackTraceExporterActivator()) + @Test + void configureStackTraceExporterProvider() { + var logExporter = InMemoryLogRecordExporter.create(); + SnapshotProfilingConfiguration configuration = + SnapshotProfilingConfiguration.builder() + .setEnabled(true) + .setConfigProperties(sdk.getConfig()) .build(); + SnapshotProfilingConfiguration.SUPPLIER.configure(configuration); - @Test - void configureStackTraceExporterProvider() { - var exporter = StackTraceExporter.SUPPLIER.get(); - assertNotSame(StackTraceExporter.NOOP, exporter); - assertInstanceOf(AsyncStackTraceExporter.class, exporter); - } + new StackTraceExporterActivator( + new OtelLoggerFactory(() -> logExporter, declarativeConfigProperties -> logExporter)) + .afterAgent(sdk); + + var exporter = StackTraceExporter.SUPPLIER.get(); + assertNotSame(StackTraceExporter.NOOP, exporter); + assertInstanceOf(AsyncStackTraceExporter.class, exporter); } - @Nested - class SnapshotProfilingDisabled { - @RegisterExtension - public final OpenTelemetrySdkExtension s = - OpenTelemetrySdkExtension.configure() - .withProperty("splunk.snapshot.profiler.enabled", "false") - .with(new StackTraceExporterActivator()) + @Test + void declarativeConfigWithoutExporterPreservesComponentLoader() { + RecordingComponentLoader componentLoader = new RecordingComponentLoader(); + DeclarativeConfigProperties configProperties = + YamlDeclarativeConfigProperties.create(Collections.emptyMap(), componentLoader); + SnapshotProfilingConfiguration configuration = + SnapshotProfilingConfiguration.builder() + .setEnabled(true) + .setConfigProperties(configProperties) .build(); + SnapshotProfilingConfiguration.SUPPLIER.configure(configuration); - @Test - void doNotConfigureStackTraceExporterProvider() { - var exporter = StackTraceExporter.SUPPLIER.get(); - assertSame(StackTraceExporter.NOOP, exporter); - } + new StackTraceExporterActivator().afterAgent(sdk); + + var exporter = StackTraceExporter.SUPPLIER.get(); + assertNotSame(StackTraceExporter.NOOP, exporter); + assertInstanceOf(AsyncStackTraceExporter.class, exporter); + assertTrue(componentLoader.loaded(HttpSenderProvider.class)); } - @Nested - class DeclarativeConfig { - @RegisterExtension - static final AutoCleanupExtension autoCleanup = AutoCleanupExtension.create(); - - @Test - void configureStackTraceExporterProvider(@TempDir Path tempDir) throws IOException { - String yaml = - """ - file_format: "1.0" - distribution: - splunk: - profiling: - exporter: - otlp_log_http: - callgraphs: - """; - var sdk = createAutoConfiguredSdk(yaml, tempDir, autoCleanup); - - new StackTraceExporterActivator().afterAgent(sdk); - - var exporter = StackTraceExporter.SUPPLIER.get(); - assertNotSame(StackTraceExporter.NOOP, exporter); - assertInstanceOf(AsyncStackTraceExporter.class, exporter); + @Test + void doNotConfigureStackTraceExporterProvider() { + SnapshotProfilingConfiguration configuration = + SnapshotProfilingConfiguration.builder().setEnabled(false).build(); + SnapshotProfilingConfiguration.SUPPLIER.configure(configuration); + + new StackTraceExporterActivator().afterAgent(sdk); + + var exporter = StackTraceExporter.SUPPLIER.get(); + assertSame(StackTraceExporter.NOOP, exporter); + } + + private static class RecordingComponentLoader implements ComponentLoader { + private final ComponentLoader delegate = + ComponentLoader.forClassLoader(StackTraceExporterActivatorTest.class.getClassLoader()); + private final List> loadedSpiClasses = new ArrayList<>(); + + @Override + public Iterable load(Class spiClass) { + loadedSpiClasses.add(spiClass); + return delegate.load(spiClass); } - @Test - void doNotConfigureStackTraceExporterProviderWhenNoCallgraphs(@TempDir Path tempDir) - throws IOException { - String yaml = - """ - file_format: "1.0" - distribution: - splunk: - profiling: - """; - var sdk = createAutoConfiguredSdk(yaml, tempDir, autoCleanup); - - new StackTraceExporterActivator().afterAgent(sdk); - - var exporter = StackTraceExporter.SUPPLIER.get(); - assertSame(StackTraceExporter.NOOP, exporter); + boolean loaded(Class spiClass) { + return loadedSpiClasses.contains(spiClass); } } } From 5c93e2bc5ec0bcb82fe4ab3589b65f616d4fcc89 Mon Sep 17 00:00:00 2001 From: robsunday Date: Tue, 7 Jul 2026 17:15:20 +0200 Subject: [PATCH 2/4] Fix for missing nodes in profiler exporter config --- .../profiler/LogExporterBuilder.java | 14 ++--- .../PeriodicRecordingFlusherFactory.java | 18 +----- .../ProfilerConfigurationInitializer.java | 17 +----- .../snapshot/StackTraceExporterActivator.java | 18 +----- .../profiler/LogExporterBuilderTest.java | 60 +++++++++++++++++++ 5 files changed, 76 insertions(+), 51 deletions(-) diff --git a/profiler/src/main/java/com/splunk/opentelemetry/profiler/LogExporterBuilder.java b/profiler/src/main/java/com/splunk/opentelemetry/profiler/LogExporterBuilder.java index f45344e43..60ebedba0 100644 --- a/profiler/src/main/java/com/splunk/opentelemetry/profiler/LogExporterBuilder.java +++ b/profiler/src/main/java/com/splunk/opentelemetry/profiler/LogExporterBuilder.java @@ -16,10 +16,10 @@ package com.splunk.opentelemetry.profiler; -import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty; import static io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil.DATA_TYPE_LOGS; import com.google.common.annotations.VisibleForTesting; +import com.splunk.opentelemetry.profiler.util.DeclarativeConfigPropertiesUtil; import io.opentelemetry.api.incubator.config.ConfigProvider; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import io.opentelemetry.common.ComponentLoader; @@ -30,7 +30,6 @@ import io.opentelemetry.exporter.otlp.internal.OtlpHttpLogRecordExporterComponentProvider; import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter; import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporterBuilder; -import io.opentelemetry.sdk.autoconfigure.declarativeconfig.YamlDeclarativeConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; import io.opentelemetry.sdk.autoconfigure.spi.internal.ExtendedDeclarativeConfigProperties; @@ -61,7 +60,8 @@ static LogRecordExporter fromDeclarativeConfig( if (propertyKeys.contains("otlp_log_http")) { DeclarativeConfigProperties otlpHttp = - exporterConfigProperties.getStructured("otlp_log_http", empty()); + DeclarativeConfigPropertiesUtil.getStructuredOrEmpty( + exporterConfigProperties, "otlp_log_http"); OtlpHttpLogRecordExporterComponentProvider provider = new OtlpHttpLogRecordExporterComponentProvider(); return provider.create(toExtended(otlpHttp)); @@ -69,7 +69,8 @@ static LogRecordExporter fromDeclarativeConfig( if (propertyKeys.contains("otlp_log_grpc")) { DeclarativeConfigProperties otlpGrpc = - exporterConfigProperties.getStructured("otlp_log_grpc", empty()); + DeclarativeConfigPropertiesUtil.getStructuredOrEmpty( + exporterConfigProperties, "otlp_log_grpc"); OtlpGrpcLogRecordExporterComponentProvider provider = new OtlpGrpcLogRecordExporterComponentProvider(); return provider.create(toExtended(otlpGrpc)); @@ -84,9 +85,8 @@ private static DeclarativeConfigProperties defaultOtlpHttpConfig( Map properties = new HashMap<>(); properties.put("endpoint", DEFAULT_HTTP_LOG_ENDPOINT); properties.put("encoding", "protobuf"); - // Keep the original component loader so OTLP sender providers remain discoverable. - return YamlDeclarativeConfigProperties.create( - properties, exporterConfigProperties.getComponentLoader()); + return DeclarativeConfigPropertiesUtil.createPreservingLoader( + exporterConfigProperties, properties); } static LogRecordExporter fromEnvironmentConfig() { diff --git a/profiler/src/main/java/com/splunk/opentelemetry/profiler/PeriodicRecordingFlusherFactory.java b/profiler/src/main/java/com/splunk/opentelemetry/profiler/PeriodicRecordingFlusherFactory.java index 22f77adea..35db26b42 100644 --- a/profiler/src/main/java/com/splunk/opentelemetry/profiler/PeriodicRecordingFlusherFactory.java +++ b/profiler/src/main/java/com/splunk/opentelemetry/profiler/PeriodicRecordingFlusherFactory.java @@ -23,8 +23,8 @@ import com.splunk.opentelemetry.profiler.context.SpanContextualizer; import com.splunk.opentelemetry.profiler.exporter.CpuEventExporter; import com.splunk.opentelemetry.profiler.exporter.PprofCpuEventExporter; +import com.splunk.opentelemetry.profiler.util.DeclarativeConfigPropertiesUtil; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.sdk.autoconfigure.declarativeconfig.YamlDeclarativeConfigProperties; import io.opentelemetry.sdk.logs.LogRecordProcessor; import io.opentelemetry.sdk.logs.SdkLoggerProvider; import io.opentelemetry.sdk.logs.export.LogRecordExporter; @@ -35,7 +35,6 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.time.Duration; -import java.util.Collections; import java.util.Map; class PeriodicRecordingFlusherFactory { @@ -147,24 +146,13 @@ private StackTraceFilter buildStackTraceFilter( private static LogRecordExporter createLogRecordExporter(Object configProperties) { if (configProperties instanceof DeclarativeConfigProperties) { DeclarativeConfigProperties exporterConfig = - getExporterConfig((DeclarativeConfigProperties) configProperties); + DeclarativeConfigPropertiesUtil.getStructuredOrEmpty( + (DeclarativeConfigProperties) configProperties, "exporter"); return LogExporterBuilder.fromDeclarativeConfig(exporterConfig); } return LogExporterBuilder.fromEnvironmentConfig(); } - private static DeclarativeConfigProperties getExporterConfig( - DeclarativeConfigProperties configProperties) { - DeclarativeConfigProperties exporterConfig = configProperties.getStructured("exporter"); - if (exporterConfig != null) { - return exporterConfig; - } - // DeclarativeConfigProperties.empty() is not used because it does not preserve the original - // component loader that is used later when creating default exporter - return YamlDeclarativeConfigProperties.create( - Collections.emptyMap(), configProperties.getComponentLoader()); - } - private boolean checkOutputDir(Path outputDir) { if (!Files.exists(outputDir)) { // Try creating the directory for the user... diff --git a/profiler/src/main/java/com/splunk/opentelemetry/profiler/ProfilerConfigurationInitializer.java b/profiler/src/main/java/com/splunk/opentelemetry/profiler/ProfilerConfigurationInitializer.java index 518ae6564..1d5d22156 100644 --- a/profiler/src/main/java/com/splunk/opentelemetry/profiler/ProfilerConfigurationInitializer.java +++ b/profiler/src/main/java/com/splunk/opentelemetry/profiler/ProfilerConfigurationInitializer.java @@ -17,11 +17,11 @@ package com.splunk.opentelemetry.profiler; import com.google.auto.service.AutoService; +import com.splunk.opentelemetry.profiler.util.DeclarativeConfigPropertiesUtil; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import io.opentelemetry.sdk.autoconfigure.AutoConfigureUtil; import io.opentelemetry.sdk.autoconfigure.declarativeconfig.DeclarativeConfigurationCustomizer; import io.opentelemetry.sdk.autoconfigure.declarativeconfig.DeclarativeConfigurationCustomizerProvider; -import io.opentelemetry.sdk.autoconfigure.declarativeconfig.YamlDeclarativeConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer; import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider; import java.util.Collections; @@ -44,7 +44,8 @@ public void customize(DeclarativeConfigurationCustomizer configurationCustomizer (model) -> { DeclarativeConfigProperties distributionConfig = AutoConfigureUtil.getDistributionConfig(model); - DeclarativeConfigProperties profilingConfig = getProfilingConfig(distributionConfig); + DeclarativeConfigProperties profilingConfig = + DeclarativeConfigPropertiesUtil.getStructuredOrEmpty(distributionConfig, "profiling"); ProfilerConfiguration.SUPPLIER.configure( ProfilerDeclarativeConfigurationFactory.create(profilingConfig)); @@ -68,16 +69,4 @@ public void customize(AutoConfigurationCustomizer autoConfiguration) { public int order() { return Integer.MAX_VALUE; } - - private static DeclarativeConfigProperties getProfilingConfig( - DeclarativeConfigProperties distributionConfig) { - DeclarativeConfigProperties profilingConfig = distributionConfig.getStructured("profiling"); - if (profilingConfig != null) { - return profilingConfig; - } - // DeclarativeConfigProperties.empty() is not used because it does not preserve the original - // component loader that is used later when creating default exporter - return YamlDeclarativeConfigProperties.create( - Collections.emptyMap(), distributionConfig.getComponentLoader()); - } } diff --git a/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/StackTraceExporterActivator.java b/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/StackTraceExporterActivator.java index 1a0bd3770..1f474d529 100644 --- a/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/StackTraceExporterActivator.java +++ b/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/StackTraceExporterActivator.java @@ -19,15 +19,14 @@ import com.google.auto.service.AutoService; import com.google.common.annotations.VisibleForTesting; import com.splunk.opentelemetry.profiler.OtelLoggerFactory; +import com.splunk.opentelemetry.profiler.util.DeclarativeConfigPropertiesUtil; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import io.opentelemetry.api.logs.Logger; import io.opentelemetry.javaagent.extension.AgentListener; import io.opentelemetry.sdk.autoconfigure.AutoConfigureUtil; import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; -import io.opentelemetry.sdk.autoconfigure.declarativeconfig.YamlDeclarativeConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.resources.Resource; -import java.util.Collections; @AutoService(AgentListener.class) public class StackTraceExporterActivator implements AgentListener { @@ -66,7 +65,8 @@ private Logger buildLogger(AutoConfiguredOpenTelemetrySdk sdk, Object configProp Resource resource = AutoConfigureUtil.getResource(sdk); if (configProperties instanceof DeclarativeConfigProperties) { DeclarativeConfigProperties exporterConfig = - getExporterConfig((DeclarativeConfigProperties) configProperties); + DeclarativeConfigPropertiesUtil.getStructuredOrEmpty( + (DeclarativeConfigProperties) configProperties, "exporter"); return otelLoggerFactory.build(exporterConfig, resource); } if (configProperties instanceof ConfigProperties) { @@ -75,16 +75,4 @@ private Logger buildLogger(AutoConfiguredOpenTelemetrySdk sdk, Object configProp throw new IllegalArgumentException( "Unsupported config properties type: " + configProperties.getClass().getName()); } - - private static DeclarativeConfigProperties getExporterConfig( - DeclarativeConfigProperties configProperties) { - DeclarativeConfigProperties exporterConfig = configProperties.getStructured("exporter"); - if (exporterConfig != null) { - return exporterConfig; - } - // DeclarativeConfigProperties.empty() would drop the component loader that discovers OTLP - // sender providers. - return YamlDeclarativeConfigProperties.create( - Collections.emptyMap(), configProperties.getComponentLoader()); - } } diff --git a/profiler/src/test/java/com/splunk/opentelemetry/profiler/LogExporterBuilderTest.java b/profiler/src/test/java/com/splunk/opentelemetry/profiler/LogExporterBuilderTest.java index b95ec00cd..528162070 100644 --- a/profiler/src/test/java/com/splunk/opentelemetry/profiler/LogExporterBuilderTest.java +++ b/profiler/src/test/java/com/splunk/opentelemetry/profiler/LogExporterBuilderTest.java @@ -31,14 +31,21 @@ import com.splunk.opentelemetry.testing.declarativeconfig.DeclarativeConfigTestUtil; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.common.ComponentLoader; import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter; import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporterBuilder; import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter; import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporterBuilder; +import io.opentelemetry.sdk.autoconfigure.declarativeconfig.YamlDeclarativeConfigProperties; import io.opentelemetry.sdk.autoconfigure.declarativeconfig.model.OpenTelemetryConfigurationModel; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; +import io.opentelemetry.sdk.common.export.GrpcSenderProvider; +import io.opentelemetry.sdk.common.export.HttpSenderProvider; import io.opentelemetry.sdk.logs.export.LogRecordExporter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; import java.util.Map; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -249,6 +256,36 @@ void shouldCreateGrpcExporter_defaultEndpoint() { assertThat(exporter).isNotNull(); } + @Test + void shouldCreateHttpExporterWithEmptyNodeUsingParentComponentLoader() { + // given + RecordingComponentLoader componentLoader = new RecordingComponentLoader(); + DeclarativeConfigProperties exporterConfig = + exporterConfigWithEmptyNode("otlp_log_http", componentLoader); + + // when + LogRecordExporter exporter = LogExporterBuilder.fromDeclarativeConfig(exporterConfig); + + // then + assertThat(exporter).isNotNull(); + assertThat(componentLoader.loaded(HttpSenderProvider.class)).isTrue(); + } + + @Test + void shouldCreateGrpcExporterWithEmptyNodeUsingParentComponentLoader() { + // given + RecordingComponentLoader componentLoader = new RecordingComponentLoader(); + DeclarativeConfigProperties exporterConfig = + exporterConfigWithEmptyNode("otlp_log_grpc", componentLoader); + + // when + LogRecordExporter exporter = LogExporterBuilder.fromDeclarativeConfig(exporterConfig); + + // then + assertThat(exporter).isNotNull(); + assertThat(componentLoader.loaded(GrpcSenderProvider.class)).isTrue(); + } + @Test void shouldThrowExceptionForInvalidProtocol() { // given @@ -274,5 +311,28 @@ private static DeclarativeConfigProperties getExporterConfig( OpenTelemetryConfigurationModel model) { return getProfilingConfig(model).getStructured("exporter", empty()); } + + private static DeclarativeConfigProperties exporterConfigWithEmptyNode( + String exporterName, ComponentLoader componentLoader) { + Map properties = new HashMap<>(); + properties.put(exporterName, null); + return YamlDeclarativeConfigProperties.create(properties, componentLoader); + } + + private static class RecordingComponentLoader implements ComponentLoader { + private final ComponentLoader delegate = + ComponentLoader.forClassLoader(LogExporterBuilderTest.class.getClassLoader()); + private final List> loadedSpiClasses = new ArrayList<>(); + + @Override + public Iterable load(Class spiClass) { + loadedSpiClasses.add(spiClass); + return delegate.load(spiClass); + } + + boolean loaded(Class spiClass) { + return loadedSpiClasses.contains(spiClass); + } + } } } From efcacf67461419d402011b569af6e5c1adfd5f8b Mon Sep 17 00:00:00 2001 From: robsunday Date: Tue, 7 Jul 2026 17:18:10 +0200 Subject: [PATCH 3/4] Fix for missing nodes in profiler exporter config --- .../util/DeclarativeConfigPropertiesUtil.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 profiler/src/main/java/com/splunk/opentelemetry/profiler/util/DeclarativeConfigPropertiesUtil.java diff --git a/profiler/src/main/java/com/splunk/opentelemetry/profiler/util/DeclarativeConfigPropertiesUtil.java b/profiler/src/main/java/com/splunk/opentelemetry/profiler/util/DeclarativeConfigPropertiesUtil.java new file mode 100644 index 000000000..4b0a4dac5 --- /dev/null +++ b/profiler/src/main/java/com/splunk/opentelemetry/profiler/util/DeclarativeConfigPropertiesUtil.java @@ -0,0 +1,45 @@ +/* + * Copyright Splunk Inc. + * + * 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.splunk.opentelemetry.profiler.util; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.sdk.autoconfigure.declarativeconfig.YamlDeclarativeConfigProperties; +import java.util.Collections; +import java.util.Map; + +public final class DeclarativeConfigPropertiesUtil { + private DeclarativeConfigPropertiesUtil() {} + + public static DeclarativeConfigProperties getStructuredOrEmpty( + DeclarativeConfigProperties parent, String name) { + DeclarativeConfigProperties structured = parent.getStructured(name); + if (structured != null) { + return structured; + } + return emptyPreservingLoader(parent); + } + + public static DeclarativeConfigProperties emptyPreservingLoader( + DeclarativeConfigProperties parent) { + return createPreservingLoader(parent, Collections.emptyMap()); + } + + public static DeclarativeConfigProperties createPreservingLoader( + DeclarativeConfigProperties parent, Map properties) { + return YamlDeclarativeConfigProperties.create(properties, parent.getComponentLoader()); + } +} From eff65447b21e00d855d299d058570c1bdc12fc88 Mon Sep 17 00:00:00 2001 From: robsunday Date: Wed, 8 Jul 2026 13:28:17 +0200 Subject: [PATCH 4/4] Code review followup --- .../profiler/ProfilerConfiguration.java | 37 +++++++++---------- .../SnapshotProfilingConfiguration.java | 19 ++++------ 2 files changed, 25 insertions(+), 31 deletions(-) diff --git a/profiler/src/main/java/com/splunk/opentelemetry/profiler/ProfilerConfiguration.java b/profiler/src/main/java/com/splunk/opentelemetry/profiler/ProfilerConfiguration.java index 70490d9e8..52fe8a398 100644 --- a/profiler/src/main/java/com/splunk/opentelemetry/profiler/ProfilerConfiguration.java +++ b/profiler/src/main/java/com/splunk/opentelemetry/profiler/ProfilerConfiguration.java @@ -74,7 +74,23 @@ public static Builder builder() { } public Builder toBuilder() { - return new Builder(this); + return new Builder() + .setEnabled(enabled) + .setIngestUrl(ingestUrl) + .setOtlpProtocol(otlpProtocol) + .setMemoryEnabled(memoryEnabled) + .setMemoryEventRateLimitEnabled(memoryEventRateLimitEnabled) + .setMemoryEventRate(memoryEventRate) + .setUseAllocationSampleEvent(useAllocationSampleEvent) + .setCallStackInterval(callStackInterval) + .setIncludeAgentInternalStacks(includeAgentInternalStacks) + .setIncludeJvmInternalStacks(includeJvmInternalStacks) + .setTracingStacksOnly(tracingStacksOnly) + .setStackDepth(stackDepth) + .setKeepFiles(keepFiles) + .setProfilerDirectory(profilerDirectory) + .setRecordingDuration(recordingDuration) + .setConfigProperties(configProperties); } public boolean isEnabled() { @@ -246,25 +262,6 @@ public static class Builder { private Builder() {} - private Builder(ProfilerConfiguration config) { - enabled = config.enabled; - ingestUrl = config.ingestUrl; - otlpProtocol = config.otlpProtocol; - memoryEnabled = config.memoryEnabled; - memoryEventRateLimitEnabled = config.memoryEventRateLimitEnabled; - memoryEventRate = config.memoryEventRate; - useAllocationSampleEvent = config.useAllocationSampleEvent; - callStackInterval = config.callStackInterval; - includeAgentInternalStacks = config.includeAgentInternalStacks; - includeJvmInternalStacks = config.includeJvmInternalStacks; - tracingStacksOnly = config.tracingStacksOnly; - stackDepth = config.stackDepth; - keepFiles = config.keepFiles; - profilerDirectory = config.profilerDirectory; - recordingDuration = config.recordingDuration; - configProperties = config.configProperties; - } - public ProfilerConfiguration build() { return new ProfilerConfiguration(this); } diff --git a/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingConfiguration.java b/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingConfiguration.java index baf0781cc..79e300f12 100644 --- a/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingConfiguration.java +++ b/profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingConfiguration.java @@ -59,7 +59,14 @@ public static Builder builder() { } public Builder toBuilder() { - return new Builder(this); + return new Builder() + .setEnabled(enabled) + .setSnapshotSelectionProbability(snapshotSelectionProbability) + .setStackDepth(stackDepth) + .setSamplingInterval(samplingInterval) + .setExportInterval(exportInterval) + .setStagingCapacity(stagingCapacity) + .setConfigProperties(configProperties); } public void log() { @@ -171,16 +178,6 @@ public static class Builder { private Builder() {} - private Builder(SnapshotProfilingConfiguration config) { - enabled = config.enabled; - snapshotSelectionProbability = config.snapshotSelectionProbability; - stackDepth = config.stackDepth; - samplingInterval = config.samplingInterval; - exportInterval = config.exportInterval; - stagingCapacity = config.stagingCapacity; - configProperties = config.configProperties; - } - public SnapshotProfilingConfiguration build() { return new SnapshotProfilingConfiguration(this); }