diff --git a/sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/main/java/com/azure/monitor/opentelemetry/autoconfigure/implementation/MetricDataMapper.java b/sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/main/java/com/azure/monitor/opentelemetry/autoconfigure/implementation/MetricDataMapper.java index 3773e88b8bdf..8dd8b957fc5b 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/main/java/com/azure/monitor/opentelemetry/autoconfigure/implementation/MetricDataMapper.java +++ b/sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/main/java/com/azure/monitor/opentelemetry/autoconfigure/implementation/MetricDataMapper.java @@ -53,12 +53,18 @@ public class MetricDataMapper { private static final Set OTEL_PRE_AGGREGATED_STANDARD_METRIC_NAMES = new HashSet<>(4); public static final AttributeKey APPLICATIONINSIGHTS_INTERNAL_METRIC_NAME = AttributeKey.stringKey("applicationinsights.internal.metric_name"); + public static final String MS_SENT_TO_AMW_ATTR = "_MS.SentToAMW"; + private static final String METRICS_TO_LOG_ANALYTICS_ENABLED + = "APPLICATIONINSIGHTS_METRICS_TO_LOGANALYTICS_ENABLED"; private final BiConsumer telemetryInitializer; private final boolean captureHttpServer4xxAsError; + private final Boolean otlpExporterEnabled; + private final boolean metricsToLAEnabled; + static { - // HTTP unstable metrics to be excluded via Otel auto instrumentation + // HTTP unstable metrics to be excluded via OTel auto instrumentation OTEL_UNSTABLE_METRICS_TO_EXCLUDE.add("rpc.client.duration"); OTEL_UNSTABLE_METRICS_TO_EXCLUDE.add("rpc.server.duration"); @@ -71,8 +77,17 @@ public class MetricDataMapper { public MetricDataMapper(BiConsumer telemetryInitializer, boolean captureHttpServer4xxAsError) { + this(telemetryInitializer, captureHttpServer4xxAsError, null); + } + + public MetricDataMapper(BiConsumer telemetryInitializer, + boolean captureHttpServer4xxAsError, Boolean otlpExporterEnabled) { this.telemetryInitializer = telemetryInitializer; this.captureHttpServer4xxAsError = captureHttpServer4xxAsError; + this.otlpExporterEnabled = otlpExporterEnabled; + + String metricsToLaEnvVar = System.getenv(METRICS_TO_LOG_ANALYTICS_ENABLED); + this.metricsToLAEnabled = metricsToLaEnvVar == null || "true".equalsIgnoreCase(metricsToLaEnvVar); } public void map(MetricData metricData, Consumer consumer) { @@ -80,7 +95,7 @@ public void map(MetricData metricData, Consumer consumer) { if (type == DOUBLE_SUM || type == DOUBLE_GAUGE || type == LONG_SUM || type == LONG_GAUGE || type == HISTOGRAM) { boolean isPreAggregatedStandardMetric = OTEL_PRE_AGGREGATED_STANDARD_METRIC_NAMES.contains(metricData.getName()); - if (isPreAggregatedStandardMetric) { + if (isPreAggregatedStandardMetric) { // we want standard metrics to always be sent to Breeze List preAggregatedStandardMetrics = convertOtelMetricToAzureMonitorMetric(metricData, true); preAggregatedStandardMetrics.forEach(consumer::accept); @@ -92,8 +107,11 @@ public void map(MetricData metricData, Consumer consumer) { && metricData.getInstrumentationScopeInfo().getName().startsWith(OTEL_INSTRUMENTATION_NAME_PREFIX)) { return; } - List stableOtelMetrics = convertOtelMetricToAzureMonitorMetric(metricData, false); - stableOtelMetrics.forEach(consumer::accept); + + if (metricsToLAEnabled && !isPreAggregatedStandardMetric) { + List stableOtelMetrics = convertOtelMetricToAzureMonitorMetric(metricData, false); + stableOtelMetrics.forEach(consumer::accept); + } } else { logger.warning("metric data type {} is not supported yet.", metricData.getType()); } @@ -109,7 +127,7 @@ private List convertOtelMetricToAzureMonitorMetric(MetricData met builder.setTime(FormattedTime.offSetDateTimeFromEpochNanos(pointData.getEpochNanos())); updateMetricPointBuilder(builder, metricData, pointData, captureHttpServer4xxAsError, - isPreAggregatedStandardMetric); + isPreAggregatedStandardMetric, this.otlpExporterEnabled); telemetryItems.add(builder.build()); } @@ -118,7 +136,8 @@ private List convertOtelMetricToAzureMonitorMetric(MetricData met // visible for testing public static void updateMetricPointBuilder(MetricTelemetryBuilder metricTelemetryBuilder, MetricData metricData, - PointData pointData, boolean captureHttpServer4xxAsError, boolean isPreAggregatedStandardMetric) { + PointData pointData, boolean captureHttpServer4xxAsError, boolean isPreAggregatedStandardMetric, + Boolean otlpExporterEnabled) { checkArgument(metricData != null, "MetricData cannot be null."); MetricPointBuilder pointBuilder = new MetricPointBuilder(); @@ -176,6 +195,9 @@ public static void updateMetricPointBuilder(MetricTelemetryBuilder metricTelemet } metricTelemetryBuilder.setMetricPoint(pointBuilder); + if (otlpExporterEnabled != null) { + metricTelemetryBuilder.addProperty(MS_SENT_TO_AMW_ATTR, otlpExporterEnabled ? "True" : "False"); + } Attributes attributes = pointData.getAttributes(); if (isPreAggregatedStandardMetric) { diff --git a/sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/test/java/com/azure/monitor/opentelemetry/autoconfigure/AzureMonitorMetricExporterTest.java b/sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/test/java/com/azure/monitor/opentelemetry/autoconfigure/AzureMonitorMetricExporterTest.java index 1081cc7dd118..ce1ef30e4b46 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/test/java/com/azure/monitor/opentelemetry/autoconfigure/AzureMonitorMetricExporterTest.java +++ b/sdk/monitor/azure-monitor-opentelemetry-autoconfigure/src/test/java/com/azure/monitor/opentelemetry/autoconfigure/AzureMonitorMetricExporterTest.java @@ -20,6 +20,8 @@ import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader; import io.opentelemetry.sdk.testing.exporter.InMemoryMetricExporter; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import java.util.Collection; import java.util.Comparator; @@ -27,6 +29,7 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import java.util.stream.Stream; import static com.azure.monitor.opentelemetry.autoconfigure.implementation.semconv.HttpAttributes.HTTP_RESPONSE_STATUS_CODE; import static com.azure.monitor.opentelemetry.autoconfigure.implementation.semconv.ServerAttributes.SERVER_ADDRESS; @@ -40,8 +43,13 @@ public class AzureMonitorMetricExporterTest { - @Test - public void testDoubleCounter() { + static Stream enablementOptions() { + return Stream.of(true, false, null); + } + + @ParameterizedTest + @MethodSource("enablementOptions") + public void testDoubleCounter(Boolean otlpExporterEnabled) { InMemoryMetricExporter inMemoryMetricExporter = InMemoryMetricExporter.create(); SdkMeterProvider meterProvider = SdkMeterProvider.builder() .registerMetricReader(PeriodicMetricReader.builder(inMemoryMetricExporter).build()) @@ -59,18 +67,28 @@ public void testDoubleCounter() { MetricData metricData = metricDataList.get(0); for (PointData pointData : metricData.getData().getPoints()) { MetricTelemetryBuilder builder = MetricTelemetryBuilder.create(); - MetricDataMapper.updateMetricPointBuilder(builder, metricDataList.get(0), pointData, true, false); + MetricDataMapper.updateMetricPointBuilder(builder, metricDataList.get(0), pointData, true, false, + otlpExporterEnabled); MetricsData metricsData = (MetricsData) builder.build().getData().getBaseData(); assertThat(metricsData.getMetrics().size()).isEqualTo(1); assertThat(metricsData.getMetrics().get(0).getValue()).isEqualTo(3.1415); + + if (otlpExporterEnabled != null) { + assertThat(metricsData.getProperties().size()).isEqualTo(1); + assertThat(metricsData.getProperties()).containsEntry("_MS.SentToAMW", + otlpExporterEnabled ? "True" : "False"); + } else { + assertThat(metricsData.getProperties()).isNull(); + } } assertThat(metricData.getType()).isEqualTo(DOUBLE_SUM); assertThat(metricData.getName()).isEqualTo("testDoubleCounter"); } - @Test - public void testDoubleGauge() { + @ParameterizedTest + @MethodSource("enablementOptions") + public void testDoubleGauge(Boolean otlpExporterEnabled) { InMemoryMetricExporter inMemoryMetricExporter = InMemoryMetricExporter.create(); SdkMeterProvider meterProvider = SdkMeterProvider.builder() .registerMetricReader(PeriodicMetricReader.builder(inMemoryMetricExporter).build()) @@ -90,12 +108,16 @@ public void testDoubleGauge() { MetricData metricData = metricDataList.get(0); for (PointData pointData : metricData.getData().getPoints()) { MetricTelemetryBuilder builder = MetricTelemetryBuilder.create(); - MetricDataMapper.updateMetricPointBuilder(builder, metricData, pointData, true, false); + MetricDataMapper.updateMetricPointBuilder(builder, metricData, pointData, true, false, otlpExporterEnabled); MetricsData metricsData = (MetricsData) builder.build().getData().getBaseData(); assertThat(metricsData.getMetrics().size()).isEqualTo(1); assertThat(metricsData.getMetrics().get(0).getValue()).isEqualTo(20.0); - assertThat(metricsData.getProperties().size()).isEqualTo(1); + assertThat(metricsData.getProperties().size()).isEqualTo(otlpExporterEnabled == null ? 1 : 2); assertThat(metricsData.getProperties()).containsEntry("thing", "engine"); + if (otlpExporterEnabled != null) { + assertThat(metricsData.getProperties()).containsEntry("_MS.SentToAMW", + otlpExporterEnabled ? "True" : "False"); + } } assertThat(metricData.getType()).isEqualTo(DOUBLE_GAUGE); @@ -123,7 +145,7 @@ public void testAttributesOnCustomMetric() { MetricData metric = metricDatas.get(0); PointData pointData = metric.getData().getPoints().stream().findFirst().get(); MetricTelemetryBuilder builder = MetricTelemetryBuilder.create(); - MetricDataMapper.updateMetricPointBuilder(builder, metric, pointData, true, false); + MetricDataMapper.updateMetricPointBuilder(builder, metric, pointData, true, false, null); MetricsData metricsData = (MetricsData) builder.build().getData().getBaseData(); assertThat(metricsData.getMetrics().size()).isEqualTo(1); @@ -157,7 +179,7 @@ public void testAttributesOnStandardMetric() { MetricData metric = metricDatas.get(0); PointData pointData = metric.getData().getPoints().stream().findFirst().get(); MetricTelemetryBuilder builder = MetricTelemetryBuilder.create(); - MetricDataMapper.updateMetricPointBuilder(builder, metric, pointData, true, true); + MetricDataMapper.updateMetricPointBuilder(builder, metric, pointData, true, true, null); MetricsData metricsData = (MetricsData) builder.build().getData().getBaseData(); assertThat(metricsData.getMetrics().size()).isEqualTo(1); @@ -220,7 +242,7 @@ public void testLongCounter() { assertThat(longPointData3.getAttributes().get(AttributeKey.stringKey("color"))).isEqualTo("yellow"); MetricTelemetryBuilder builder = MetricTelemetryBuilder.create(); - MetricDataMapper.updateMetricPointBuilder(builder, metricData, longPointData1, true, false); + MetricDataMapper.updateMetricPointBuilder(builder, metricData, longPointData1, true, false, null); MetricsData metricsData = (MetricsData) builder.build().getData().getBaseData(); assertThat(metricsData.getMetrics().size()).isEqualTo(1); MetricDataPoint metricDataPoint = metricsData.getMetrics().get(0); @@ -232,7 +254,7 @@ public void testLongCounter() { assertThat(properties).containsEntry("color", "green"); builder = MetricTelemetryBuilder.create(); - MetricDataMapper.updateMetricPointBuilder(builder, metricData, longPointData2, true, false); + MetricDataMapper.updateMetricPointBuilder(builder, metricData, longPointData2, true, false, null); metricsData = (MetricsData) builder.build().getData().getBaseData(); assertThat(metricsData.getMetrics().size()).isEqualTo(1); metricDataPoint = metricsData.getMetrics().get(0); @@ -244,7 +266,7 @@ public void testLongCounter() { assertThat(properties).containsEntry("color", "red"); builder = MetricTelemetryBuilder.create(); - MetricDataMapper.updateMetricPointBuilder(builder, metricData, longPointData3, true, false); + MetricDataMapper.updateMetricPointBuilder(builder, metricData, longPointData3, true, false, null); metricsData = (MetricsData) builder.build().getData().getBaseData(); assertThat(metricsData.getMetrics().size()).isEqualTo(1); metricDataPoint = metricsData.getMetrics().get(0); @@ -283,7 +305,7 @@ public void testLongGauge() { MetricData metricData = metricDataList.get(0); for (PointData pointData : metricData.getData().getPoints()) { MetricTelemetryBuilder builder = MetricTelemetryBuilder.create(); - MetricDataMapper.updateMetricPointBuilder(builder, metricData, pointData, true, false); + MetricDataMapper.updateMetricPointBuilder(builder, metricData, pointData, true, false, null); MetricsData metricsData = (MetricsData) builder.build().getData().getBaseData(); assertThat(metricsData.getMetrics().size()).isEqualTo(1); assertThat(metricsData.getMetrics().get(0).getValue()).isEqualTo(20); @@ -319,7 +341,7 @@ public void testDoubleHistogram() { assertThat(metricData.getData().getPoints().size()).isEqualTo(1); PointData pointData = metricData.getData().getPoints().iterator().next(); MetricTelemetryBuilder builder = MetricTelemetryBuilder.create(); - MetricDataMapper.updateMetricPointBuilder(builder, metricData, pointData, true, false); + MetricDataMapper.updateMetricPointBuilder(builder, metricData, pointData, true, false, null); MetricsData metricsData = (MetricsData) builder.build().getData().getBaseData(); assertThat(metricsData.getMetrics().size()).isEqualTo(1); assertThat(metricsData.getMetrics().get(0).getCount()).isEqualTo(1); @@ -357,7 +379,7 @@ public void testNoAttributeWithPrefixApplicationInsightsInternal() { assertThat(metricData.getData().getPoints().size()).isEqualTo(1); PointData pointData = metricData.getData().getPoints().iterator().next(); MetricTelemetryBuilder builder = MetricTelemetryBuilder.create(); - MetricDataMapper.updateMetricPointBuilder(builder, metricData, pointData, true, false); + MetricDataMapper.updateMetricPointBuilder(builder, metricData, pointData, true, false, null); MetricsData metricsData = (MetricsData) builder.build().getData().getBaseData(); assertThat(metricsData.getMetrics().size()).isEqualTo(1); assertThat(metricsData.getProperties()).isNotNull();