Skip to content

Commit ba10f8d

Browse files
[File based config] Snapshot profiling config refactoring (signalfx#2558)
* Support for distribution node in YAML Refactoring profiler config methods to use config from the instance property, not form argument * Spotless * Comments updated * Comments updated * Tests updated * Spotless * Update profiler/src/main/java/com/splunk/opentelemetry/profiler/JfrActivator.java Co-authored-by: jason plumb <75337021+breedx-splk@users.noreply.github.com> * Code review followup * GDI spec changes applied * Snapshot profiling configuration refactored to use instance methods. Update of profiling config YAML structure. Fixes for invalid snapshot profiling configuration YAML node extraction Initial exporter configuration for snapshot profiling * Spotless apply * StackTraceInitializer refactoring * Fixed YAMLs in some unit tests * isDeclarativeConfig fix * spotless * Grpc profiler log exporter fixed * After merge followup * After merge followup * Defaults moved to the interface --------- Co-authored-by: jason plumb <75337021+breedx-splk@users.noreply.github.com>
1 parent 964320a commit ba10f8d

30 files changed

+1144
-608
lines changed

custom/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfigureUtil.java

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,17 @@
2222
import io.opentelemetry.api.incubator.ExtendedOpenTelemetry;
2323
import io.opentelemetry.api.incubator.config.ConfigProvider;
2424
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
25+
import io.opentelemetry.common.ComponentLoader;
2526
import io.opentelemetry.instrumentation.config.bridge.ConfigPropertiesBackedConfigProvider;
2627
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
28+
import io.opentelemetry.sdk.extension.incubator.fileconfig.YamlDeclarativeConfigProperties;
29+
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalInstrumentationModel;
30+
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalLanguageSpecificInstrumentationModel;
31+
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalLanguageSpecificInstrumentationPropertyModel;
32+
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel;
2733
import io.opentelemetry.sdk.resources.Resource;
34+
import java.util.HashMap;
35+
import java.util.Map;
2836
import java.util.logging.Logger;
2937
import javax.annotation.Nullable;
3038

@@ -57,6 +65,8 @@ public static boolean isDeclarativeConfig(AutoConfiguredOpenTelemetrySdk sdk) {
5765
return false;
5866
}
5967

68+
// TODO: This is temporary solution. For now assume that distribution node is located under
69+
// .instrumentation/development.java.distribution
6070
@Nullable
6171
public static DeclarativeConfigProperties getDistributionConfig(
6272
AutoConfiguredOpenTelemetrySdk sdk) {
@@ -69,18 +79,38 @@ public static DeclarativeConfigProperties getDistributionConfig(
6979
return null;
7080
}
7181

72-
// TODO: This is temporary solution until distribution config support is implemented in the
73-
// upstream. For now assume that distribution node is located under
74-
// .instrumentation/development.java.distribution
75-
// Replace this code with `return sdk.getConfigProvider().getDistributionConfig()` once is
76-
// implemented
7782
DeclarativeConfigProperties instrumentationConfig = configProvider.getInstrumentationConfig();
7883
if (instrumentationConfig == null) {
7984
return null;
8085
}
81-
return instrumentationConfig
82-
.getStructured("java", empty())
83-
.getStructured("distribution", empty());
86+
return instrumentationConfig.getStructured("java", empty()).getStructured("distribution");
87+
}
88+
89+
public static DeclarativeConfigProperties getDistributionConfig(
90+
OpenTelemetryConfigurationModel model) {
91+
ExperimentalInstrumentationModel instrumentationModel = model.getInstrumentationDevelopment();
92+
if (instrumentationModel == null) {
93+
return empty();
94+
}
95+
96+
ExperimentalLanguageSpecificInstrumentationModel javaModel = instrumentationModel.getJava();
97+
if (javaModel == null) {
98+
return empty();
99+
}
100+
101+
ComponentLoader componentLoader =
102+
ComponentLoader.forClassLoader(DeclarativeConfigProperties.class.getClassLoader());
103+
Map<String, ExperimentalLanguageSpecificInstrumentationPropertyModel> original =
104+
javaModel.getAdditionalProperties();
105+
Map<String, Object> properties = new HashMap<>();
106+
ExperimentalLanguageSpecificInstrumentationPropertyModel distribution =
107+
original.get("distribution");
108+
properties.put(
109+
"distribution", distribution != null ? distribution.getAdditionalProperties() : null);
110+
DeclarativeConfigProperties config =
111+
YamlDeclarativeConfigProperties.create(properties, componentLoader);
112+
113+
return config.getStructured("distribution", empty()); // Should this empty() be there?
84114
}
85115

86116
public static Resource getResource(AutoConfiguredOpenTelemetrySdk sdk) {

profiler/src/main/java/com/splunk/opentelemetry/profiler/JfrActivator.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,7 @@ private static ProfilerConfiguration getProfilerConfiguration(
8989
DeclarativeConfigProperties distributionConfig = AutoConfigureUtil.getDistributionConfig(sdk);
9090
distributionConfig = Optional.ofNullable(distributionConfig).orElse(empty());
9191
return new ProfilerDeclarativeConfiguration(
92-
distributionConfig
93-
.getStructured("splunk", empty())
94-
.getStructured("profiling", empty())
95-
.getStructured("always_on", empty()));
92+
distributionConfig.getStructured("splunk", empty()).getStructured("profiling", empty()));
9693
} else {
9794
ConfigProperties configProperties = AutoConfigureUtil.getConfig(sdk);
9895
return new ProfilerEnvVarsConfiguration(configProperties);

profiler/src/main/java/com/splunk/opentelemetry/profiler/LogExporterBuilder.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter;
2424
import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporterBuilder;
2525
import io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil;
26+
import io.opentelemetry.exporter.otlp.internal.OtlpGrpcLogRecordExporterComponentProvider;
2627
import io.opentelemetry.exporter.otlp.internal.OtlpHttpLogRecordExporterComponentProvider;
2728
import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter;
2829
import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporterBuilder;
@@ -39,17 +40,19 @@ class LogExporterBuilder {
3940
static LogRecordExporter fromConfig(DeclarativeConfigProperties exporterConfigProperties) {
4041
if (exporterConfigProperties != null) {
4142

42-
DeclarativeConfigProperties otlpHttp = exporterConfigProperties.getStructured("otlp_http");
43+
DeclarativeConfigProperties otlpHttp =
44+
exporterConfigProperties.getStructured("otlp_log_http");
4345
if (otlpHttp != null) {
4446
OtlpHttpLogRecordExporterComponentProvider provider =
4547
new OtlpHttpLogRecordExporterComponentProvider();
4648
return provider.create(otlpHttp);
4749
}
4850

49-
DeclarativeConfigProperties otlpGrpc = exporterConfigProperties.getStructured("otlp_grpc");
51+
DeclarativeConfigProperties otlpGrpc =
52+
exporterConfigProperties.getStructured("otlp_log_grpc");
5053
if (otlpGrpc != null) {
51-
OtlpHttpLogRecordExporterComponentProvider provider =
52-
new OtlpHttpLogRecordExporterComponentProvider();
54+
OtlpGrpcLogRecordExporterComponentProvider provider =
55+
new OtlpGrpcLogRecordExporterComponentProvider();
5356
return provider.create(otlpGrpc);
5457
}
5558
}

profiler/src/main/java/com/splunk/opentelemetry/profiler/OtelLoggerFactory.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.splunk.opentelemetry.profiler;
1818

1919
import com.google.common.annotations.VisibleForTesting;
20+
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
2021
import io.opentelemetry.api.logs.Logger;
2122
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
2223
import io.opentelemetry.sdk.logs.LogRecordProcessor;
@@ -28,14 +29,19 @@
2829

2930
public class OtelLoggerFactory {
3031
private final Function<ConfigProperties, LogRecordExporter> logRecordExporter;
32+
private final Function<DeclarativeConfigProperties, LogRecordExporter>
33+
declarativeLogRecordExporter;
3134

3235
public OtelLoggerFactory() {
33-
this(LogExporterBuilder::fromConfig);
36+
this(LogExporterBuilder::fromConfig, LogExporterBuilder::fromConfig);
3437
}
3538

3639
@VisibleForTesting
37-
public OtelLoggerFactory(Function<ConfigProperties, LogRecordExporter> logRecordExporter) {
40+
public OtelLoggerFactory(
41+
Function<ConfigProperties, LogRecordExporter> logRecordExporter,
42+
Function<DeclarativeConfigProperties, LogRecordExporter> declarativeLogRecordExporter) {
3843
this.logRecordExporter = logRecordExporter;
44+
this.declarativeLogRecordExporter = declarativeLogRecordExporter;
3945
}
4046

4147
public Logger build(ConfigProperties properties, Resource resource) {
@@ -44,10 +50,20 @@ public Logger build(ConfigProperties properties, Resource resource) {
4450
return buildOtelLogger(processor, resource);
4551
}
4652

53+
public Logger build(DeclarativeConfigProperties properties, Resource resource) {
54+
LogRecordExporter exporter = createLogRecordExporter(properties);
55+
LogRecordProcessor processor = SimpleLogRecordProcessor.create(exporter);
56+
return buildOtelLogger(processor, resource);
57+
}
58+
4759
private LogRecordExporter createLogRecordExporter(ConfigProperties properties) {
4860
return logRecordExporter.apply(properties);
4961
}
5062

63+
private LogRecordExporter createLogRecordExporter(DeclarativeConfigProperties properties) {
64+
return declarativeLogRecordExporter.apply(properties);
65+
}
66+
5167
private Logger buildOtelLogger(LogRecordProcessor logProcessor, Resource resource) {
5268
return SdkLoggerProvider.builder()
5369
.addLogRecordProcessor(logProcessor)

profiler/src/main/java/com/splunk/opentelemetry/profiler/ProfilerDeclarativeConfiguration.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,24 @@ public class ProfilerDeclarativeConfiguration implements ProfilerConfiguration {
2727
private static final Logger logger =
2828
Logger.getLogger(ProfilerDeclarativeConfiguration.class.getName());
2929

30+
private static final String ROOT_NODE_NAME = "always_on";
31+
3032
private static final String DEFAULT_PROFILER_DIRECTORY = System.getProperty("java.io.tmpdir");
3133
private static final long DEFAULT_RECORDING_DURATION = Duration.ofSeconds(20).toMillis();
3234
private static final long DEFAULT_SAMPLING_INTERVAL = Duration.ofSeconds(10).toMillis();
3335

3436
private static final String MEMORY_PROFILER = "memory_profiler";
3537
private static final String MEMORY_EVENT_RATE = "event_rate";
3638

37-
private final DeclarativeConfigProperties config;
39+
private final DeclarativeConfigProperties profilingConfig;
3840

39-
public ProfilerDeclarativeConfiguration(DeclarativeConfigProperties config) {
40-
this.config = config;
41+
public ProfilerDeclarativeConfiguration(DeclarativeConfigProperties profilingConfig) {
42+
this.profilingConfig = profilingConfig;
4143
}
4244

4345
@Override
4446
public boolean isEnabled() {
45-
return !config.equals(empty());
47+
return (profilingConfig != null) && profilingConfig.getPropertyKeys().contains(ROOT_NODE_NAME);
4648
}
4749

4850
@Override
@@ -127,7 +129,7 @@ public boolean getTracingStacksOnly() {
127129

128130
@Override
129131
public int getStackDepth() {
130-
return getConfigRoot().getInt("stack_depth_limit", 1024);
132+
return getConfigRoot().getInt("stack_depth", 1024);
131133
}
132134

133135
@Override
@@ -147,11 +149,11 @@ public Duration getRecordingDuration() {
147149

148150
@Override
149151
public DeclarativeConfigProperties getConfigProperties() {
150-
return config;
152+
return profilingConfig;
151153
}
152154

153155
private DeclarativeConfigProperties getConfigRoot() {
154-
return config.getStructured("always_on", empty());
156+
return profilingConfig.getStructured(ROOT_NODE_NAME, empty());
155157
}
156158

157159
private DeclarativeConfigProperties getMemoryProfilerConfig() {

profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/AsyncStackTraceExporter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class AsyncStackTraceExporter implements StackTraceExporter {
4343

4444
@Override
4545
public void export(Collection<StackTrace> stackTraces) {
46-
if (closed) {
46+
if (closed || stackTraces.isEmpty()) {
4747
return;
4848
}
4949
executor.submit(pprofExporter(otelLogger, stackTraces));

profiler/src/main/java/com/splunk/opentelemetry/profiler/snapshot/SnapshotProfilingConfiguration.java

Lines changed: 50 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -16,102 +16,70 @@
1616

1717
package com.splunk.opentelemetry.profiler.snapshot;
1818

19+
import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty;
20+
21+
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
22+
import io.opentelemetry.sdk.autoconfigure.AutoConfigureUtil;
23+
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
1924
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
2025
import java.time.Duration;
26+
import java.util.Optional;
2127
import java.util.logging.Logger;
2228

23-
public class SnapshotProfilingConfiguration {
24-
private static final Logger logger =
25-
Logger.getLogger(SnapshotProfilingConfiguration.class.getName());
29+
public interface SnapshotProfilingConfiguration {
30+
double MAX_SELECTION_PROBABILITY = 1.0;
31+
double DEFAULT_SELECTION_PROBABILITY = 0.01;
32+
int DEFAULT_STACK_DEPTH = 1024;
33+
long DEFAULT_SAMPLING_INTERVAL = 10;
34+
long DEFAULT_EXPORT_INTERVAL = 5000;
35+
int DEFAULT_STAGING_CAPACITY = 2000;
2636

27-
public static final String CONFIG_KEY_ENABLE_SNAPSHOT_PROFILER =
28-
"splunk.snapshot.profiler.enabled";
29-
private static final String SELECTION_PROBABILITY_KEY = "splunk.snapshot.selection.probability";
30-
private static final String STACK_DEPTH_KEY = "splunk.snapshot.profiler.max.stack.depth";
31-
private static final String SAMPLING_INTERVAL_KEY = "splunk.snapshot.sampling.interval";
32-
private static final String EXPORT_INTERVAL_KEY = "splunk.snapshot.profiler.export.interval";
33-
private static final String STAGING_CAPACITY_KEY = "splunk.snapshot.profiler.staging.capacity";
37+
void log();
3438

35-
private static final double DEFAULT_SELECTION_PROBABILITY = 0.01;
36-
private static final double MAX_SELECTION_PROBABILITY = 1.0;
37-
private static final int DEFAULT_STACK_DEPTH = 1024;
38-
private static final Duration DEFAULT_SAMPLING_INTERVAL = Duration.ofMillis(10);
39-
private static final Duration DEFAULT_EXPORT_INTERVAL = Duration.ofSeconds(5);
40-
private static final int DEFAULT_STAGING_CAPACITY = 2000;
39+
boolean isEnabled();
4140

42-
static void log(ConfigProperties properties) {
43-
logger.fine("Snapshot Profiler Configuration:");
44-
logger.fine("-------------------------------------------------------");
41+
double getSnapshotSelectionProbability();
4542

46-
log(CONFIG_KEY_ENABLE_SNAPSHOT_PROFILER, isSnapshotProfilingEnabled(properties));
47-
log(SELECTION_PROBABILITY_KEY, getSnapshotSelectionProbability(properties));
48-
log(STACK_DEPTH_KEY, getStackDepth(properties));
49-
log(SAMPLING_INTERVAL_KEY, getSamplingInterval(properties));
50-
log(EXPORT_INTERVAL_KEY, getExportInterval(properties));
51-
log(STAGING_CAPACITY_KEY, getStagingCapacity(properties));
52-
logger.fine("-------------------------------------------------------");
53-
}
43+
int getStackDepth();
5444

55-
static boolean isSnapshotProfilingEnabled(ConfigProperties properties) {
56-
return properties.getBoolean(CONFIG_KEY_ENABLE_SNAPSHOT_PROFILER, false);
57-
}
45+
Duration getSamplingInterval();
5846

59-
static double getSnapshotSelectionProbability(ConfigProperties properties) {
60-
String selectionProbabilityPropertyValue =
61-
properties.getString(
62-
SELECTION_PROBABILITY_KEY, String.valueOf(DEFAULT_SELECTION_PROBABILITY));
63-
try {
64-
double selectionProbability = Double.parseDouble(selectionProbabilityPropertyValue);
65-
if (selectionProbability > MAX_SELECTION_PROBABILITY) {
66-
logger.warning(
67-
"Configured snapshot selection probability of '"
68-
+ selectionProbabilityPropertyValue
69-
+ "' is higher than the maximum allowed probability. Using maximum allowed snapshot selection probability of '"
70-
+ MAX_SELECTION_PROBABILITY
71-
+ "'");
72-
return MAX_SELECTION_PROBABILITY;
73-
}
74-
if (selectionProbability <= 0) {
75-
logger.warning(
76-
"Snapshot selection probability must be greater than 0. Using default snapshot"
77-
+ "selection probability of '"
78-
+ DEFAULT_SELECTION_PROBABILITY
79-
+ "' instead.");
80-
return DEFAULT_SELECTION_PROBABILITY;
81-
}
82-
return selectionProbability;
83-
} catch (NumberFormatException e) {
84-
logger.warning(
85-
"Invalid snapshot selection probability: '"
86-
+ selectionProbabilityPropertyValue
87-
+ "', using default probability of '"
88-
+ DEFAULT_SELECTION_PROBABILITY
89-
+ "'");
90-
return DEFAULT_SELECTION_PROBABILITY;
91-
}
92-
}
47+
Duration getExportInterval();
9348

94-
static int getStackDepth(ConfigProperties properties) {
95-
return properties.getInt(STACK_DEPTH_KEY, DEFAULT_STACK_DEPTH);
96-
}
49+
int getStagingCapacity();
9750

98-
static Duration getSamplingInterval(ConfigProperties properties) {
99-
return properties.getDuration(SAMPLING_INTERVAL_KEY, DEFAULT_SAMPLING_INTERVAL);
100-
}
51+
Object getConfigProperties();
10152

102-
static Duration getExportInterval(ConfigProperties properties) {
103-
return properties.getDuration(EXPORT_INTERVAL_KEY, DEFAULT_EXPORT_INTERVAL);
104-
}
105-
106-
static int getStagingCapacity(ConfigProperties properties) {
107-
return properties.getInt(STAGING_CAPACITY_KEY, DEFAULT_STAGING_CAPACITY);
108-
}
109-
110-
private static void log(String key, Object value) {
111-
logger.fine(" " + pad(key) + " : " + value);
53+
static SnapshotProfilingConfiguration fromSdk(AutoConfiguredOpenTelemetrySdk sdk) {
54+
if (AutoConfigureUtil.isDeclarativeConfig(sdk)) {
55+
DeclarativeConfigProperties distributionConfig = AutoConfigureUtil.getDistributionConfig(sdk);
56+
distributionConfig = Optional.ofNullable(distributionConfig).orElse(empty());
57+
return new SnapshotProfilingDeclarativeConfiguration(
58+
distributionConfig.getStructured("splunk", empty()).getStructured("profiling", empty()));
59+
} else {
60+
ConfigProperties configProperties = AutoConfigureUtil.getConfig(sdk);
61+
return new SnapshotProfilingEnvVarsConfiguration(configProperties);
62+
}
11263
}
11364

114-
private static String pad(String str) {
115-
return String.format("%42s", str);
65+
static double validateSelectionProbability(double selectionProbability, Logger logger) {
66+
if (selectionProbability > MAX_SELECTION_PROBABILITY) {
67+
logger.warning(
68+
"Configured snapshot selection probability of '"
69+
+ selectionProbability
70+
+ "' is higher than the maximum allowed probability. Using maximum allowed snapshot selection probability of '"
71+
+ MAX_SELECTION_PROBABILITY
72+
+ "'");
73+
return MAX_SELECTION_PROBABILITY;
74+
}
75+
if (selectionProbability <= 0) {
76+
logger.warning(
77+
"Snapshot selection probability must be greater than 0. Using default snapshot"
78+
+ "selection probability of '"
79+
+ DEFAULT_SELECTION_PROBABILITY
80+
+ "' instead.");
81+
return DEFAULT_SELECTION_PROBABILITY;
82+
}
83+
return selectionProbability;
11684
}
11785
}

0 commit comments

Comments
 (0)