-
Notifications
You must be signed in to change notification settings - Fork 45
Periodically Export Stacktraces From StagingArea #2298
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
Changes from all commits
23e6c9c
4dcbfeb
65922be
f291c53
2f631f8
5f13f30
7a3eb30
f7db0f1
1ca2291
1dd6131
55a58cd
fb83db2
0909970
4d03248
66dfc45
7e61fb1
7b48c90
28da0f8
ce6fde4
1327e7c
f798040
50b0b17
a45ff9b
6a0fa09
b7f8dea
ea9881c
b9ff741
b020a09
5d70bf9
1d293ab
c565d7f
37998fc
1c9dbda
4fc150b
3d630bb
96acf30
279cccb
421978b
960516e
07ea81f
b7378d3
1844b1f
9e7d1a4
feddbd5
fd0bb8e
1b2819a
e1141de
c27db01
677203c
39a5a90
2bb2c86
c0cb4a8
bb20b4c
3ecf6f9
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 |
|---|---|---|
|
|
@@ -81,6 +81,14 @@ public class Configuration implements AutoConfigurationCustomizerProvider { | |
| "splunk.snapshot.profiler.sampling.interval"; | ||
| private static final Duration DEFAULT_SNAPSHOT_PROFILER_SAMPLING_INTERVAL = Duration.ofMillis(10); | ||
|
|
||
| private static final String CONFIG_KEY_SNAPSHOT_PROFILER_EXPORT_INTERVAL = | ||
| "splunk.snapshot.profiler.export.interval"; | ||
| private static final Duration DEFAULT_SNAPSHOT_PROFILER_EXPORT_INTERVAL = Duration.ofSeconds(5); | ||
|
|
||
| private static final String CONFIG_KEY_SNAPSHOT_PROFILER_STAGING_CAPACITY = | ||
| "splunk.snapshot.profiler.staging.capacity"; | ||
| private static final int DEFAULT_SNAPSHOT_PROFILER_STAGING_CAPACITY = 2000; | ||
|
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. I don't have a reason for the chosen defaults. Happy to change them.
Collaborator
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. I think 2000 is reasonable for start. |
||
|
|
||
| @Override | ||
| public void customize(AutoConfigurationCustomizer autoConfiguration) { | ||
| autoConfiguration.addPropertiesSupplier(this::defaultProperties); | ||
|
|
@@ -228,4 +236,14 @@ public static Duration getSnapshotProfilerSamplingInterval(ConfigProperties prop | |
| CONFIG_KEY_SNAPSHOT_PROFILER_SAMPLING_INTERVAL, | ||
| DEFAULT_SNAPSHOT_PROFILER_SAMPLING_INTERVAL); | ||
| } | ||
|
|
||
| public static Duration getSnapshotProfilerExportInterval(ConfigProperties properties) { | ||
| return properties.getDuration( | ||
| CONFIG_KEY_SNAPSHOT_PROFILER_EXPORT_INTERVAL, DEFAULT_SNAPSHOT_PROFILER_EXPORT_INTERVAL); | ||
| } | ||
|
|
||
| public static int getSnapshotProfilerStagingCapacity(ConfigProperties properties) { | ||
| return properties.getInt( | ||
| CONFIG_KEY_SNAPSHOT_PROFILER_STAGING_CAPACITY, DEFAULT_SNAPSHOT_PROFILER_STAGING_CAPACITY); | ||
| } | ||
| } | ||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,133 @@ | ||
| /* | ||
| * 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 java.time.Duration; | ||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import java.util.concurrent.ArrayBlockingQueue; | ||
| import java.util.concurrent.BlockingQueue; | ||
| import java.util.concurrent.TimeUnit; | ||
| import java.util.function.Supplier; | ||
|
|
||
| class PeriodicallyExportingStagingArea implements StagingArea { | ||
laurit marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| private static final String WORKER_THREAD_NAME = | ||
| PeriodicallyExportingStagingArea.class.getSimpleName() + "_WorkerThread"; | ||
|
|
||
| private volatile boolean closed = false; | ||
|
|
||
| private final Worker worker; | ||
|
|
||
| PeriodicallyExportingStagingArea( | ||
| Supplier<StackTraceExporter> exporter, Duration delay, int capacity) { | ||
| worker = new Worker(exporter, delay, capacity); | ||
| worker.setName(WORKER_THREAD_NAME); | ||
| worker.setDaemon(true); | ||
| worker.start(); | ||
| } | ||
|
|
||
| @Override | ||
| public void stage(StackTrace stackTrace) { | ||
| if (closed) { | ||
| return; | ||
| } | ||
| worker.add(stackTrace); | ||
| } | ||
|
|
||
| @Override | ||
| public void empty() {} | ||
|
|
||
| @Override | ||
| public void close() { | ||
| this.closed = true; | ||
|
|
||
| // Wait for the worker thread to exit. Note that this does not guarantee that the pending items | ||
| // are exported as we don't attempt to wait for the actual export to complete. | ||
| try { | ||
| worker.shutdown(); | ||
| worker.join(); | ||
| } catch (InterruptedException exception) { | ||
| Thread.currentThread().interrupt(); | ||
| } | ||
| } | ||
|
|
||
| private static class Worker extends Thread { | ||
| // when shutting down we queue a fake stack trace to ensure that shutdown process starts | ||
| // immediately | ||
| private static final Object SHUTDOWN_MARKER = new Object(); | ||
|
|
||
| private final BlockingQueue<Object> queue; | ||
| private final Supplier<StackTraceExporter> exporter; | ||
| private final Duration delay; | ||
| private final int maxExportBatchSize; | ||
|
|
||
| private volatile boolean shutdown = false; | ||
| private long nextExportTime; | ||
|
|
||
| private Worker(Supplier<StackTraceExporter> exporter, Duration delay, int maxExportBatchSize) { | ||
| this.exporter = exporter; | ||
| this.delay = delay; | ||
| this.maxExportBatchSize = maxExportBatchSize; | ||
| // set the queue size to 4x the batch size, in sdk batch processors both of these are | ||
| // configurable but by default queue size is also 4*batch size | ||
| this.queue = new ArrayBlockingQueue<>(maxExportBatchSize * 4); | ||
|
|
||
| updateNextExportTime(); | ||
| } | ||
|
|
||
| void add(StackTrace stackTrace) { | ||
| // If queue is full drop the stack trace, not much we can do. | ||
| queue.offer(stackTrace); | ||
| } | ||
|
|
||
| @Override | ||
| public void run() { | ||
| List<StackTrace> stackTracesToExport = new ArrayList<>(); | ||
laurit marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| try { | ||
| // run until shutdown is called and all queued spans are passed to the exporter | ||
| while (!shutdown || !queue.isEmpty() || !stackTracesToExport.isEmpty()) { | ||
| Object stackTrace = queue.poll(nextExportTime - System.nanoTime(), TimeUnit.NANOSECONDS); | ||
| if (stackTrace != null && stackTrace != SHUTDOWN_MARKER) { | ||
| stackTracesToExport.add((StackTrace) stackTrace); | ||
| } | ||
| // trigger export when either next export time is reached, we have max batch size, or we | ||
| // are shutting down and have read all the queued stacks | ||
| if (System.nanoTime() >= nextExportTime | ||
| || stackTracesToExport.size() >= maxExportBatchSize | ||
| || (shutdown && queue.isEmpty())) { | ||
| exporter.get().export(stackTracesToExport); | ||
| stackTracesToExport = new ArrayList<>(); | ||
| updateNextExportTime(); | ||
| } | ||
| } | ||
| } catch (InterruptedException exception) { | ||
| Thread.currentThread().interrupt(); | ||
| } | ||
| } | ||
|
|
||
| private void updateNextExportTime() { | ||
| nextExportTime = System.nanoTime() + delay.toNanos(); | ||
| } | ||
|
|
||
| private void shutdown() throws InterruptedException { | ||
| shutdown = true; | ||
| // we don't care if the queue is full and offer fails, we only wish to ensure that there is | ||
| // something in the queue so that shutdown could start immediately | ||
| queue.offer(SHUTDOWN_MARKER); | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
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.
sdk uses
otel.bsp.max.export.batch.sizefor similar purpose