Skip to content

Commit 277922e

Browse files
authored
1 parent 50ba6c4 commit 277922e

5 files changed

Lines changed: 94 additions & 8 deletions

File tree

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,14 @@
3030
import io.opentelemetry.exporter.otlp.internal.OtlpHttpLogRecordExporterComponentProvider;
3131
import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter;
3232
import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporterBuilder;
33+
import io.opentelemetry.sdk.autoconfigure.declarativeconfig.YamlDeclarativeConfigProperties;
3334
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
3435
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
3536
import io.opentelemetry.sdk.autoconfigure.spi.internal.ExtendedDeclarativeConfigProperties;
3637
import io.opentelemetry.sdk.logs.export.LogRecordExporter;
38+
import java.util.HashMap;
3739
import java.util.List;
40+
import java.util.Map;
3841
import java.util.Set;
3942
import java.util.function.Supplier;
4043
import javax.annotation.Nullable;
@@ -43,11 +46,18 @@ class LogExporterBuilder {
4346

4447
static final String EXTRA_CONTENT_TYPE = "Extra-Content-Type";
4548
static final String STACKTRACES_HEADER_VALUE = "otel-profiling-stacktraces";
49+
private static final String DEFAULT_HTTP_LOG_ENDPOINT = "http://localhost:4318/v1/logs";
4650

4751
static LogRecordExporter fromDeclarativeConfig(
4852
DeclarativeConfigProperties exporterConfigProperties) {
4953
if (exporterConfigProperties != null) {
5054
Set<String> propertyKeys = exporterConfigProperties.getPropertyKeys();
55+
if (propertyKeys.isEmpty()) {
56+
DeclarativeConfigProperties otlpHttp = defaultOtlpHttpConfig(exporterConfigProperties);
57+
OtlpHttpLogRecordExporterComponentProvider provider =
58+
new OtlpHttpLogRecordExporterComponentProvider();
59+
return provider.create(toExtended(otlpHttp));
60+
}
5161

5262
if (propertyKeys.contains("otlp_log_http")) {
5363
DeclarativeConfigProperties otlpHttp =
@@ -69,6 +79,16 @@ static LogRecordExporter fromDeclarativeConfig(
6979
throw new ConfigurationException("Profiler exporter configuration is invalid");
7080
}
7181

82+
private static DeclarativeConfigProperties defaultOtlpHttpConfig(
83+
DeclarativeConfigProperties exporterConfigProperties) {
84+
Map<String, Object> properties = new HashMap<>();
85+
properties.put("endpoint", DEFAULT_HTTP_LOG_ENDPOINT);
86+
properties.put("encoding", "protobuf");
87+
// Keep the original component loader so OTLP sender providers remain discoverable.
88+
return YamlDeclarativeConfigProperties.create(
89+
properties, exporterConfigProperties.getComponentLoader());
90+
}
91+
7292
static LogRecordExporter fromEnvironmentConfig() {
7393
ProfilerConfiguration config = ProfilerConfiguration.SUPPLIER.get();
7494
String protocol = config.getOtlpProtocol();

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package com.splunk.opentelemetry.profiler;
1818

19-
import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty;
2019
import static java.util.logging.Level.WARNING;
2120

2221
import com.splunk.opentelemetry.profiler.allocation.exporter.AllocationEventExporter;
@@ -25,6 +24,7 @@
2524
import com.splunk.opentelemetry.profiler.exporter.CpuEventExporter;
2625
import com.splunk.opentelemetry.profiler.exporter.PprofCpuEventExporter;
2726
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
27+
import io.opentelemetry.sdk.autoconfigure.declarativeconfig.YamlDeclarativeConfigProperties;
2828
import io.opentelemetry.sdk.logs.LogRecordProcessor;
2929
import io.opentelemetry.sdk.logs.SdkLoggerProvider;
3030
import io.opentelemetry.sdk.logs.export.LogRecordExporter;
@@ -35,6 +35,7 @@
3535
import java.nio.file.Path;
3636
import java.nio.file.Paths;
3737
import java.time.Duration;
38+
import java.util.Collections;
3839
import java.util.Map;
3940

4041
class PeriodicRecordingFlusherBuilder {
@@ -160,12 +161,24 @@ private StackTraceFilter buildStackTraceFilter(
160161
private static LogRecordExporter createLogRecordExporter(Object configProperties) {
161162
if (configProperties instanceof DeclarativeConfigProperties) {
162163
DeclarativeConfigProperties exporterConfig =
163-
((DeclarativeConfigProperties) configProperties).getStructured("exporter", empty());
164+
getExporterConfig((DeclarativeConfigProperties) configProperties);
164165
return LogExporterBuilder.fromDeclarativeConfig(exporterConfig);
165166
}
166167
return LogExporterBuilder.fromEnvironmentConfig();
167168
}
168169

170+
private static DeclarativeConfigProperties getExporterConfig(
171+
DeclarativeConfigProperties configProperties) {
172+
DeclarativeConfigProperties exporterConfig = configProperties.getStructured("exporter");
173+
if (exporterConfig != null) {
174+
return exporterConfig;
175+
}
176+
// DeclarativeConfigProperties.empty() is not used because it does not preserve the original
177+
// component loader that is used later when creating default exporter
178+
return YamlDeclarativeConfigProperties.create(
179+
Collections.emptyMap(), configProperties.getComponentLoader());
180+
}
181+
169182
private boolean checkOutputDir(Path outputDir) {
170183
if (!Files.exists(outputDir)) {
171184
// Try creating the directory for the user...

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

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,12 @@
1616

1717
package com.splunk.opentelemetry.profiler;
1818

19-
import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty;
20-
2119
import com.google.auto.service.AutoService;
2220
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
2321
import io.opentelemetry.sdk.autoconfigure.AutoConfigureUtil;
2422
import io.opentelemetry.sdk.autoconfigure.declarativeconfig.DeclarativeConfigurationCustomizer;
2523
import io.opentelemetry.sdk.autoconfigure.declarativeconfig.DeclarativeConfigurationCustomizerProvider;
24+
import io.opentelemetry.sdk.autoconfigure.declarativeconfig.YamlDeclarativeConfigProperties;
2625
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer;
2726
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider;
2827
import java.util.Collections;
@@ -45,8 +44,7 @@ public void customize(DeclarativeConfigurationCustomizer configurationCustomizer
4544
(model) -> {
4645
DeclarativeConfigProperties distributionConfig =
4746
AutoConfigureUtil.getDistributionConfig(model);
48-
DeclarativeConfigProperties profilingConfig =
49-
distributionConfig.getStructured("profiling", empty());
47+
DeclarativeConfigProperties profilingConfig = getProfilingConfig(distributionConfig);
5048

5149
ProfilerConfiguration.SUPPLIER.configure(
5250
ProfilerDeclarativeConfigurationFactory.create(profilingConfig));
@@ -70,4 +68,16 @@ public void customize(AutoConfigurationCustomizer autoConfiguration) {
7068
public int order() {
7169
return Integer.MAX_VALUE;
7270
}
71+
72+
private static DeclarativeConfigProperties getProfilingConfig(
73+
DeclarativeConfigProperties distributionConfig) {
74+
DeclarativeConfigProperties profilingConfig = distributionConfig.getStructured("profiling");
75+
if (profilingConfig != null) {
76+
return profilingConfig;
77+
}
78+
// DeclarativeConfigProperties.empty() is not used because it does not preserve the original
79+
// component loader that is used later when creating default exporter
80+
return YamlDeclarativeConfigProperties.create(
81+
Collections.emptyMap(), distributionConfig.getComponentLoader());
82+
}
7383
}

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

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

1919
import static io.opentelemetry.sdk.autoconfigure.AutoConfigureUtil.getResource;
20-
import static java.util.logging.Level.FINE;
20+
import static java.util.logging.Level.WARNING;
2121

2222
import com.google.common.annotations.VisibleForTesting;
2323
import com.splunk.opentelemetry.profiler.util.HelpfulExecutors;
@@ -92,7 +92,7 @@ private void commandLoop() {
9292
logger.fine("ProfilingSupervisor is shutting down");
9393
return;
9494
} catch (Exception e) {
95-
logger.log(FINE, "ProfilingSupervisor encountered an unexpected exception", e);
95+
logger.log(WARNING, "ProfilingSupervisor encountered an unexpected exception", e);
9696
}
9797
}
9898
}

profiler/src/test/java/com/splunk/opentelemetry/profiler/PeriodicRecordingFlusherBuilderTest.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,18 @@
2222
import static org.mockito.Mockito.verify;
2323
import static org.mockito.Mockito.when;
2424

25+
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
26+
import io.opentelemetry.common.ComponentLoader;
27+
import io.opentelemetry.sdk.autoconfigure.declarativeconfig.YamlDeclarativeConfigProperties;
2528
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
29+
import io.opentelemetry.sdk.common.export.HttpSenderProvider;
2630
import io.opentelemetry.sdk.resources.Resource;
2731
import java.nio.file.Files;
2832
import java.nio.file.Path;
2933
import java.time.Duration;
34+
import java.util.ArrayList;
35+
import java.util.Collections;
36+
import java.util.List;
3037
import java.util.Map;
3138
import org.junit.jupiter.api.AfterEach;
3239
import org.junit.jupiter.api.Test;
@@ -103,6 +110,26 @@ void buildContinuesWhenKeepFilesPathIsNotADirectory() throws Exception {
103110
}
104111
}
105112

113+
@Test
114+
void buildUsesProfilerConfigComponentLoaderWhenExporterNodeIsAbsent() {
115+
RecordingComponentLoader componentLoader = new RecordingComponentLoader();
116+
DeclarativeConfigProperties configProperties =
117+
YamlDeclarativeConfigProperties.create(Collections.emptyMap(), componentLoader);
118+
JFR jfr = mock(JFR.class);
119+
ProfilerConfiguration config = config(tempDir).setConfigProperties(configProperties).build();
120+
ProfilerConfiguration.SUPPLIER.configure(config);
121+
122+
try (MockedConstruction<JfrRecorder> recorderConstruction =
123+
mockConstruction(JfrRecorder.class)) {
124+
PeriodicRecordingFlusher sequencer =
125+
PeriodicRecordingFlusher.builder(config, Resource.empty()).jfr(jfr).build();
126+
127+
assertThat(sequencer).isNotNull();
128+
assertThat(recorderConstruction.constructed()).hasSize(1);
129+
assertThat(componentLoader.loaded(HttpSenderProvider.class)).isTrue();
130+
}
131+
}
132+
106133
private ProfilerConfiguration.Builder config(Path outputDir) {
107134
return ProfilerConfiguration.builder()
108135
.setEnabled(true)
@@ -118,4 +145,20 @@ private ProfilerConfiguration.Builder config(Path outputDir) {
118145
"otel.exporter.otlp.endpoint",
119146
"http://localhost:4318")));
120147
}
148+
149+
private static class RecordingComponentLoader implements ComponentLoader {
150+
private final ComponentLoader delegate =
151+
ComponentLoader.forClassLoader(PeriodicRecordingFlusherBuilderTest.class.getClassLoader());
152+
private final List<Class<?>> loadedSpiClasses = new ArrayList<>();
153+
154+
@Override
155+
public <T> Iterable<T> load(Class<T> spiClass) {
156+
loadedSpiClasses.add(spiClass);
157+
return delegate.load(spiClass);
158+
}
159+
160+
boolean loaded(Class<?> spiClass) {
161+
return loadedSpiClasses.contains(spiClass);
162+
}
163+
}
121164
}

0 commit comments

Comments
 (0)