Skip to content

Commit 0051f9b

Browse files
committed
Configurable SdkMeterProvider #4
1 parent defae7c commit 0051f9b

15 files changed

Lines changed: 391 additions & 41 deletions

RELEASE-NOTES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
* #1 OpenTelemetry bootstrap
44
* #2 Configurable SdkTracerProvider
55
* #3 Injectable OTel Resource with Bootique application name
6+
* #4 Configurable SdkMeterProvider
67

bootique-opentelemetry/src/main/java/io/bootique/otel/OpenTelemetryFactory.java

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,27 @@
2020

2121
import io.bootique.annotation.BQConfig;
2222
import io.bootique.annotation.BQConfigProperty;
23+
import io.bootique.otel.meter.SdkMeterProviderFactory;
2324
import io.bootique.otel.trace.SdkTracerProviderFactory;
2425
import io.bootique.shutdown.ShutdownManager;
2526
import io.opentelemetry.api.OpenTelemetry;
2627
import io.opentelemetry.sdk.OpenTelemetrySdk;
27-
import io.opentelemetry.sdk.OpenTelemetrySdkBuilder;
28+
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
2829
import io.opentelemetry.sdk.resources.Resource;
30+
import io.opentelemetry.sdk.trace.SdkTracerProvider;
2931
import jakarta.inject.Inject;
3032

3133
/**
3234
* @since 4.0
3335
*/
3436
@BQConfig
3537
public class OpenTelemetryFactory {
36-
38+
3739
private final Resource resource;
3840
private final ShutdownManager shutdownManager;
3941

40-
private SdkTracerProviderFactory traceProvider;
42+
private SdkMeterProviderFactory meterProvider;
43+
private SdkTracerProviderFactory tracerProvider;
4144

4245
@Inject
4346
public OpenTelemetryFactory(Resource resource, ShutdownManager shutdownManager) {
@@ -46,20 +49,37 @@ public OpenTelemetryFactory(Resource resource, ShutdownManager shutdownManager)
4649
}
4750

4851
@BQConfigProperty
49-
public OpenTelemetryFactory setTraceProvider(SdkTracerProviderFactory traceProvider) {
50-
this.traceProvider = traceProvider;
52+
public OpenTelemetryFactory setMeterProvider(SdkMeterProviderFactory meterProvider) {
53+
this.meterProvider = meterProvider;
54+
return this;
55+
}
56+
57+
@BQConfigProperty
58+
public OpenTelemetryFactory setTracerProvider(SdkTracerProviderFactory tracerProvider) {
59+
this.tracerProvider = tracerProvider;
5160
return this;
5261
}
5362

5463
public OpenTelemetry create() {
55-
OpenTelemetrySdkBuilder builder = OpenTelemetrySdk.builder();
56-
builder.setTracerProvider(traceProviderOrDefault().create());
57-
return builder.build();
64+
SdkMeterProvider meterProvider = meterProviderOrDefault().create();
65+
SdkTracerProvider tracerProvider = traceProviderOrDefault().create(meterProvider);
66+
67+
return OpenTelemetrySdk
68+
.builder()
69+
.setTracerProvider(tracerProvider)
70+
.setMeterProvider(meterProvider)
71+
.build();
72+
}
73+
74+
private SdkMeterProviderFactory meterProviderOrDefault() {
75+
return meterProvider != null
76+
? meterProvider
77+
: new SdkMeterProviderFactory(resource, shutdownManager);
5878
}
5979

6080
private SdkTracerProviderFactory traceProviderOrDefault() {
61-
return traceProvider != null
62-
? traceProvider
81+
return tracerProvider != null
82+
? tracerProvider
6383
: new SdkTracerProviderFactory(resource, shutdownManager);
6484
}
6585
}

bootique-opentelemetry/src/main/java/io/bootique/otel/OpenTelemetryVar.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,15 @@ enum OpenTelemetryVar {
3333

3434
/* Exporter Selection */
3535
OTEL_TRACES_EXPORTER("traces.exporter"),
36+
OTEL_METRICS_EXPORTER("metrics.exporter"),
3637

3738
/* OTLP Exporter */
38-
OTEL_EXPORTER_OTLP_PROTOCOL("exporter.otlp.protocol");
39+
OTEL_EXPORTER_OTLP_PROTOCOL("exporter.otlp.protocol"),
3940
// TODO: OTEL_EXPORTER_OTLP_TRACES_PROTOCOL, OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, OTEL_EXPORTER_OTLP_LOGS_PROTOCOL
4041

42+
/* Metrics SDK Configuration */
43+
OTEL_METRIC_EXPORT_INTERVAL("metric.export.interval");
44+
4145
public final String otelProperty;
4246

4347
OpenTelemetryVar(String otelProperty) {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Licensed to ObjectStyle LLC under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ObjectStyle LLC licenses
6+
* this file to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package io.bootique.otel.meter;
20+
21+
import com.fasterxml.jackson.annotation.JsonTypeName;
22+
import io.opentelemetry.exporter.logging.LoggingMetricExporter;
23+
import io.opentelemetry.sdk.metrics.export.MetricExporter;
24+
25+
/**
26+
* @since 4.0
27+
*/
28+
@JsonTypeName("console")
29+
public class ConsoleMetricExporterFactory implements MetricExporterFactory {
30+
31+
@Override
32+
public MetricExporter create() {
33+
return LoggingMetricExporter.create();
34+
}
35+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Licensed to ObjectStyle LLC under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ObjectStyle LLC licenses
6+
* this file to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package io.bootique.otel.meter;
20+
21+
import com.fasterxml.jackson.annotation.JsonTypeInfo;
22+
import io.bootique.annotation.BQConfig;
23+
import io.bootique.config.PolymorphicConfiguration;
24+
import io.opentelemetry.sdk.metrics.export.MetricExporter;
25+
26+
/**
27+
* @since 4.0
28+
*/
29+
@BQConfig
30+
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", defaultImpl = ConsoleMetricExporterFactory.class)
31+
public interface MetricExporterFactory extends PolymorphicConfiguration {
32+
33+
MetricExporter create();
34+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Licensed to ObjectStyle LLC under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ObjectStyle LLC licenses
6+
* this file to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package io.bootique.otel.meter;
20+
21+
import com.fasterxml.jackson.annotation.JsonTypeName;
22+
import io.opentelemetry.sdk.metrics.export.MetricExporter;
23+
24+
/**
25+
* @since 4.0
26+
*/
27+
@JsonTypeName("noop")
28+
public class NoopMetricExporterFactory implements MetricExporterFactory {
29+
30+
@Override
31+
public MetricExporter create() {
32+
return null;
33+
}
34+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
* Licensed to ObjectStyle LLC under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ObjectStyle LLC licenses
6+
* this file to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package io.bootique.otel.meter;
20+
21+
import io.bootique.annotation.BQConfig;
22+
import io.bootique.annotation.BQConfigProperty;
23+
import io.bootique.shutdown.ShutdownManager;
24+
import io.bootique.value.Duration;
25+
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
26+
import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder;
27+
import io.opentelemetry.sdk.metrics.export.MetricExporter;
28+
import io.opentelemetry.sdk.metrics.export.MetricReader;
29+
import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader;
30+
import io.opentelemetry.sdk.resources.Resource;
31+
import jakarta.inject.Inject;
32+
33+
import java.util.List;
34+
import java.util.Objects;
35+
36+
/**
37+
* @since 4.0
38+
*/
39+
@BQConfig
40+
public class SdkMeterProviderFactory {
41+
42+
private final Resource resource;
43+
private final ShutdownManager shutdownManager;
44+
45+
private Duration metricExportInterval;
46+
private List<MetricExporterFactory> metricExporters;
47+
48+
49+
@Inject
50+
public SdkMeterProviderFactory(Resource resource, ShutdownManager shutdownManager) {
51+
this.resource = resource;
52+
this.shutdownManager = shutdownManager;
53+
}
54+
55+
@BQConfigProperty("Time interval between the start of two export attempts. The default is '1min'")
56+
public SdkMeterProviderFactory setMetricExportInterval(Duration metricExportInterval) {
57+
this.metricExportInterval = metricExportInterval;
58+
return this;
59+
}
60+
61+
@BQConfigProperty
62+
public SdkMeterProviderFactory setMetricExporters(List<MetricExporterFactory> metricExporters) {
63+
this.metricExporters = metricExporters;
64+
return this;
65+
}
66+
67+
public SdkMeterProvider create() {
68+
SdkMeterProviderBuilder builder = SdkMeterProvider
69+
.builder()
70+
.setResource(resource);
71+
72+
// TODO:
73+
// views
74+
// clock
75+
// exemplar filter
76+
77+
createMetricReaders().forEach(builder::registerMetricReader);
78+
return shutdownManager.onShutdown(builder.build());
79+
}
80+
81+
private List<MetricReader> createMetricReaders() {
82+
return createMetricExporters().stream().map(this::createMetricReader).toList();
83+
}
84+
85+
private List<MetricExporter> createMetricExporters() {
86+
87+
// unlike the agent whose default is "otlp", our default will be "console", so that the app could
88+
// work standalone out of the box. To suppress exporting, an explicit "none" exporter should be set
89+
90+
// A single "none" exporter would suppress the default "console" exporter. Though unlike the agent, having a
91+
// "none" exporter mixed with others doesn't result in an exception. It will just be ignored
92+
93+
List<MetricExporterFactory> exporters = this.metricExporters == null || this.metricExporters.isEmpty()
94+
? List.of(new ConsoleMetricExporterFactory())
95+
: this.metricExporters;
96+
97+
return exporters.stream()
98+
.map(MetricExporterFactory::create)
99+
.filter(Objects::nonNull)
100+
.toList();
101+
}
102+
103+
private MetricReader createMetricReader(MetricExporter exporter) {
104+
return PeriodicMetricReader.builder(exporter)
105+
.setInterval(getMetricExportIntervalOrDefault())
106+
.build();
107+
}
108+
109+
private java.time.Duration getMetricExportIntervalOrDefault() {
110+
return this.metricExportInterval != null
111+
? this.metricExportInterval.getDuration()
112+
: java.time.Duration.ofMinutes(1);
113+
}
114+
}

bootique-opentelemetry/src/main/java/io/bootique/otel/trace/ConsoleSpanExporterFactory.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
public class ConsoleSpanExporterFactory implements SpanExporterFactory {
2626

2727
@Override
28-
public SpanExporterSupplier create() {
29-
return new SpanExporterSupplier(() -> LoggingSpanExporter.create(), false);
28+
public SpanExporterHolder create() {
29+
return new SpanExporterHolder(LoggingSpanExporter::create, false);
3030
}
3131
}

bootique-opentelemetry/src/main/java/io/bootique/otel/trace/NoneSpanExporterFactory.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
public class NoneSpanExporterFactory implements SpanExporterFactory {
2525

2626
@Override
27-
public SpanExporterSupplier create() {
28-
return new SpanExporterSupplier(null, false);
27+
public SpanExporterHolder create() {
28+
return null;
2929
}
3030
}

0 commit comments

Comments
 (0)