-
Notifications
You must be signed in to change notification settings - Fork 46
[OpAMP] Enabling and disabling call graphs via remote config #2944
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
bf44697
5c93e2b
efcacf6
eff6544
b8e36cf
57276b0
898d25e
73b5c6d
dbdaeaa
576149f
6f66ce4
cce4a7d
656daea
900e1f8
a7aa8c6
0538bb5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| /* | ||
| * 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 com.google.auto.service.AutoService; | ||
| import com.google.common.annotations.VisibleForTesting; | ||
| import io.opentelemetry.javaagent.extension.AgentListener; | ||
| import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; | ||
| import java.util.function.Function; | ||
|
|
||
| @AutoService(AgentListener.class) | ||
| public class SnapshotProfilingAgentListener implements AgentListener { | ||
| private final Function<AutoConfiguredOpenTelemetrySdk, SnapshotProfilingSupervisor> | ||
| snapshotProfilingSupervisorMaker; | ||
|
|
||
| public SnapshotProfilingAgentListener() { | ||
| this(SnapshotProfilingSupervisor::initialize); | ||
| } | ||
|
|
||
| @VisibleForTesting | ||
| SnapshotProfilingAgentListener( | ||
| Function<AutoConfiguredOpenTelemetrySdk, SnapshotProfilingSupervisor> | ||
| snapshotProfilingSupervisorMaker) { | ||
| this.snapshotProfilingSupervisorMaker = snapshotProfilingSupervisorMaker; | ||
| } | ||
|
|
||
| @Override | ||
| public void afterAgent(AutoConfiguredOpenTelemetrySdk sdk) { | ||
| // Must be always executed to initialize supervisor | ||
| SnapshotProfilingSupervisor supervisor = snapshotProfilingSupervisorMaker.apply(sdk); | ||
|
|
||
| SnapshotProfilingConfiguration configuration = SnapshotProfilingConfiguration.SUPPLIER.get(); | ||
| if (!configuration.isEnabled()) { | ||
| return; | ||
| } | ||
|
|
||
| supervisor.startProfiling(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -49,19 +49,12 @@ OpenTelemetryConfigurationModel customizeModel(OpenTelemetryConfigurationModel m | |
| SnapshotProfilingConfiguration snapshotProfiling = getSnapshotProfilingConfig(model); | ||
| SnapshotProfilingConfiguration.SUPPLIER.configure(snapshotProfiling); | ||
|
|
||
| if (snapshotProfiling.isEnabled()) { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [for reviewer] We always setup some components that must be created during sdk initialization, and later on they are enabled or disabled by |
||
| initActiveSpansTracking(); | ||
| initStackTraceSampler(snapshotProfiling); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [for reviewer] |
||
| addSpanProcessors(model); | ||
| } | ||
| initActiveSpansTracking(); | ||
| addSpanProcessors(model); | ||
|
|
||
| return model; | ||
| } | ||
|
|
||
| private void initStackTraceSampler(SnapshotProfilingConfiguration snapshotProfilingConfig) { | ||
| StackTraceSamplerInitializer.setupStackTraceSampler(snapshotProfilingConfig); | ||
| } | ||
|
|
||
| private void addSpanProcessors(OpenTelemetryConfigurationModel model) { | ||
| TracerProviderModel tracerProviderModel = model.getTracerProvider(); | ||
| if (tracerProviderModel == null) { | ||
|
|
||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [for reviewer] Like in SnapshotProfilingConfigurationCustomizerProvider, we always preconfigure some components that later can be enabled or disabled by |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,56 +22,24 @@ | |
| import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider; | ||
| import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; | ||
| import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder; | ||
| import java.time.Duration; | ||
| import java.util.Collections; | ||
| import java.util.Map; | ||
| import java.util.Set; | ||
| import java.util.function.BiFunction; | ||
| import java.util.function.Function; | ||
|
|
||
| @AutoService(AutoConfigurationCustomizerProvider.class) | ||
| public class SnapshotProfilingSdkCustomizer implements AutoConfigurationCustomizerProvider { | ||
| private final TraceRegistry registry; | ||
| private final Function<ConfigProperties, StackTraceSampler> samplerProvider; | ||
| private final ContextStorageWrapper contextStorageWrapper; | ||
|
|
||
| public SnapshotProfilingSdkCustomizer() { | ||
| this( | ||
| TraceRegistryHolder.getTraceRegistry(), | ||
| stackTraceSamplerProvider(), | ||
| new ContextStorageWrapper()); | ||
| } | ||
|
|
||
| private static Function<ConfigProperties, StackTraceSampler> stackTraceSamplerProvider() { | ||
| return properties -> { | ||
| SnapshotProfilingConfiguration configuration = SnapshotProfilingConfiguration.SUPPLIER.get(); | ||
| Duration samplingPeriod = configuration.getSamplingInterval(); | ||
| StagingArea.SUPPLIER.configure(createStagingArea(configuration)); | ||
| return new PeriodicStackTraceSampler( | ||
| StagingArea.SUPPLIER, SpanTracker.SUPPLIER, samplingPeriod); | ||
| }; | ||
| } | ||
|
|
||
| private static StagingArea createStagingArea(SnapshotProfilingConfiguration configuration) { | ||
| Duration interval = configuration.getExportInterval(); | ||
| int capacity = configuration.getStagingCapacity(); | ||
| return new PeriodicallyExportingStagingArea(StackTraceExporter.SUPPLIER, interval, capacity); | ||
| this(TraceRegistryHolder.getTraceRegistry(), new ContextStorageWrapper()); | ||
| } | ||
|
|
||
| @VisibleForTesting | ||
| SnapshotProfilingSdkCustomizer( | ||
| TraceRegistry registry, | ||
| StackTraceSampler sampler, | ||
| ContextStorageWrapper contextStorageWrapper) { | ||
| this(registry, properties -> sampler, contextStorageWrapper); | ||
| } | ||
|
|
||
| private SnapshotProfilingSdkCustomizer( | ||
| TraceRegistry registry, | ||
| Function<ConfigProperties, StackTraceSampler> samplerProvider, | ||
| ContextStorageWrapper contextStorageWrapper) { | ||
| TraceRegistry registry, ContextStorageWrapper contextStorageWrapper) { | ||
| this.registry = registry; | ||
| this.samplerProvider = samplerProvider; | ||
| this.contextStorageWrapper = contextStorageWrapper; | ||
| } | ||
|
|
||
|
|
@@ -82,7 +50,6 @@ public void customize(AutoConfigurationCustomizer autoConfigurationCustomizer) { | |
|
|
||
| autoConfigurationCustomizer | ||
| .addTracerProviderCustomizer(snapshotProfilingSpanProcessor(registry)) | ||
| .addPropertiesCustomizer(setupStackTraceSampler()) | ||
| .addPropertiesCustomizer(startTrackingActiveSpans(registry)) | ||
| .addTracerProviderCustomizer(addShutdownHook()); | ||
| } | ||
|
|
@@ -99,54 +66,28 @@ public void customize(AutoConfigurationCustomizer autoConfigurationCustomizer) { | |
| private BiFunction<SdkTracerProviderBuilder, ConfigProperties, SdkTracerProviderBuilder> | ||
| addShutdownHook() { | ||
| return (builder, properties) -> { | ||
| if (snapshotProfilingEnabled()) { | ||
| builder.addSpanProcessor(new SdkShutdownHook()); | ||
| } | ||
| builder.addSpanProcessor(new SdkShutdownHook()); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [for reviewer] It is safe to call |
||
| return builder; | ||
| }; | ||
| } | ||
|
|
||
| private BiFunction<SdkTracerProviderBuilder, ConfigProperties, SdkTracerProviderBuilder> | ||
| snapshotProfilingSpanProcessor(TraceRegistry registry) { | ||
| return (builder, properties) -> { | ||
| if (snapshotProfilingEnabled()) { | ||
| double selectionProbability = | ||
| SnapshotProfilingConfiguration.SUPPLIER.get().getSnapshotSelectionProbability(); | ||
|
|
||
| return builder.addSpanProcessor( | ||
| new SnapshotProfilingSpanProcessor( | ||
| registry, new TraceIdBasedSnapshotSelector(selectionProbability))); | ||
| } | ||
| return builder; | ||
| }; | ||
| } | ||
|
|
||
| private boolean includeTraceContextPropagator(Set<String> configuredPropagators) { | ||
| return configuredPropagators.isEmpty(); | ||
| } | ||
| double selectionProbability = | ||
| SnapshotProfilingConfiguration.SUPPLIER.get().getSnapshotSelectionProbability(); | ||
|
|
||
| private Function<ConfigProperties, Map<String, String>> setupStackTraceSampler() { | ||
| return properties -> { | ||
| if (snapshotProfilingEnabled()) { | ||
| StackTraceSampler sampler = samplerProvider.apply(properties); | ||
| ConfigurableSupplier<StackTraceSampler> supplier = StackTraceSampler.SUPPLIER; | ||
| supplier.configure(sampler); | ||
| } | ||
| return Collections.emptyMap(); | ||
| return builder.addSpanProcessor( | ||
| new SnapshotProfilingSpanProcessor( | ||
| registry, new TraceIdBasedSnapshotSelector(selectionProbability))); | ||
| }; | ||
| } | ||
|
|
||
| private Function<ConfigProperties, Map<String, String>> startTrackingActiveSpans( | ||
| TraceRegistry registry) { | ||
| return properties -> { | ||
| if (snapshotProfilingEnabled()) { | ||
| contextStorageWrapper.wrapContextStorage(registry); | ||
| } | ||
| contextStorageWrapper.wrapContextStorage(registry); | ||
| return Collections.emptyMap(); | ||
| }; | ||
| } | ||
|
|
||
| private boolean snapshotProfilingEnabled() { | ||
| return SnapshotProfilingConfiguration.SUPPLIER.get().isEnabled(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| /* | ||
| * 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 com.google.common.annotations.VisibleForTesting; | ||
| import com.splunk.opentelemetry.profiler.OtelLoggerFactory; | ||
| import com.splunk.opentelemetry.profiler.util.OptionalConfigurableSupplier; | ||
| import io.opentelemetry.sdk.autoconfigure.AutoConfigureUtil; | ||
| import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; | ||
| import java.util.logging.Logger; | ||
|
|
||
| public class SnapshotProfilingSupervisor { | ||
| public static final OptionalConfigurableSupplier<SnapshotProfilingSupervisor> SUPPLIER = | ||
| new OptionalConfigurableSupplier<>(); | ||
| private static final Logger logger = | ||
| Logger.getLogger(SnapshotProfilingSupervisor.class.getName()); | ||
|
|
||
| private final OptionalConfigurableSupplier<SnapshotProfilingConfiguration> configurationSupplier; | ||
| private final ConfigurableSupplier<SpanTracker> spanTrackerSupplier; | ||
| private final OptionalConfigurableSupplier<TraceThreadChangeDetector> | ||
| traceThreadChangeDetectorSupplier; | ||
| private final AutoConfiguredOpenTelemetrySdk sdk; | ||
| private final OtelLoggerFactory otelLoggerFactory; | ||
| private boolean running; | ||
|
|
||
| @VisibleForTesting | ||
| SnapshotProfilingSupervisor( | ||
| OptionalConfigurableSupplier<SnapshotProfilingConfiguration> configurationSupplier, | ||
| ConfigurableSupplier<SpanTracker> spanTrackerSupplier, | ||
| OptionalConfigurableSupplier<TraceThreadChangeDetector> traceThreadChangeDetectorSupplier, | ||
| AutoConfiguredOpenTelemetrySdk sdk, | ||
| OtelLoggerFactory otelLoggerFactory) { | ||
| this.configurationSupplier = configurationSupplier; | ||
| this.spanTrackerSupplier = spanTrackerSupplier; | ||
| this.traceThreadChangeDetectorSupplier = traceThreadChangeDetectorSupplier; | ||
| this.sdk = sdk; | ||
| this.otelLoggerFactory = otelLoggerFactory; | ||
| } | ||
|
|
||
| public static SnapshotProfilingSupervisor initialize(AutoConfiguredOpenTelemetrySdk sdk) { | ||
| if (SUPPLIER.isConfigured()) { | ||
| throw new IllegalStateException("Snapshot profiling already initialized"); | ||
| } | ||
|
|
||
| SnapshotProfilingSupervisor supervisor = | ||
| new SnapshotProfilingSupervisor( | ||
| SnapshotProfilingConfiguration.SUPPLIER, | ||
| SpanTracker.SUPPLIER, | ||
| TraceThreadChangeDetector.SUPPLIER, | ||
| sdk, | ||
| new OtelLoggerFactory()); | ||
| SUPPLIER.configure(supervisor); | ||
|
|
||
| return supervisor; | ||
| } | ||
|
|
||
| public synchronized void startProfiling() { | ||
| if (running) { | ||
| return; | ||
| } | ||
|
|
||
| configurationSupplier.get().log(); | ||
|
|
||
| // StagingArea.SUPPLIER | ||
| // StackTraceSampler.SUPPLIER | ||
| // StackTraceExporter.SUPPLIER = AsyncStackTraceExporter | ||
| StackTraceSamplerInitializer.setupStackTraceSampler(configurationSupplier.get()); | ||
| StackTraceSamplerInitializer.setupStackTraceExporter( | ||
| configurationSupplier.get(), AutoConfigureUtil.getResource(sdk), otelLoggerFactory); | ||
|
|
||
| // SpanTracker.SUPPLIER | ||
| spanTrackerSupplier.get().setEnabled(true); | ||
| traceThreadChangeDetectorSupplier.get().setEnabled(true); | ||
|
|
||
| // SnapshotProfilingSdkCustomizer/SnapshotProfilingSpanProcessorComponentProvider -> | ||
| // SnapshotProfilingSpanProcessor | ||
| // SdkShutdownHookComponentProvider -> SdkShutdownHook | ||
|
|
||
| running = true; | ||
| logger.info("Snapshot profiling is active."); | ||
| } | ||
|
|
||
| public synchronized void stopProfiling() { | ||
| if (!running) { | ||
| return; | ||
| } | ||
|
|
||
| StackTraceSampler.SUPPLIER.get().close(); | ||
| StackTraceSampler.SUPPLIER.reset(); | ||
|
|
||
| StagingArea.SUPPLIER.get().close(); | ||
| StagingArea.SUPPLIER.reset(); | ||
|
|
||
| StackTraceExporter.SUPPLIER.get().close(); | ||
| StackTraceExporter.SUPPLIER.reset(); | ||
|
|
||
| SpanTracker.SUPPLIER.get().setEnabled(false); | ||
| TraceThreadChangeDetector.SUPPLIER.get().setEnabled(false); | ||
|
|
||
| running = false; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[for reviewer]
ActiveSpanTrackeris always created during SDK initialization and can be turned on and off bySnapshotProfilingSupervisor