Skip to content

Commit 555746a

Browse files
authored
Add support for live metrics (#44653)
1 parent 233c3d8 commit 555746a

File tree

16 files changed

+123
-57
lines changed

16 files changed

+123
-57
lines changed

eng/versioning/external_dependencies.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ io.opentelemetry:opentelemetry-bom;1.48.0
129129
io.opentelemetry.instrumentation:opentelemetry-runtime-telemetry-java8;2.14.0-alpha
130130
io.opentelemetry.instrumentation:opentelemetry-spring-boot-starter;2.14.0
131131
io.opentelemetry.instrumentation:opentelemetry-logback-appender-1.0;2.14.0-alpha
132-
io.opentelemetry.semconv:opentelemetry-semconv-incubating;1.26.0-alpha
132+
io.opentelemetry:opentelemetry-semconv;0.14.1
133133
io.projectreactor:reactor-test;3.4.41
134134
io.github.hakky54:logcaptor;2.9.3
135135
com.squareup.okio:okio;3.9.1

sdk/monitor/azure-monitor-opentelemetry-autoconfigure/README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,14 +141,19 @@ For more information on the OpenTelemetry project, please review the [OpenTeleme
141141

142142
### Enabling Logging
143143

144-
You can leverage [Azure SDK logging](logging].
144+
You can leverage [Azure SDK logging][logging].
145145

146146
Examples:
147147
* [Log4j][log4j]
148148
* [Logback][logback]
149149

150150
Learn more about [OpenTelemetry SDK logging][logging_otel_sdk].
151151

152+
### Disable live metrics
153+
154+
You can disable the [live metrics][live_metrics] by setting the `APPLICATIONINSIGHTS_LIVE_METRICS_ENABLED` environment variable to false, the `applicationinsights.live.metrics.enabled` Java system property to false,
155+
or programmatically with a properties supplier: `sdkBuilder.addPropertiesSupplier(() -> Collections.singletonMap("applicationinsights.live.metrics.enabled", "false"))`.
156+
152157
## Next steps
153158
Learn more about [OpenTelemetry][opentelemetry_io]
154159

@@ -182,6 +187,7 @@ This project has adopted the [Microsoft Open Source Code of Conduct][coc]. For m
182187
[log4j]: https://github.com/Azure-Samples/ApplicationInsights-Java-Samples/blob/9a7344eeb44525dfc83df3a1bd59460b8a7d93c6/opentelemetry-api/exporter/TrackTrace/Log4j2/src/main/resources/log4j2.xml#L16
183188
[logback]: https://github.com/Azure-Samples/ApplicationInsights-Java-Samples/blob/9a7344eeb44525dfc83df3a1bd59460b8a7d93c6/opentelemetry-api/exporter/TrackTrace/Logback/src/main/resources/logback.xml#L22
184189
[logging_otel_sdk]: https://opentelemetry.io/docs/languages/java/sdk/#internal-logging
190+
[live_metrics]: https://learn.microsoft.com/azure/azure-monitor/app/live-stream
185191
[opentelemetry_specification]: https://github.com/open-telemetry/opentelemetry-specification
186192
[application_insights_resource]: https://learn.microsoft.com/azure/azure-monitor/app/create-new-resource
187193
[application_insights_intro]: https://learn.microsoft.com/azure/azure-monitor/app/app-insights-overview

sdk/monitor/azure-monitor-opentelemetry-autoconfigure/checkstyle-suppressions.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
<suppress files="com.azure.monitor.opentelemetry.autoconfigure.AzureMonitorAutoConfigure.java" checks="IllegalImportCheck" />
7171
<suppress files="com.azure.monitor.opentelemetry.autoconfigure.AzureMonitorAutoConfigureTest.java" checks="IllegalImportCheck" />
7272
<suppress files="com.azure.monitor.opentelemetry.autoconfigure.AzureMonitorExporterBuilder.java" checks="IllegalImportCheck" />
73+
<suppress files="com.azure.monitor.opentelemetry.autoconfigure.LiveMetrics.java" checks="IllegalImportCheck" />
7374
<suppress files="com.azure.monitor.opentelemetry.autoconfigure.AzureMonitorExportersEndToEndTest.java" checks="IllegalImportCheck" />
7475
<suppress files="com.azure.monitor.opentelemetry.autoconfigure.AzureMonitorLogRecordExporter.java" checks="IllegalImportCheck" />
7576
<suppress files="com.azure.monitor.opentelemetry.autoconfigure.AzureMonitorMetricExporter.java" checks="IllegalImportCheck" />

sdk/monitor/azure-monitor-opentelemetry-autoconfigure/pom.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,9 @@
9292
<version>1.48.0</version> <!-- {x-version-update;io.opentelemetry:opentelemetry-sdk-extension-autoconfigure;external_dependency} -->
9393
</dependency>
9494
<dependency>
95-
<groupId>io.opentelemetry.semconv</groupId>
96-
<artifactId>opentelemetry-semconv-incubating</artifactId>
97-
<version>1.26.0-alpha</version> <!-- {x-version-update;io.opentelemetry.semconv:opentelemetry-semconv-incubating;external_dependency} -->
95+
<groupId>io.opentelemetry</groupId>
96+
<artifactId>opentelemetry-semconv</artifactId>
97+
<version>0.14.1</version> <!-- {x-version-update;io.opentelemetry:opentelemetry-semconv;external_dependency} -->
9898
</dependency>
9999

100100
<!-- Added this dependency to include necessary annotations used by reactor core.
@@ -194,13 +194,13 @@
194194
<rules>
195195
<bannedDependencies>
196196
<includes>
197+
<include>io.opentelemetry:opentelemetry-semconv:[0.14.1]</include> <!-- {x-include-update;io.opentelemetry:opentelemetry-semconv;external_dependency} -->
197198
<include>io.opentelemetry:opentelemetry-api:[1.48.0]</include> <!-- {x-include-update;io.opentelemetry:opentelemetry-api;external_dependency} -->
198199
<include>io.opentelemetry:opentelemetry-sdk:[1.48.0]</include> <!-- {x-include-update;io.opentelemetry:opentelemetry-sdk;external_dependency} -->
199200
<include>io.opentelemetry:opentelemetry-sdk-metrics:[1.48.0]</include> <!-- {x-include-update;io.opentelemetry:opentelemetry-sdk-metrics;external_dependency} -->
200201
<include>io.opentelemetry:opentelemetry-sdk-logs:[1.48.0]</include> <!-- {x-include-update;io.opentelemetry:opentelemetry-sdk-logs;external_dependency} -->
201202
<include>io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi:[1.48.0]</include> <!-- {x-include-update;io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi;external_dependency} -->
202203
<include>io.opentelemetry:opentelemetry-sdk-extension-autoconfigure:[1.48.0]</include> <!-- {x-include-update;io.opentelemetry:opentelemetry-sdk-extension-autoconfigure;external_dependency} -->
203-
<include>io.opentelemetry.semconv:opentelemetry-semconv-incubating:[1.26.0-alpha]</include> <!-- {x-include-update;io.opentelemetry.semconv:opentelemetry-semconv-incubating;external_dependency} -->
204204
<include>com.squareup.okio:okio:[3.9.1]</include> <!-- {x-include-update;com.squareup.okio:okio;external_dependency} -->
205205
</includes>
206206
</bannedDependencies>

sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/main/java/com/azure/monitor/opentelemetry/autoconfigure/AzureMonitorAutoConfigure.java

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,19 @@
33

44
package com.azure.monitor.opentelemetry.autoconfigure;
55

6+
import com.azure.monitor.opentelemetry.autoconfigure.implementation.AzureMonitorExporterProviderKeys;
67
import com.azure.monitor.opentelemetry.autoconfigure.implementation.AzureMonitorLogRecordExporterProvider;
78
import com.azure.monitor.opentelemetry.autoconfigure.implementation.AzureMonitorMetricExporterProvider;
8-
import com.azure.monitor.opentelemetry.autoconfigure.implementation.AzureMonitorExporterProviderKeys;
99
import com.azure.monitor.opentelemetry.autoconfigure.implementation.AzureMonitorSpanExporterProvider;
1010
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer;
1111
import io.opentelemetry.sdk.metrics.Aggregation;
1212
import io.opentelemetry.sdk.metrics.InstrumentSelector;
1313
import io.opentelemetry.sdk.metrics.View;
14+
import io.opentelemetry.sdk.resources.Resource;
1415

1516
import java.util.HashMap;
1617
import java.util.Map;
18+
import java.util.concurrent.atomic.AtomicReference;
1719

1820
/**
1921
* Class to enable Azure Monitor for OpenTelemetry autoconfiguration.
@@ -59,33 +61,40 @@ public static void customize(AutoConfigurationCustomizer autoConfigurationCustom
5961
props.put(AzureMonitorExporterProviderKeys.INTERNAL_USING_AZURE_MONITOR_EXPORTER_BUILDER, "true");
6062
return props;
6163
});
64+
final AtomicReference<Resource> otelResource = new AtomicReference<>();
65+
autoConfigurationCustomizer.addResourceCustomizer((resource, configProperties) -> {
66+
otelResource.set(resource);
67+
return resource;
68+
});
6269
AzureMonitorExporterBuilder azureMonitorExporterBuilder = new AzureMonitorExporterBuilder();
6370
autoConfigurationCustomizer.addSpanExporterCustomizer((spanExporter, configProperties) -> {
6471
if (spanExporter instanceof AzureMonitorSpanExporterProvider.MarkerSpanExporter) {
65-
azureMonitorExporterBuilder.initializeIfNot(autoConfigureOptions, configProperties);
72+
azureMonitorExporterBuilder.initializeIfNot(autoConfigureOptions, configProperties, otelResource.get());
6673
spanExporter = azureMonitorExporterBuilder.buildSpanExporter();
6774
}
6875
return spanExporter;
6976
});
7077
autoConfigurationCustomizer.addMetricExporterCustomizer((metricExporter, configProperties) -> {
7178
if (metricExporter instanceof AzureMonitorMetricExporterProvider.MarkerMetricExporter) {
72-
azureMonitorExporterBuilder.initializeIfNot(autoConfigureOptions, configProperties);
79+
azureMonitorExporterBuilder.initializeIfNot(autoConfigureOptions, configProperties, otelResource.get());
7380
metricExporter = azureMonitorExporterBuilder.buildMetricExporter();
7481
}
7582
return metricExporter;
7683
});
7784
autoConfigurationCustomizer.addLogRecordExporterCustomizer((logRecordExporter, configProperties) -> {
7885
if (logRecordExporter instanceof AzureMonitorLogRecordExporterProvider.MarkerLogRecordExporter) {
79-
azureMonitorExporterBuilder.initializeIfNot(autoConfigureOptions, configProperties);
86+
azureMonitorExporterBuilder.initializeIfNot(autoConfigureOptions, configProperties, otelResource.get());
8087
logRecordExporter = azureMonitorExporterBuilder.buildLogRecordExporter();
8188
}
8289
return logRecordExporter;
8390
});
84-
// TODO (trask)
85-
// sdkBuilder.addTracerProviderCustomizer((sdkTracerProviderBuilder, configProperties) -> {
86-
// QuickPulse quickPulse = QuickPulse.create(getHttpPipeline());
87-
// return sdkTracerProviderBuilder.addSpanProcessor(
88-
// ne
91+
autoConfigurationCustomizer.addTracerProviderCustomizer((sdkTracerProviderBuilder, configProperties) -> {
92+
azureMonitorExporterBuilder.initializeIfNot(autoConfigureOptions, configProperties, otelResource.get());
93+
if (LiveMetrics.isEnabled(configProperties)) {
94+
sdkTracerProviderBuilder.addSpanProcessor(azureMonitorExporterBuilder.buildLiveMetricsSpanProcesor());
95+
}
96+
return sdkTracerProviderBuilder;
97+
});
8998
autoConfigurationCustomizer
9099
.addMeterProviderCustomizer((sdkMeterProviderBuilder, config) -> sdkMeterProviderBuilder
91100
.registerView(InstrumentSelector.builder().setMeterName("io.opentelemetry.sdk.trace").build(),

sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/main/java/com/azure/monitor/opentelemetry/autoconfigure/AzureMonitorExporterBuilder.java

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,32 @@
1313
import com.azure.core.util.Configuration;
1414
import com.azure.core.util.CoreUtils;
1515
import com.azure.core.util.logging.ClientLogger;
16-
import com.azure.monitor.opentelemetry.autoconfigure.implementation.configuration.ConnectionString;
17-
import com.azure.monitor.opentelemetry.autoconfigure.implementation.localstorage.LocalStorageStats;
16+
import com.azure.monitor.opentelemetry.autoconfigure.implementation.LiveMetricsSpanProcessor;
1817
import com.azure.monitor.opentelemetry.autoconfigure.implementation.LogDataMapper;
1918
import com.azure.monitor.opentelemetry.autoconfigure.implementation.MetricDataMapper;
2019
import com.azure.monitor.opentelemetry.autoconfigure.implementation.NoopTracer;
2120
import com.azure.monitor.opentelemetry.autoconfigure.implementation.SpanDataMapper;
21+
import com.azure.monitor.opentelemetry.autoconfigure.implementation.configuration.ConnectionString;
22+
import com.azure.monitor.opentelemetry.autoconfigure.implementation.localstorage.LocalStorageStats;
2223
import com.azure.monitor.opentelemetry.autoconfigure.implementation.builders.AbstractTelemetryBuilder;
2324
import com.azure.monitor.opentelemetry.autoconfigure.implementation.configuration.StatsbeatConnectionString;
2425
import com.azure.monitor.opentelemetry.autoconfigure.implementation.heartbeat.HeartbeatExporter;
2526
import com.azure.monitor.opentelemetry.autoconfigure.implementation.models.ContextTagKeys;
2627
import com.azure.monitor.opentelemetry.autoconfigure.implementation.pipeline.TelemetryItemExporter;
28+
import com.azure.monitor.opentelemetry.autoconfigure.implementation.quickpulse.QuickPulse;
2729
import com.azure.monitor.opentelemetry.autoconfigure.implementation.statsbeat.Feature;
2830
import com.azure.monitor.opentelemetry.autoconfigure.implementation.statsbeat.StatsbeatModule;
2931
import com.azure.monitor.opentelemetry.autoconfigure.implementation.utils.AzureMonitorHelper;
3032
import com.azure.monitor.opentelemetry.autoconfigure.implementation.utils.PropertyHelper;
3133
import com.azure.monitor.opentelemetry.autoconfigure.implementation.utils.ResourceParser;
3234
import com.azure.monitor.opentelemetry.autoconfigure.implementation.utils.TempDirs;
3335
import com.azure.monitor.opentelemetry.autoconfigure.implementation.utils.VersionGenerator;
36+
import io.opentelemetry.api.common.AttributeKey;
3437
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
3538
import io.opentelemetry.sdk.logs.export.LogRecordExporter;
3639
import io.opentelemetry.sdk.metrics.export.MetricExporter;
3740
import io.opentelemetry.sdk.resources.Resource;
41+
import io.opentelemetry.sdk.trace.SpanProcessor;
3842
import io.opentelemetry.sdk.trace.export.SpanExporter;
3943

4044
import java.io.File;
@@ -68,32 +72,51 @@ class AzureMonitorExporterBuilder {
6872

6973
private ConfigProperties configProperties;
7074

75+
private HttpPipeline httpPipeline;
76+
77+
private QuickPulse quickPulse;
78+
79+
private SpanDataMapper spanDataMapper;
80+
7181
private boolean initialized;
7282

73-
void initializeIfNot(AzureMonitorAutoConfigureOptions exporterOptions, ConfigProperties configProperties) {
83+
void initializeIfNot(AzureMonitorAutoConfigureOptions exporterOptions, ConfigProperties configProperties,
84+
Resource resource) {
7485
if (initialized) {
7586
return;
7687
}
77-
initialized = true;
88+
this.initialized = true;
7889
this.exporterOptions = exporterOptions;
7990
this.configProperties = configProperties;
80-
HttpPipeline httpPipeline = createHttpPipeline();
81-
statsbeatModule = initStatsbeatModule(configProperties);
91+
this.httpPipeline = createHttpPipeline();
92+
this.statsbeatModule = initStatsbeatModule(configProperties);
93+
this.spanDataMapper = createSpanDataMapper();
8294
File tempDir = TempDirs.getApplicationInsightsTempDir(LOGGER,
8395
"Telemetry will not be stored to disk and retried on sporadic network failures");
8496
// TODO (heya) change LocalStorageStats.noop() to statsbeatModule.getNonessentialStatsbeat() when we decide to collect non-essential Statsbeat by default.
85-
builtTelemetryItemExporter = AzureMonitorHelper.createTelemetryItemExporter(httpPipeline, statsbeatModule,
97+
this.builtTelemetryItemExporter = AzureMonitorHelper.createTelemetryItemExporter(httpPipeline, statsbeatModule,
8698
tempDir, LocalStorageStats.noop());
99+
if (LiveMetrics.isEnabled(configProperties)) {
100+
this.quickPulse = createQuickPulse(resource);
101+
}
87102
startStatsbeatModule(statsbeatModule, configProperties, tempDir); // wait till TelemetryItemExporter has been initialized before starting StatsbeatModule
88103
}
89104

105+
private QuickPulse createQuickPulse(Resource resource) {
106+
String roleName = resource.getAttribute(AttributeKey.stringKey("service.name"));
107+
String roleInstance = resource.getAttribute(AttributeKey.stringKey("service.instance.id"));
108+
ConnectionString connectionString = getConnectionString();
109+
return QuickPulse.create(httpPipeline, () -> connectionString.getLiveEndpoint(),
110+
() -> connectionString.getInstrumentationKey(), roleName, roleInstance, VersionGenerator.getSdkVersion());
111+
}
112+
90113
SpanExporter buildSpanExporter() {
91-
return new AzureMonitorTraceExporter(createSpanDataMapper(), builtTelemetryItemExporter, statsbeatModule);
114+
return new AzureMonitorTraceExporter(spanDataMapper, builtTelemetryItemExporter, statsbeatModule);
92115
}
93116

94117
LogRecordExporter buildLogRecordExporter() {
95118
return new AzureMonitorLogRecordExporter(new LogDataMapper(true, false, createDefaultsPopulator()),
96-
builtTelemetryItemExporter);
119+
builtTelemetryItemExporter, quickPulse);
97120
}
98121

99122
MetricExporter buildMetricExporter() {
@@ -102,6 +125,10 @@ MetricExporter buildMetricExporter() {
102125
builtTelemetryItemExporter);
103126
}
104127

128+
public SpanProcessor buildLiveMetricsSpanProcesor() {
129+
return new LiveMetricsSpanProcessor(quickPulse, spanDataMapper);
130+
}
131+
105132
private Set<Feature> initStatsbeatFeatures() {
106133
if (System.getProperty("org.graalvm.nativeimage.imagecode") != null) {
107134
return Collections.singleton(Feature.GRAAL_VM_NATIVE);

sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/main/java/com/azure/monitor/opentelemetry/autoconfigure/AzureMonitorLogRecordExporter.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.azure.monitor.opentelemetry.autoconfigure.implementation.logging.OperationLogger;
1010
import com.azure.monitor.opentelemetry.autoconfigure.implementation.models.TelemetryItem;
1111
import com.azure.monitor.opentelemetry.autoconfigure.implementation.pipeline.TelemetryItemExporter;
12+
import com.azure.monitor.opentelemetry.autoconfigure.implementation.quickpulse.QuickPulse;
1213
import com.azure.monitor.opentelemetry.autoconfigure.implementation.utils.AzureMonitorMsgId;
1314
import io.opentelemetry.sdk.common.CompletableResultCode;
1415
import io.opentelemetry.sdk.logs.data.LogRecordData;
@@ -33,14 +34,17 @@ class AzureMonitorLogRecordExporter implements LogRecordExporter {
3334
private final AtomicBoolean stopped = new AtomicBoolean();
3435
private final LogDataMapper mapper;
3536
private final TelemetryItemExporter telemetryItemExporter;
37+
private final QuickPulse quickPulse;
3638

3739
/**
3840
* Creates an instance of log exporter that is configured with given exporter client that sends
3941
* telemetry events to Application Insights resource identified by the instrumentation key.
4042
*/
41-
AzureMonitorLogRecordExporter(LogDataMapper mapper, TelemetryItemExporter telemetryItemExporter) {
43+
AzureMonitorLogRecordExporter(LogDataMapper mapper, TelemetryItemExporter telemetryItemExporter,
44+
QuickPulse quickPulse) {
4245
this.mapper = mapper;
4346
this.telemetryItemExporter = telemetryItemExporter;
47+
this.quickPulse = quickPulse;
4448
}
4549

4650
/**
@@ -61,7 +65,11 @@ public CompletableResultCode export(Collection<LogRecordData> logs) {
6165
LOGGER.verbose("exporting log: {}", log);
6266
try {
6367
String stack = log.getAttributes().get(SemanticAttributes.EXCEPTION_STACKTRACE);
64-
telemetryItems.add(mapper.map(log, stack, null));
68+
TelemetryItem telemetryItem = mapper.map(log, stack, null);
69+
telemetryItems.add(telemetryItem);
70+
if (quickPulse != null && quickPulse.isEnabled()) {
71+
quickPulse.add(telemetryItem);
72+
}
6573
OPERATION_LOGGER.recordSuccess();
6674
} catch (Throwable t) {
6775
OPERATION_LOGGER.recordFailure(t.getMessage(), t, AzureMonitorMsgId.EXPORTER_MAPPING_ERROR);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package com.azure.monitor.opentelemetry.autoconfigure;
5+
6+
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
7+
8+
class LiveMetrics {
9+
10+
static boolean isEnabled(ConfigProperties configProperties) {
11+
return configProperties.getBoolean("applicationinsights.live.metrics.enabled", true);
12+
}
13+
}

sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/main/java/com/azure/monitor/opentelemetry/autoconfigure/implementation/LiveMetricsSpanProcessor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public boolean isStartRequired() {
3030

3131
@Override
3232
public void onEnd(ReadableSpan readableSpan) {
33-
if (quickPulse.isEnabled()) {
33+
if (quickPulse != null && quickPulse.isEnabled()) {
3434
// TODO (trask) can we do anything better here in terms of double conversion?
3535
quickPulse.add(mapper.map(readableSpan.toSpanData()));
3636
}

0 commit comments

Comments
 (0)