2525import com .google .auto .service .AutoService ;
2626import com .microsoft .applicationinsights .agent .internal .configuration .Configuration ;
2727import com .microsoft .applicationinsights .agent .internal .configuration .Configuration .ProcessorConfig ;
28+ import com .microsoft .applicationinsights .agent .internal .exporter .AzureMonitorMetricExporter ;
2829import com .microsoft .applicationinsights .agent .internal .exporter .Exporter ;
2930import com .microsoft .applicationinsights .agent .internal .exporter .LoggerExporter ;
3031import com .microsoft .applicationinsights .agent .internal .legacyheaders .AiLegacyHeaderSpanProcessor ;
4748import io .opentelemetry .sdk .logs .SdkLogEmitterProviderBuilder ;
4849import io .opentelemetry .sdk .logs .export .BatchLogProcessor ;
4950import io .opentelemetry .sdk .logs .export .LogExporter ;
51+ import io .opentelemetry .sdk .metrics .SdkMeterProviderBuilder ;
52+ import io .opentelemetry .sdk .metrics .export .PeriodicMetricReader ;
5053import io .opentelemetry .sdk .trace .SdkTracerProviderBuilder ;
5154import io .opentelemetry .sdk .trace .data .SpanData ;
5255import io .opentelemetry .sdk .trace .export .BatchSpanProcessor ;
6265@ AutoService (AutoConfigurationCustomizerProvider .class )
6366public class OpenTelemetryConfigurer implements AutoConfigurationCustomizerProvider {
6467
65- private static volatile BatchSpanProcessor batchSpanProcessor ;
66- private static volatile BatchLogProcessor batchLogProcessor ;
67-
6868 @ Override
6969 public void customize (AutoConfigurationCustomizer autoConfiguration ) {
7070 TelemetryClient telemetryClient = TelemetryClient .getActive ();
@@ -75,28 +75,21 @@ public void customize(AutoConfigurationCustomizer autoConfiguration) {
7575
7676 Configuration configuration = MainEntryPoint .getConfiguration ();
7777
78- autoConfiguration .addTracerProviderCustomizer (
79- (builder , config ) -> configureTracing (builder , config , configuration ));
80- autoConfiguration .addLogEmitterProviderCustomizer (
81- (builder , config ) -> configureLogging (builder , configuration ));
82- }
83-
84- public static CompletableResultCode flush () {
85- List <CompletableResultCode > results = new ArrayList <>();
86- if (batchSpanProcessor != null ) {
87- results .add (batchSpanProcessor .forceFlush ());
88- }
89- if (batchLogProcessor != null ) {
90- results .add (batchLogProcessor .forceFlush ());
91- }
92- return CompletableResultCode .ofAll (results );
78+ autoConfiguration
79+ .addTracerProviderCustomizer (
80+ (builder , config ) -> configureTracing (builder , telemetryClient , config , configuration ))
81+ .addLogEmitterProviderCustomizer (
82+ (builder , config ) -> configureLogging (builder , telemetryClient , configuration ))
83+ .addMeterProviderCustomizer (
84+ (builder , config ) -> configureMetrics (builder , telemetryClient , configuration ));
9385 }
9486
9587 @ SuppressFBWarnings (
9688 value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD" ,
9789 justification = "this method is only called once during initialization" )
9890 private static SdkTracerProviderBuilder configureTracing (
9991 SdkTracerProviderBuilder tracerProvider ,
92+ TelemetryClient telemetryClient ,
10093 ConfigProperties config ,
10194 Configuration configuration ) {
10295
@@ -151,25 +144,28 @@ private static SdkTracerProviderBuilder configureTracing(
151144 String tracesExporter = config .getString ("otel.traces.exporter" );
152145 if ("none" .equals (tracesExporter )) { // "none" is the default set in ConfigOverride
153146 SpanExporter spanExporter =
154- createSpanExporter (configuration , configuration .preview .captureHttpServer4xxAsError );
147+ createSpanExporter (
148+ telemetryClient , configuration , configuration .preview .captureHttpServer4xxAsError );
155149
156150 // using BatchSpanProcessor in order to get off of the application thread as soon as possible
157- batchSpanProcessor =
151+ BatchSpanProcessor batchSpanProcessor =
158152 BatchSpanProcessor .builder (spanExporter )
159153 .setScheduleDelay (getBatchProcessorDelay ())
160154 .build ();
161155
162- tracerProvider .addSpanProcessor (batchSpanProcessor );
156+ tracerProvider .addSpanProcessor (
157+ new TelemetryClientFlushingSpanProcessor (batchSpanProcessor , telemetryClient ));
163158 }
164159
165160 return tracerProvider ;
166161 }
167162
168163 private static SpanExporter createSpanExporter (
169- Configuration configuration , boolean captureHttpServer4xxAsError ) {
164+ TelemetryClient telemetryClient ,
165+ Configuration configuration ,
166+ boolean captureHttpServer4xxAsError ) {
170167
171- SpanExporter spanExporter =
172- new Exporter (TelemetryClient .getActive (), captureHttpServer4xxAsError );
168+ SpanExporter spanExporter = new Exporter (telemetryClient , captureHttpServer4xxAsError );
173169 List <ProcessorConfig > processorConfigs = getSpanProcessorConfigs (configuration );
174170 // NOTE if changing the span processor to something async, flush it in the shutdown hook before
175171 // flushing TelemetryClient
@@ -208,27 +204,32 @@ private static List<ProcessorConfig> getSpanProcessorConfigs(Configuration confi
208204 }
209205
210206 private static SdkLogEmitterProviderBuilder configureLogging (
211- SdkLogEmitterProviderBuilder builder , Configuration configuration ) {
207+ SdkLogEmitterProviderBuilder builder ,
208+ TelemetryClient telemetryClient ,
209+ Configuration configuration ) {
212210
213- LogExporter logExporter = createLogExporter (configuration );
211+ LogExporter logExporter = createLogExporter (telemetryClient , configuration );
214212
215213 // using BatchLogProcessor in order to get off of the application thread as soon as possible
216- batchLogProcessor =
214+ BatchLogProcessor batchLogProcessor =
217215 BatchLogProcessor .builder (logExporter ).setScheduleDelay (getBatchProcessorDelay ()).build ();
218216
217+ TelemetryClientFlushingLogProcessor telemetryClientFlushingLogProcessor =
218+ new TelemetryClientFlushingLogProcessor (batchLogProcessor , telemetryClient );
219+
219220 // inherited attributes log processor also handles operation name, ikey and role name attributes
220221 // and these all need access to Span.current(), so must be run before passing off to the
221222 // BatchLogProcessor
222223 return builder .addLogProcessor (
223224 new InheritedAttributesLogProcessor (
224- configuration .preview .inheritedAttributes , batchLogProcessor ));
225+ configuration .preview .inheritedAttributes , telemetryClientFlushingLogProcessor ));
225226 }
226227
227- private static LogExporter createLogExporter (Configuration configuration ) {
228+ private static LogExporter createLogExporter (
229+ TelemetryClient telemetryClient , Configuration configuration ) {
228230 LogExporter logExporter =
229231 new LoggerExporter (
230- TelemetryClient .getActive (),
231- configuration .preview .captureLoggingLevelAsCustomDimension );
232+ telemetryClient , configuration .preview .captureLoggingLevelAsCustomDimension );
232233 List <ProcessorConfig > processorConfigs = getLogProcessorConfigs (configuration );
233234 if (!processorConfigs .isEmpty ()) {
234235 // Reversing the order of processors before passing it Log processor
@@ -271,6 +272,16 @@ private static Duration getBatchProcessorDelay() {
271272 }
272273 }
273274
275+ private static SdkMeterProviderBuilder configureMetrics (
276+ SdkMeterProviderBuilder builder ,
277+ TelemetryClient telemetryClient ,
278+ Configuration configuration ) {
279+ return builder .registerMetricReader (
280+ PeriodicMetricReader .builder (new AzureMonitorMetricExporter (telemetryClient ))
281+ .setInterval (Duration .ofSeconds (configuration .preview .metricIntervalSeconds ))
282+ .build ());
283+ }
284+
274285 private static class BackCompatHttpUrlProcessor implements SpanExporter {
275286
276287 private final SpanExporter delegate ;
0 commit comments