Skip to content

Commit 052587d

Browse files
committed
Lazy metrics
1 parent af0de7a commit 052587d

File tree

15 files changed

+228
-118
lines changed

15 files changed

+228
-118
lines changed

docs/apidiffs/current_vs_latest/opentelemetry-sdk-trace.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ Comparing source compatibility of opentelemetry-sdk-trace-1.58.0-SNAPSHOT.jar ag
22
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.trace.export.BatchSpanProcessorBuilder (not serializable)
33
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
44
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.trace.export.BatchSpanProcessorBuilder setInternalTelemetryVersion(io.opentelemetry.sdk.common.InternalTelemetryVersion)
5+
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.trace.export.BatchSpanProcessorBuilder setMeterProvider(java.util.function.Supplier<io.opentelemetry.api.metrics.MeterProvider>)
56
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.trace.export.SimpleSpanProcessorBuilder (not serializable)
67
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
7-
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.trace.export.SimpleSpanProcessorBuilder setMeterProvider(io.opentelemetry.api.metrics.MeterProvider)
8+
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.trace.export.SimpleSpanProcessorBuilder setMeterProvider(java.util.function.Supplier<io.opentelemetry.api.metrics.MeterProvider>)
89
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.trace.SdkTracerProviderBuilder (not serializable)
910
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
10-
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.trace.SdkTracerProviderBuilder setMeterProvider(io.opentelemetry.api.metrics.MeterProvider)
11+
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.trace.SdkTracerProviderBuilder setMeterProvider(java.util.function.Supplier<io.opentelemetry.api.metrics.MeterProvider>)

sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/TracerProviderConfiguration.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ static void configureTracerProvider(
4949
List<Closeable> closeables) {
5050

5151
tracerProviderBuilder.setSpanLimits(configureSpanLimits(config));
52-
tracerProviderBuilder.setMeterProvider(meterProvider);
52+
tracerProviderBuilder.setMeterProvider(() -> meterProvider);
5353

5454
String sampler = config.getString("otel.traces.sampler", PARENTBASED_ALWAYS_ON);
5555
tracerProviderBuilder.setSampler(
@@ -82,7 +82,7 @@ static List<SpanProcessor> configureSpanProcessors(
8282
SpanExporter exporter = exportersByNameCopy.remove(simpleProcessorExporterNames);
8383
if (exporter != null) {
8484
SpanProcessor spanProcessor =
85-
SimpleSpanProcessor.builder(exporter).setMeterProvider(meterProvider).build();
85+
SimpleSpanProcessor.builder(exporter).setMeterProvider(() -> meterProvider).build();
8686
closeables.add(spanProcessor);
8787
spanProcessors.add(spanProcessor);
8888
}
@@ -103,7 +103,7 @@ static List<SpanProcessor> configureSpanProcessors(
103103
static BatchSpanProcessor configureBatchSpanProcessor(
104104
ConfigProperties config, SpanExporter exporter, MeterProvider meterProvider) {
105105
BatchSpanProcessorBuilder builder =
106-
BatchSpanProcessor.builder(exporter).setMeterProvider(meterProvider);
106+
BatchSpanProcessor.builder(exporter).setMeterProvider(() -> meterProvider);
107107

108108
Duration scheduleDelay = config.getDuration("otel.bsp.schedule.delay");
109109
if (scheduleDelay != null) {

sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactory.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public SpanProcessor create(SpanProcessorModel model, DeclarativeConfigContext c
5151
}
5252
MeterProvider meterProvider = context.getMeterProvider();
5353
if (meterProvider != null) {
54-
builder.setMeterProvider(meterProvider);
54+
builder.setMeterProvider(() -> meterProvider);
5555
}
5656

5757
return context.addCloseable(builder.build());
@@ -66,7 +66,7 @@ public SpanProcessor create(SpanProcessorModel model, DeclarativeConfigContext c
6666
SimpleSpanProcessorBuilder builder = SimpleSpanProcessor.builder(spanExporter);
6767
MeterProvider meterProvider = context.getMeterProvider();
6868
if (meterProvider != null) {
69-
builder.setMeterProvider(meterProvider);
69+
builder.setMeterProvider(() -> meterProvider);
7070
}
7171
return context.addCloseable(builder.build());
7272
}

sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactoryTest.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ void create_Configured() throws NoSuchFieldException, IllegalAccessException {
337337
.extracting("meterProviderSharedState")
338338
.isEqualTo(sharedState);
339339

340+
// Lazily initialized
340341
assertThat(sdk)
341342
.extracting("tracerProvider")
342343
.extracting("delegate")
@@ -345,8 +346,6 @@ void create_Configured() throws NoSuchFieldException, IllegalAccessException {
345346
.extracting("worker")
346347
.extracting("spanProcessorMetrics")
347348
.extracting("processedSpans")
348-
.extracting("sdkMeter")
349-
.extracting("meterProviderSharedState")
350-
.isEqualTo(sharedState);
349+
.isNull();
351350
}
352351
}

sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerMetrics.java

Lines changed: 76 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
import io.opentelemetry.api.metrics.MeterProvider;
1616
import io.opentelemetry.api.trace.SpanContext;
1717
import io.opentelemetry.sdk.trace.samplers.SamplingDecision;
18+
import java.util.function.Supplier;
19+
import javax.annotation.Nullable;
1820

1921
/**
2022
* SDK metrics exported for started and ended spans as defined in the <a
@@ -88,25 +90,16 @@ final class SdkTracerMetrics {
8890
private static final Attributes recordAndSample =
8991
Attributes.of(OTEL_SPAN_SAMPLING_RESULT, SamplingDecision.RECORD_AND_SAMPLE.name());
9092

91-
private final LongCounter startedSpans;
92-
private final LongUpDownCounter liveSpans;
93-
94-
SdkTracerMetrics(MeterProvider meterProvider) {
95-
Meter meter = meterProvider.get("io.opentelemetry.sdk.trace");
96-
97-
startedSpans =
98-
meter
99-
.counterBuilder("otel.sdk.span.started")
100-
.setUnit("{span}")
101-
.setDescription("The number of created spans.")
102-
.build();
103-
liveSpans =
104-
meter
105-
.upDownCounterBuilder("otel.sdk.span.live")
106-
.setUnit("{span}")
107-
.setDescription(
108-
"The number of created spans with recording=true for which the end operation has not been called yet.")
109-
.build();
93+
private final Object lock = new Object();
94+
95+
private final Supplier<MeterProvider> meterProvider;
96+
97+
@Nullable private Meter meter;
98+
@Nullable private volatile LongCounter startedSpans;
99+
@Nullable private volatile LongUpDownCounter liveSpans;
100+
101+
SdkTracerMetrics(Supplier<MeterProvider> meterProvider) {
102+
this.meterProvider = meterProvider;
110103
}
111104

112105
/**
@@ -117,46 +110,46 @@ Runnable startSpan(SpanContext parentSpanContext, SamplingDecision samplingDecis
117110
if (!parentSpanContext.isValid()) {
118111
switch (samplingDecision) {
119112
case DROP:
120-
startedSpans.add(1, noParentDrop);
113+
startedSpans().add(1, noParentDrop);
121114
return SdkTracerMetrics::noop;
122115
case RECORD_ONLY:
123-
startedSpans.add(1, noParentRecordOnly);
124-
liveSpans.add(1, recordOnly);
116+
startedSpans().add(1, noParentRecordOnly);
117+
liveSpans().add(1, recordOnly);
125118
return this::decrementRecordOnly;
126119
case RECORD_AND_SAMPLE:
127-
startedSpans.add(1, noParentRecordAndSample);
128-
liveSpans.add(1, recordAndSample);
120+
startedSpans().add(1, noParentRecordAndSample);
121+
liveSpans().add(1, recordAndSample);
129122
return this::decrementRecordAndSample;
130123
}
131124
throw new IllegalArgumentException("Unrecognized sampling decision: " + samplingDecision);
132125
} else if (parentSpanContext.isRemote()) {
133126
switch (samplingDecision) {
134127
case DROP:
135-
startedSpans.add(1, remoteParentDrop);
128+
startedSpans().add(1, remoteParentDrop);
136129
return SdkTracerMetrics::noop;
137130
case RECORD_ONLY:
138-
startedSpans.add(1, remoteParentRecordOnly);
139-
liveSpans.add(1, recordOnly);
131+
startedSpans().add(1, remoteParentRecordOnly);
132+
liveSpans().add(1, recordOnly);
140133
return this::decrementRecordOnly;
141134
case RECORD_AND_SAMPLE:
142-
startedSpans.add(1, remoteParentRecordAndSample);
143-
liveSpans.add(1, recordAndSample);
135+
startedSpans().add(1, remoteParentRecordAndSample);
136+
liveSpans().add(1, recordAndSample);
144137
return this::decrementRecordAndSample;
145138
}
146139
throw new IllegalArgumentException("Unrecognized sampling decision: " + samplingDecision);
147140
}
148141
// local parent
149142
switch (samplingDecision) {
150143
case DROP:
151-
startedSpans.add(1, localParentDrop);
144+
startedSpans().add(1, localParentDrop);
152145
return SdkTracerMetrics::noop;
153146
case RECORD_ONLY:
154-
startedSpans.add(1, localParentRecordOnly);
155-
liveSpans.add(1, recordOnly);
147+
startedSpans().add(1, localParentRecordOnly);
148+
liveSpans().add(1, recordOnly);
156149
return this::decrementRecordOnly;
157150
case RECORD_AND_SAMPLE:
158-
startedSpans.add(1, localParentRecordAndSample);
159-
liveSpans.add(1, recordAndSample);
151+
startedSpans().add(1, localParentRecordAndSample);
152+
liveSpans().add(1, recordAndSample);
160153
return this::decrementRecordAndSample;
161154
}
162155
throw new IllegalArgumentException("Unrecognized sampling decision: " + samplingDecision);
@@ -165,10 +158,57 @@ Runnable startSpan(SpanContext parentSpanContext, SamplingDecision samplingDecis
165158
private static void noop() {}
166159

167160
private void decrementRecordOnly() {
168-
liveSpans.add(-1, recordOnly);
161+
liveSpans().add(-1, recordOnly);
169162
}
170163

171164
private void decrementRecordAndSample() {
172-
liveSpans.add(-1, recordAndSample);
165+
liveSpans().add(-1, recordAndSample);
166+
}
167+
168+
private LongCounter startedSpans() {
169+
LongCounter startedSpans = this.startedSpans;
170+
if (startedSpans == null) {
171+
synchronized (lock) {
172+
startedSpans = this.startedSpans;
173+
if (startedSpans == null) {
174+
startedSpans =
175+
meter()
176+
.counterBuilder("otel.sdk.span.started")
177+
.setUnit("{span}")
178+
.setDescription("The number of created spans.")
179+
.build();
180+
this.startedSpans = startedSpans;
181+
}
182+
}
183+
}
184+
return startedSpans;
185+
}
186+
187+
private LongUpDownCounter liveSpans() {
188+
LongUpDownCounter liveSpans = this.liveSpans;
189+
if (liveSpans == null) {
190+
synchronized (lock) {
191+
liveSpans = this.liveSpans;
192+
if (liveSpans == null) {
193+
liveSpans =
194+
meter()
195+
.upDownCounterBuilder("otel.sdk.span.live")
196+
.setUnit("{span}")
197+
.setDescription(
198+
"The number of created spans with recording=true for which the end operation has not been called yet.")
199+
.build();
200+
this.liveSpans = liveSpans;
201+
}
202+
}
203+
}
204+
return liveSpans;
205+
}
206+
207+
private Meter meter() {
208+
if (meter == null) {
209+
// Safe to call from multiple threads.
210+
meter = meterProvider.get().get("io.opentelemetry.sdk.trace");
211+
}
212+
return meter;
173213
}
174214
}

sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public static SdkTracerProviderBuilder builder() {
5656
List<SpanProcessor> spanProcessors,
5757
ScopeConfigurator<TracerConfig> tracerConfigurator,
5858
ExceptionAttributeResolver exceptionAttributeResolver,
59-
MeterProvider meterProvider) {
59+
Supplier<MeterProvider> meterProvider) {
6060
this.sharedState =
6161
new TracerSharedState(
6262
clock,

sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkTracerProviderBuilder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public final class SdkTracerProviderBuilder {
3939
TracerConfig.configuratorBuilder();
4040
private ExceptionAttributeResolver exceptionAttributeResolver =
4141
ExceptionAttributeResolver.getDefault();
42-
private MeterProvider meterProvider = MeterProvider.noop();
42+
private Supplier<MeterProvider> meterProvider = MeterProvider::noop;
4343

4444
/**
4545
* Assign a {@link Clock}. {@link Clock} will be used each time a {@link Span} is started, ended
@@ -239,7 +239,7 @@ SdkTracerProviderBuilder setExceptionAttributeResolver(
239239
* href="https://opentelemetry.io/docs/specs/semconv/otel/sdk-metrics/#span-metrics">SDK Span
240240
* Metrics</a>.
241241
*/
242-
public SdkTracerProviderBuilder setMeterProvider(MeterProvider meterProvider) {
242+
public SdkTracerProviderBuilder setMeterProvider(Supplier<MeterProvider> meterProvider) {
243243
requireNonNull(meterProvider, "meterProvider");
244244
this.meterProvider = meterProvider;
245245
return this;

sdk/trace/src/main/java/io/opentelemetry/sdk/trace/export/BatchSpanProcessor.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import java.util.concurrent.atomic.AtomicBoolean;
2828
import java.util.concurrent.atomic.AtomicInteger;
2929
import java.util.concurrent.atomic.AtomicReference;
30+
import java.util.function.Supplier;
3031
import java.util.logging.Level;
3132
import java.util.logging.Logger;
3233

@@ -67,7 +68,7 @@ public static BatchSpanProcessorBuilder builder(SpanExporter spanExporter) {
6768
BatchSpanProcessor(
6869
SpanExporter spanExporter,
6970
boolean exportUnsampledSpans,
70-
MeterProvider meterProvider,
71+
Supplier<MeterProvider> meterProvider,
7172
InternalTelemetryVersion telemetryVersion,
7273
long scheduleDelayNanos,
7374
int maxQueueSize,
@@ -182,10 +183,11 @@ private static final class Worker implements Runnable {
182183
private final AtomicReference<CompletableResultCode> flushRequested = new AtomicReference<>();
183184
private volatile boolean continueWork = true;
184185
private final ArrayList<SpanData> batch;
186+
private final long maxQueueSize;
185187

186188
private Worker(
187189
SpanExporter spanExporter,
188-
MeterProvider meterProvider,
190+
Supplier<MeterProvider> meterProvider,
189191
InternalTelemetryVersion telemetryVersion,
190192
long scheduleDelayNanos,
191193
int maxExportBatchSize,
@@ -201,13 +203,13 @@ private Worker(
201203

202204
spanProcessorMetrics =
203205
SpanProcessorMetrics.get(telemetryVersion, COMPONENT_ID, meterProvider);
204-
spanProcessorMetrics.buildQueueCapacityMetric(maxQueueSize);
205-
spanProcessorMetrics.buildQueueSizeMetric(queue::size);
206+
this.maxQueueSize = maxQueueSize;
206207

207208
this.batch = new ArrayList<>(this.maxExportBatchSize);
208209
}
209210

210211
private void addSpan(ReadableSpan span) {
212+
spanProcessorMetrics.buildQueueMetricsOnce(maxQueueSize, queue::size);
211213
if (!queue.offer(span)) {
212214
spanProcessorMetrics.dropSpans(1);
213215
} else {

sdk/trace/src/main/java/io/opentelemetry/sdk/trace/export/BatchSpanProcessorBuilder.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import io.opentelemetry.sdk.common.InternalTelemetryVersion;
1313
import java.time.Duration;
1414
import java.util.concurrent.TimeUnit;
15+
import java.util.function.Supplier;
1516
import java.util.logging.Level;
1617
import java.util.logging.Logger;
1718

@@ -34,7 +35,7 @@ public final class BatchSpanProcessorBuilder {
3435
private int maxQueueSize = DEFAULT_MAX_QUEUE_SIZE;
3536
private int maxExportBatchSize = DEFAULT_MAX_EXPORT_BATCH_SIZE;
3637
private long exporterTimeoutNanos = TimeUnit.MILLISECONDS.toNanos(DEFAULT_EXPORT_TIMEOUT_MILLIS);
37-
private MeterProvider meterProvider = MeterProvider.noop();
38+
private Supplier<MeterProvider> meterProvider = MeterProvider::noop;
3839
private InternalTelemetryVersion telemetryVersion = InternalTelemetryVersion.LEGACY;
3940

4041
BatchSpanProcessorBuilder(SpanExporter spanExporter) {
@@ -146,6 +147,16 @@ public BatchSpanProcessorBuilder setMaxExportBatchSize(int maxExportBatchSize) {
146147
* metrics will not be collected.
147148
*/
148149
public BatchSpanProcessorBuilder setMeterProvider(MeterProvider meterProvider) {
150+
requireNonNull(meterProvider, "meterProvider");
151+
this.meterProvider = () -> meterProvider;
152+
return this;
153+
}
154+
155+
/**
156+
* Sets the {@link MeterProvider} to use to collect metrics related to batch export. If not set,
157+
* metrics will not be collected.
158+
*/
159+
public BatchSpanProcessorBuilder setMeterProvider(Supplier<MeterProvider> meterProvider) {
149160
requireNonNull(meterProvider, "meterProvider");
150161
this.meterProvider = meterProvider;
151162
return this;

0 commit comments

Comments
 (0)