From e49cf3b5a6c21a13a871c36fcfcdcd8dac83169b Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Thu, 25 Aug 2022 21:53:32 -0700 Subject: [PATCH 01/17] Add connectionStringOverrides --- .../internal/configuration/Configuration.java | 50 ++++++++--- .../init/InheritedAttributesLogProcessor.java | 14 ++- .../InheritedAttributesSpanProcessor.java | 6 +- ...InheritedConnectionStringLogProcessor.java | 47 ++++++++++ ...nheritedConnectionStringSpanProcessor.java | 89 +++++++++++++++++++ .../agent/internal/init/SecondEntryPoint.java | 26 ++++-- .../implementation/SpanDataMapper.java | 11 +++ .../smoketestapp/TestController.java | 15 +++- .../OpenTelemetryApiSupportTest.java | 35 +++++++- 9 files changed, 257 insertions(+), 36 deletions(-) create mode 100644 agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedConnectionStringLogProcessor.java create mode 100644 agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedConnectionStringSpanProcessor.java diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/configuration/Configuration.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/configuration/Configuration.java index 99b14283416..53cefbfabbf 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/configuration/Configuration.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/configuration/Configuration.java @@ -345,9 +345,12 @@ public static class PreviewConfiguration { public AadAuthentication authentication = new AadAuthentication(); public PreviewStatsbeat statsbeat = new PreviewStatsbeat(); - public List instrumentationKeyOverrides = new ArrayList<>(); + public List connectionStringOverrides = new ArrayList<>(); public List roleNameOverrides = new ArrayList<>(); + @Deprecated + public List instrumentationKeyOverrides = new ArrayList<>(); + public int generalExportQueueCapacity = 2048; // metrics get flooded every 60 seconds by default, so need larger queue size to avoid dropping // telemetry (they are much smaller so a larger queue size is ok) @@ -374,13 +377,17 @@ public void validate() { for (SamplingOverride samplingOverride : sampling.overrides) { samplingOverride.validate(); } - for (Configuration.InstrumentationKeyOverride instrumentationKeyOverride : - instrumentationKeyOverrides) { - instrumentationKeyOverride.validate(); + for (Configuration.ConnectionStringOverride connectionStringOverride : + connectionStringOverrides) { + connectionStringOverride.validate(); } for (Configuration.RoleNameOverride roleNameOverride : roleNameOverrides) { roleNameOverride.validate(); } + for (Configuration.InstrumentationKeyOverride instrumentationKeyOverride : + instrumentationKeyOverrides) { + instrumentationKeyOverride.validate(); + } for (ProcessorConfig processorConfig : processors) { processorConfig.validate(); } @@ -503,22 +510,22 @@ public static class PreviewStatsbeat { public boolean disabled = false; } - public static class InstrumentationKeyOverride { + public static class ConnectionStringOverride { public String httpPathPrefix; - public String instrumentationKey; + public String connectionString; public void validate() { if (httpPathPrefix == null) { // TODO add doc and go link, similar to telemetry processors throw new FriendlyException( - "A instrumentation key override configuration is missing an \"httpPathPrefix\".", - "Please provide an \"httpPathPrefix\" for the instrumentation key override configuration."); + "A connection string override configuration is missing an \"httpPathPrefix\".", + "Please provide an \"httpPathPrefix\" for the connection string override configuration."); } - if (instrumentationKey == null) { + if (connectionString == null) { // TODO add doc and go link, similar to telemetry processors throw new FriendlyException( - "An instrumentation key override configuration is missing an \"instrumentationKey\".", - "Please provide an \"instrumentationKey\" for the instrumentation key override configuration."); + "A connection string override configuration is missing an \"connectionString\".", + "Please provide an \"instrumentationKey\" for the connection string override configuration."); } } } @@ -543,6 +550,27 @@ public void validate() { } } + @Deprecated + public static class InstrumentationKeyOverride { + public String httpPathPrefix; + public String instrumentationKey; + + public void validate() { + if (httpPathPrefix == null) { + // TODO add doc and go link, similar to telemetry processors + throw new FriendlyException( + "An instrumentation key override configuration is missing an \"httpPathPrefix\".", + "Please provide an \"httpPathPrefix\" for the instrumentation key override configuration."); + } + if (instrumentationKey == null) { + // TODO add doc and go link, similar to telemetry processors + throw new FriendlyException( + "An instrumentation key override configuration is missing an \"instrumentationKey\".", + "Please provide an \"instrumentationKey\" for the instrumentation key override configuration."); + } + } + } + public static class CustomInstrumentation { public String className; public String methodName; diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedAttributesLogProcessor.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedAttributesLogProcessor.java index c7dcfb3e797..37f6699fbcf 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedAttributesLogProcessor.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedAttributesLogProcessor.java @@ -29,20 +29,18 @@ import io.opentelemetry.sdk.trace.ReadableSpan; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; public class InheritedAttributesLogProcessor implements LogProcessor { - private static final AttributeKey INSTRUMENTATION_KEY_KEY = - AttributeKey.stringKey("ai.preview.instrumentation_key"); - - private static final AttributeKey ROLE_NAME_KEY = - AttributeKey.stringKey("ai.preview.service_name"); - private final List> inheritedAttributes; public InheritedAttributesLogProcessor( List inheritedAttributes) { - this.inheritedAttributes = buildInheritedAttributesList(inheritedAttributes); + this.inheritedAttributes = + inheritedAttributes.stream() + .map(Configuration.InheritedAttribute::getAttributeKey) + .collect(Collectors.toList()); } private static List> buildInheritedAttributesList( @@ -51,8 +49,6 @@ private static List> buildInheritedAttributesList( for (Configuration.InheritedAttribute inheritedAttribute : inheritedAttributes) { list.add(inheritedAttribute.getAttributeKey()); } - list.add(INSTRUMENTATION_KEY_KEY); - list.add(ROLE_NAME_KEY); return list; } diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedAttributesSpanProcessor.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedAttributesSpanProcessor.java index 20ac0b688c8..d6d18db8c1f 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedAttributesSpanProcessor.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedAttributesSpanProcessor.java @@ -33,11 +33,11 @@ public class InheritedAttributesSpanProcessor implements SpanProcessor { - private final List> inheritAttributeKeys; + private final List> inheritAttributes; public InheritedAttributesSpanProcessor( List inheritedAttributes) { - this.inheritAttributeKeys = + this.inheritAttributes = inheritedAttributes.stream() .map(Configuration.InheritedAttribute::getAttributeKey) .collect(Collectors.toList()); @@ -52,7 +52,7 @@ public void onStart(Context parentContext, ReadWriteSpan span) { } ReadableSpan parentReadableSpan = (ReadableSpan) parentSpan; - for (AttributeKey inheritAttributeKey : inheritAttributeKeys) { + for (AttributeKey inheritAttributeKey : inheritAttributes) { Object value = parentReadableSpan.getAttribute(inheritAttributeKey); if (value != null) { span.setAttribute((AttributeKey) inheritAttributeKey, value); diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedConnectionStringLogProcessor.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedConnectionStringLogProcessor.java new file mode 100644 index 00000000000..09bc9a568e7 --- /dev/null +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedConnectionStringLogProcessor.java @@ -0,0 +1,47 @@ +/* + * ApplicationInsights-Java + * Copyright (c) Microsoft Corporation + * All rights reserved. + * + * MIT License + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the ""Software""), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package com.microsoft.applicationinsights.agent.internal.init; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.sdk.logs.LogProcessor; +import io.opentelemetry.sdk.logs.ReadWriteLogRecord; +import io.opentelemetry.sdk.trace.ReadableSpan; + +public class InheritedConnectionStringLogProcessor implements LogProcessor { + + private static final AttributeKey CONNECTION_STRING = + AttributeKey.stringKey("ai.preview.connection_string"); + + @Override + public void onEmit(ReadWriteLogRecord logRecord) { + Span currentSpan = Span.current(); + if (!(currentSpan instanceof ReadableSpan)) { + return; + } + ReadableSpan currentReadableSpan = (ReadableSpan) currentSpan; + String instrumentationKey = currentReadableSpan.getAttribute(CONNECTION_STRING); + if (instrumentationKey != null) { + logRecord.setAttribute(CONNECTION_STRING, instrumentationKey); + } + } +} diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedConnectionStringSpanProcessor.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedConnectionStringSpanProcessor.java new file mode 100644 index 00000000000..1397ede73b0 --- /dev/null +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedConnectionStringSpanProcessor.java @@ -0,0 +1,89 @@ +/* + * ApplicationInsights-Java + * Copyright (c) Microsoft Corporation + * All rights reserved. + * + * MIT License + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the ""Software""), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package com.microsoft.applicationinsights.agent.internal.init; + +import com.microsoft.applicationinsights.agent.internal.configuration.Configuration; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.trace.ReadWriteSpan; +import io.opentelemetry.sdk.trace.ReadableSpan; +import io.opentelemetry.sdk.trace.SpanProcessor; +import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; +import java.util.List; + +public class InheritedConnectionStringSpanProcessor implements SpanProcessor { + + private static final AttributeKey CONNECTION_STRING = + AttributeKey.stringKey("ai.preview.connection_string"); + + private final List overrides; + + public InheritedConnectionStringSpanProcessor( + List overrides) { + + this.overrides = overrides; + } + + @Override + public void onStart(Context parentContext, ReadWriteSpan span) { + Span parentSpan = Span.fromContext(parentContext); + SpanContext parentSpanContext = parentSpan.getSpanContext(); + if (!parentSpanContext.isValid() || parentSpanContext.isRemote()) { + // this part (setting the attribute on the local root span) could be moved to Sampler + String target = span.getAttribute(SemanticAttributes.HTTP_TARGET); + if (target == null) { + return; + } + for (Configuration.ConnectionStringOverride override : overrides) { + if (target.startsWith(override.httpPathPrefix)) { + span.setAttribute(CONNECTION_STRING, override.connectionString); + break; + } + } + return; + } + if (!(parentSpan instanceof ReadableSpan)) { + return; + } + ReadableSpan parentReadableSpan = (ReadableSpan) parentSpan; + + String instrumentationKey = parentReadableSpan.getAttribute(CONNECTION_STRING); + if (instrumentationKey != null) { + span.setAttribute(CONNECTION_STRING, instrumentationKey); + } + } + + @Override + public boolean isStartRequired() { + return true; + } + + @Override + public void onEnd(ReadableSpan span) {} + + @Override + public boolean isEndRequired() { + return false; + } +} diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/SecondEntryPoint.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/SecondEntryPoint.java index 4c78bd0f35d..07339945909 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/SecondEntryPoint.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/SecondEntryPoint.java @@ -326,15 +326,21 @@ private static SdkTracerProviderBuilder configureTracing( tracerProvider.addSpanProcessor( new InheritedAttributesSpanProcessor(configuration.preview.inheritedAttributes)); } - // adding this even if there are no instrumentationKeyOverrides, in order to support - // "ai.preview.instrumentation_key" being set programmatically on CONSUMER spans + // adding this even if there are no connectionStringOverrides, in order to support + // "ai.preview.connection_string" being set programmatically on CONSUMER spans tracerProvider.addSpanProcessor( - new InheritedInstrumentationKeySpanProcessor( - configuration.preview.instrumentationKeyOverrides)); + new InheritedConnectionStringSpanProcessor( + configuration.preview.connectionStringOverrides)); // adding this even if there are no roleNameOverrides, in order to support // "ai.preview.service_name" being set programmatically on CONSUMER spans tracerProvider.addSpanProcessor( new InheritedRoleNameSpanProcessor(configuration.preview.roleNameOverrides)); + + if (!configuration.preview.instrumentationKeyOverrides.isEmpty()) { + tracerProvider.addSpanProcessor( + new InheritedInstrumentationKeySpanProcessor( + configuration.preview.instrumentationKeyOverrides)); + } if (configuration.preview.profiler.enabled && configuration.preview.profiler.enableRequestTriggering) { tracerProvider.addSpanProcessor(new AlertTriggerSpanProcessor()); @@ -455,13 +461,19 @@ private static SdkLogEmitterProviderBuilder configureLogging( builder.addLogProcessor( new InheritedAttributesLogProcessor(configuration.preview.inheritedAttributes)); } - // adding this even if there are no instrumentationKeyOverrides, in order to support - // "ai.preview.instrumentation_key" being set programmatically on CONSUMER spans - builder.addLogProcessor(new InheritedInstrumentationKeyLogProcessor()); + // adding this even if there are no connectionStringOverrides, in order to support + // "ai.preview.connection_string" being set programmatically on CONSUMER spans + builder.addLogProcessor(new InheritedConnectionStringLogProcessor()); // adding this even if there are no roleNameOverrides, in order to support // "ai.preview.service_name" being set programmatically on CONSUMER spans builder.addLogProcessor(new InheritedRoleNameLogProcessor()); + if (!configuration.preview.instrumentationKeyOverrides.isEmpty()) { + // adding this even if there are no instrumentationKeyOverrides, in order to support + // "ai.preview.instrumentation_key" being set programmatically on CONSUMER spans + builder.addLogProcessor(new InheritedInstrumentationKeyLogProcessor()); + } + String logsExporter = otelConfig.getString("otel.logs.exporter"); if ("none".equals(logsExporter)) { // "none" is the default set in AiConfigCustomizer LogExporter logExporter = createLogExporter(telemetryClient, quickPulse, configuration); diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/SpanDataMapper.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/SpanDataMapper.java index 18265a14321..f9a00e92fb8 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/SpanDataMapper.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/SpanDataMapper.java @@ -938,6 +938,17 @@ static boolean applyCommonTags( telemetryBuilder.setInstrumentationKey((String) value); return true; } + if (stringKey.equals("ai.preview.connection_string") && value instanceof String) { + // TODO set connection string somehow + // telemetryBuilder.setInstrumentationKey((String) value); + + // TODO split out 3 new smoke tests from TelemetryFiltering: + // * RoleNameOverrides + // * InstrumentationKeyOverrides + // * ConnectionStringOverrides + + return true; + } if (stringKey.equals("ai.preview.service_name") && value instanceof String) { telemetryBuilder.addTag(ContextTagKeys.AI_CLOUD_ROLE.toString(), (String) value); return true; diff --git a/smoke-tests/apps/OpenTelemetryApiSupport/src/main/java/com/microsoft/applicationinsights/smoketestapp/TestController.java b/smoke-tests/apps/OpenTelemetryApiSupport/src/main/java/com/microsoft/applicationinsights/smoketestapp/TestController.java index 40005161681..6902dbca627 100644 --- a/smoke-tests/apps/OpenTelemetryApiSupport/src/main/java/com/microsoft/applicationinsights/smoketestapp/TestController.java +++ b/smoke-tests/apps/OpenTelemetryApiSupport/src/main/java/com/microsoft/applicationinsights/smoketestapp/TestController.java @@ -42,16 +42,25 @@ public String testApi() { return "OK!"; } - @GetMapping("/test-overriding-ikey-etc") - public String testOverridingIkeyEtc() { + @GetMapping("/test-overriding-connection-string-etc") + public String testOverridingConnectionStringEtc() { Span.current() - .setAttribute("ai.preview.instrumentation_key", "12341234-1234-1234-1234-123412341234"); + .setAttribute( + "ai.preview.connection_string", + "InstrumentationKey=12341234-1234-1234-1234-123412341234"); Span.current().setAttribute("ai.preview.service_name", "role-name-here"); Span.current().setAttribute("ai.preview.service_instance_id", "role-instance-here"); Span.current().setAttribute("ai.preview.service_version", "application-version-here"); return "OK!"; } + @GetMapping("/test-overriding-ikey-etc") + public String testOverridingIkeyEtc() { + Span.current() + .setAttribute("ai.preview.instrumentation_key", "12341234-1234-1234-1234-123412341234"); + return "OK!"; + } + @GetMapping("/test-extension-annotations") public String testExtensionAnnotations() { return underExtensionAnnotation("a message"); diff --git a/smoke-tests/apps/OpenTelemetryApiSupport/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/OpenTelemetryApiSupportTest.java b/smoke-tests/apps/OpenTelemetryApiSupport/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/OpenTelemetryApiSupportTest.java index 8b54f7962e6..9ba93133b89 100644 --- a/smoke-tests/apps/OpenTelemetryApiSupport/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/OpenTelemetryApiSupportTest.java +++ b/smoke-tests/apps/OpenTelemetryApiSupport/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/OpenTelemetryApiSupportTest.java @@ -74,12 +74,41 @@ void testApi() throws Exception { } @Test - @TargetUri("/test-overriding-ikey-etc") - void testOverridingIkeyEtc() throws Exception { + @TargetUri("/test-overriding-connection-string-etc") + void testOverridingConnectionStringEtc() throws Exception { Telemetry telemetry = testing.getTelemetry(0); assertThat(telemetry.rd.getName()) - .isEqualTo("GET /OpenTelemetryApiSupport/test-overriding-ikey-etc"); + .isEqualTo("GET /OpenTelemetryApiSupport/test-overriding-connection-string-etc"); + assertThat(telemetry.rd.getUrl()) + .matches( + "http://localhost:[0-9]+/OpenTelemetryApiSupport/test-overriding-connection-string-etc"); + assertThat(telemetry.rd.getResponseCode()).isEqualTo("200"); + assertThat(telemetry.rd.getSuccess()).isTrue(); + assertThat(telemetry.rd.getSource()).isNull(); + assertThat(telemetry.rd.getProperties()) + .containsExactly(entry("_MS.ProcessedByMetricExtractors", "True")); + assertThat(telemetry.rd.getMeasurements()).isEmpty(); + + // checking that instrumentation key, cloud role name, cloud role instance, and sdk version are + // from the agent + assertThat(telemetry.rdEnvelope.getIKey()).isEqualTo("12341234-1234-1234-1234-123412341234"); + assertThat(telemetry.rdEnvelope.getTags()).containsEntry("ai.cloud.role", "role-name-here"); + assertThat(telemetry.rdEnvelope.getTags().get("ai.cloud.roleInstance")) + .isEqualTo("role-instance-here"); + assertThat(telemetry.rdEnvelope.getTags()) + .containsEntry("ai.application.ver", "application-version-here"); + assertThat(telemetry.rdEnvelope.getTags()) + .hasEntrySatisfying("ai.internal.sdkVersion", v -> assertThat(v).startsWith("java:3.")); + } + + @Test + @TargetUri("/test-overriding-ikey") + void testOverridingIkey() throws Exception { + Telemetry telemetry = testing.getTelemetry(0); + + assertThat(telemetry.rd.getName()) + .isEqualTo("GET /OpenTelemetryApiSupport/test-overriding-ikey"); assertThat(telemetry.rd.getUrl()) .matches("http://localhost:[0-9]+/OpenTelemetryApiSupport/test-overriding-ikey-etc"); assertThat(telemetry.rd.getResponseCode()).isEqualTo("200"); From c76ef22678cf0e032ee707a29b4fd95260a53dcb Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Fri, 26 Aug 2022 16:14:54 -0700 Subject: [PATCH 02/17] Constants --- ...heritedInstrumentationKeyLogProcessor.java | 10 +- ...eritedInstrumentationKeySpanProcessor.java | 12 +- .../init/InheritedRoleNameLogProcessor.java | 9 +- .../init/InheritedRoleNameSpanProcessor.java | 11 +- .../AiLegacyHeaderSpanProcessor.java | 6 +- .../implementation/AiSemanticAttributes.java | 60 +++++++++- .../implementation/SpanDataMapper.java | 106 ++++++------------ .../builders/AbstractTelemetryBuilder.java | 4 + .../implementation/models/TelemetryItem.java | 11 ++ .../pipeline/TelemetryItemExporter.java | 7 +- 10 files changed, 127 insertions(+), 109 deletions(-) diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedInstrumentationKeyLogProcessor.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedInstrumentationKeyLogProcessor.java index e42cec0b42b..d21a6152122 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedInstrumentationKeyLogProcessor.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedInstrumentationKeyLogProcessor.java @@ -21,7 +21,7 @@ package com.microsoft.applicationinsights.agent.internal.init; -import io.opentelemetry.api.common.AttributeKey; +import com.azure.monitor.opentelemetry.exporter.implementation.AiSemanticAttributes; import io.opentelemetry.api.trace.Span; import io.opentelemetry.sdk.logs.LogProcessor; import io.opentelemetry.sdk.logs.ReadWriteLogRecord; @@ -29,9 +29,6 @@ public class InheritedInstrumentationKeyLogProcessor implements LogProcessor { - private static final AttributeKey INSTRUMENTATION_KEY_KEY = - AttributeKey.stringKey("ai.preview.instrumentation_key"); - @Override public void onEmit(ReadWriteLogRecord logRecord) { Span currentSpan = Span.current(); @@ -39,9 +36,10 @@ public void onEmit(ReadWriteLogRecord logRecord) { return; } ReadableSpan currentReadableSpan = (ReadableSpan) currentSpan; - String instrumentationKey = currentReadableSpan.getAttribute(INSTRUMENTATION_KEY_KEY); + String instrumentationKey = + currentReadableSpan.getAttribute(AiSemanticAttributes.INSTRUMENTATION_KEY); if (instrumentationKey != null) { - logRecord.setAttribute(INSTRUMENTATION_KEY_KEY, instrumentationKey); + logRecord.setAttribute(AiSemanticAttributes.INSTRUMENTATION_KEY, instrumentationKey); } } } diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedInstrumentationKeySpanProcessor.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedInstrumentationKeySpanProcessor.java index 1cbdaa42fa7..301386b7af8 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedInstrumentationKeySpanProcessor.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedInstrumentationKeySpanProcessor.java @@ -21,8 +21,8 @@ package com.microsoft.applicationinsights.agent.internal.init; +import com.azure.monitor.opentelemetry.exporter.implementation.AiSemanticAttributes; import com.microsoft.applicationinsights.agent.internal.configuration.Configuration; -import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.context.Context; @@ -34,9 +34,6 @@ public class InheritedInstrumentationKeySpanProcessor implements SpanProcessor { - private static final AttributeKey INSTRUMENTATION_KEY_KEY = - AttributeKey.stringKey("ai.preview.instrumentation_key"); - private final List overrides; public InheritedInstrumentationKeySpanProcessor( @@ -57,7 +54,7 @@ public void onStart(Context parentContext, ReadWriteSpan span) { } for (Configuration.InstrumentationKeyOverride override : overrides) { if (target.startsWith(override.httpPathPrefix)) { - span.setAttribute(INSTRUMENTATION_KEY_KEY, override.instrumentationKey); + span.setAttribute(AiSemanticAttributes.INSTRUMENTATION_KEY, override.instrumentationKey); break; } } @@ -68,9 +65,10 @@ public void onStart(Context parentContext, ReadWriteSpan span) { } ReadableSpan parentReadableSpan = (ReadableSpan) parentSpan; - String instrumentationKey = parentReadableSpan.getAttribute(INSTRUMENTATION_KEY_KEY); + String instrumentationKey = + parentReadableSpan.getAttribute(AiSemanticAttributes.INSTRUMENTATION_KEY); if (instrumentationKey != null) { - span.setAttribute(INSTRUMENTATION_KEY_KEY, instrumentationKey); + span.setAttribute(AiSemanticAttributes.INSTRUMENTATION_KEY, instrumentationKey); } } diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedRoleNameLogProcessor.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedRoleNameLogProcessor.java index 7bb4b306f31..6df2bbc74ae 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedRoleNameLogProcessor.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedRoleNameLogProcessor.java @@ -21,7 +21,7 @@ package com.microsoft.applicationinsights.agent.internal.init; -import io.opentelemetry.api.common.AttributeKey; +import com.azure.monitor.opentelemetry.exporter.implementation.AiSemanticAttributes; import io.opentelemetry.api.trace.Span; import io.opentelemetry.sdk.logs.LogProcessor; import io.opentelemetry.sdk.logs.ReadWriteLogRecord; @@ -29,9 +29,6 @@ public class InheritedRoleNameLogProcessor implements LogProcessor { - private static final AttributeKey ROLE_NAME_KEY = - AttributeKey.stringKey("ai.preview.service_name"); - @Override public void onEmit(ReadWriteLogRecord logRecord) { Span currentSpan = Span.current(); @@ -39,9 +36,9 @@ public void onEmit(ReadWriteLogRecord logRecord) { return; } ReadableSpan currentReadableSpan = (ReadableSpan) currentSpan; - String roleName = currentReadableSpan.getAttribute(ROLE_NAME_KEY); + String roleName = currentReadableSpan.getAttribute(AiSemanticAttributes.ROLE_NAME); if (roleName != null) { - logRecord.setAttribute(ROLE_NAME_KEY, roleName); + logRecord.setAttribute(AiSemanticAttributes.ROLE_NAME, roleName); } } } diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedRoleNameSpanProcessor.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedRoleNameSpanProcessor.java index 8e2d3f494fd..f0f2e9dd093 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedRoleNameSpanProcessor.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedRoleNameSpanProcessor.java @@ -21,8 +21,8 @@ package com.microsoft.applicationinsights.agent.internal.init; +import com.azure.monitor.opentelemetry.exporter.implementation.AiSemanticAttributes; import com.microsoft.applicationinsights.agent.internal.configuration.Configuration; -import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.context.Context; @@ -34,9 +34,6 @@ public class InheritedRoleNameSpanProcessor implements SpanProcessor { - private static final AttributeKey ROLE_NAME_KEY = - AttributeKey.stringKey("ai.preview.service_name"); - private final List overrides; public InheritedRoleNameSpanProcessor(List overrides) { @@ -55,7 +52,7 @@ public void onStart(Context parentContext, ReadWriteSpan span) { } for (Configuration.RoleNameOverride override : overrides) { if (target.startsWith(override.httpPathPrefix)) { - span.setAttribute(ROLE_NAME_KEY, override.roleName); + span.setAttribute(AiSemanticAttributes.ROLE_NAME, override.roleName); break; } } @@ -66,9 +63,9 @@ public void onStart(Context parentContext, ReadWriteSpan span) { } ReadableSpan parentReadableSpan = (ReadableSpan) parentSpan; - String roleName = parentReadableSpan.getAttribute(ROLE_NAME_KEY); + String roleName = parentReadableSpan.getAttribute(AiSemanticAttributes.ROLE_NAME); if (roleName != null) { - span.setAttribute(ROLE_NAME_KEY, roleName); + span.setAttribute(AiSemanticAttributes.ROLE_NAME, roleName); } } diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/legacyheaders/AiLegacyHeaderSpanProcessor.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/legacyheaders/AiLegacyHeaderSpanProcessor.java index 83f2eb3ea24..1207629b053 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/legacyheaders/AiLegacyHeaderSpanProcessor.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/legacyheaders/AiLegacyHeaderSpanProcessor.java @@ -21,7 +21,7 @@ package com.microsoft.applicationinsights.agent.internal.legacyheaders; -import com.azure.monitor.opentelemetry.exporter.implementation.SpanDataMapper; +import com.azure.monitor.opentelemetry.exporter.implementation.AiSemanticAttributes; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.context.Context; @@ -41,9 +41,9 @@ public void onStart(Context parentContext, ReadWriteSpan span) { // AiLegacyPropagator, because only want to add these properties to the request span if (legacyIds != null && legacyIds.spanContext.equals(Span.fromContext(parentContext).getSpanContext())) { - span.setAttribute(SpanDataMapper.AI_LEGACY_PARENT_ID_KEY, legacyIds.legacyParentId); + span.setAttribute(AiSemanticAttributes.LEGACY_PARENT_ID, legacyIds.legacyParentId); if (legacyIds.legacyRootId != null) { - span.setAttribute(SpanDataMapper.AI_LEGACY_ROOT_ID_KEY, legacyIds.legacyRootId); + span.setAttribute(AiSemanticAttributes.LEGACY_ROOT_ID, legacyIds.legacyRootId); } } } diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/AiSemanticAttributes.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/AiSemanticAttributes.java index 9d058709330..a7fb44527f5 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/AiSemanticAttributes.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/AiSemanticAttributes.java @@ -26,9 +26,25 @@ import static io.opentelemetry.api.common.AttributeKey.stringKey; import io.opentelemetry.api.common.AttributeKey; +import java.util.List; public final class AiSemanticAttributes { + public static final AttributeKey INSTRUMENTATION_KEY = + AttributeKey.stringKey("ai.preview.instrumentation_key"); + + public static final AttributeKey CONNECTION_STRING = + AttributeKey.stringKey("ai.preview.connection_string"); + + public static final AttributeKey ROLE_NAME = + AttributeKey.stringKey("ai.preview.service_name"); + + public static final AttributeKey ROLE_INSTANCE_ID = + AttributeKey.stringKey("ai.preview.service_instance_id"); + + public static final AttributeKey APPLICATION_VERSION = + AttributeKey.stringKey("ai.preview.service_version"); + public static final AttributeKey OPERATION_NAME = stringKey("applicationinsights.internal.operation_name"); @@ -38,8 +54,48 @@ public final class AiSemanticAttributes { public static final AttributeKey IS_SYNTHETIC = booleanKey("applicationinsights.internal.is_synthetic"); - public static final AttributeKey TARGET = - stringKey("applicationinsights.internal.target"); + // this is only used by the 2.x web interop bridge + // for ThreadContext.getRequestTelemetryContext().getRequestTelemetry().setSource() + public static final AttributeKey SPAN_SOURCE = + AttributeKey.stringKey("applicationinsights.internal.source"); + + public static final AttributeKey SESSION_ID = + AttributeKey.stringKey("applicationinsights.internal.session_id"); + + public static final AttributeKey DEVICE_OS = + AttributeKey.stringKey("applicationinsights.internal.operating_system"); + + public static final AttributeKey DEVICE_OS_VERSION = + AttributeKey.stringKey("applicationinsights.internal.operating_system_version"); + + // TODO (trask) remove once this makes it into SemanticAttributes + public static final AttributeKey NET_SOCK_PEER_ADDR = + AttributeKey.stringKey("net.sock.peer.addr"); + + // TODO (trask) this can go away once new indexer is rolled out to gov clouds + public static final AttributeKey> REQUEST_CONTEXT = + AttributeKey.stringArrayKey("http.response.header.request_context"); + + public static final AttributeKey LEGACY_PARENT_ID = + AttributeKey.stringKey("applicationinsights.internal.legacy_parent_id"); + public static final AttributeKey LEGACY_ROOT_ID = + AttributeKey.stringKey("applicationinsights.internal.legacy_root_id"); + + public static final AttributeKey AZURE_SDK_NAMESPACE = + AttributeKey.stringKey("az.namespace"); + public static final AttributeKey AZURE_SDK_PEER_ADDRESS = + AttributeKey.stringKey("peer.address"); + public static final AttributeKey AZURE_SDK_MESSAGE_BUS_DESTINATION = + AttributeKey.stringKey("message_bus.destination"); + public static final AttributeKey AZURE_SDK_ENQUEUED_TIME = + AttributeKey.longKey("x-opt-enqueued-time"); + + public static final AttributeKey KAFKA_RECORD_QUEUE_TIME_MS = + AttributeKey.longKey("kafka.record.queue_time_ms"); + public static final AttributeKey KAFKA_OFFSET = AttributeKey.longKey("kafka.offset"); + + public static final AttributeKey IS_PRE_AGGREGATED = + AttributeKey.booleanKey("applicationinsights.internal.is_pre_aggregated"); private AiSemanticAttributes() {} } diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/SpanDataMapper.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/SpanDataMapper.java index f9a00e92fb8..318031ae20d 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/SpanDataMapper.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/SpanDataMapper.java @@ -61,7 +61,6 @@ import java.util.function.Supplier; import javax.annotation.Nullable; -// TODO (trask) move this class into internal package public final class SpanDataMapper { // visible for testing @@ -76,43 +75,6 @@ public final class SpanDataMapper { // TODO (trask) add to generated ContextTagKeys class private static final ContextTagKeys AI_DEVICE_OS = ContextTagKeys.fromString("ai.device.os"); - // TODO (trask) remove once this makes it into SemanticAttributes - private static final AttributeKey NET_SOCK_PEER_ADDR = - AttributeKey.stringKey("net.sock.peer.addr"); - - // TODO (trask) this can go away once new indexer is rolled out to gov clouds - private static final AttributeKey> AI_REQUEST_CONTEXT_KEY = - AttributeKey.stringArrayKey("http.response.header.request_context"); - - public static final AttributeKey AI_LEGACY_PARENT_ID_KEY = - AttributeKey.stringKey("applicationinsights.internal.legacy_parent_id"); - public static final AttributeKey AI_LEGACY_ROOT_ID_KEY = - AttributeKey.stringKey("applicationinsights.internal.legacy_root_id"); - - // this is only used by the 2.x web interop bridge - // for ThreadContext.getRequestTelemetryContext().getRequestTelemetry().setSource() - private static final AttributeKey AI_SPAN_SOURCE_KEY = - AttributeKey.stringKey("applicationinsights.internal.source"); - private static final AttributeKey AI_SESSION_ID_KEY = - AttributeKey.stringKey("applicationinsights.internal.session_id"); - private static final AttributeKey AI_DEVICE_OS_KEY = - AttributeKey.stringKey("applicationinsights.internal.operating_system"); - private static final AttributeKey AI_DEVICE_OS_VERSION_KEY = - AttributeKey.stringKey("applicationinsights.internal.operating_system_version"); - - private static final AttributeKey AZURE_NAMESPACE = - AttributeKey.stringKey("az.namespace"); - private static final AttributeKey AZURE_SDK_PEER_ADDRESS = - AttributeKey.stringKey("peer.address"); - private static final AttributeKey AZURE_SDK_MESSAGE_BUS_DESTINATION = - AttributeKey.stringKey("message_bus.destination"); - private static final AttributeKey AZURE_SDK_ENQUEUED_TIME = - AttributeKey.longKey("x-opt-enqueued-time"); - - private static final AttributeKey KAFKA_RECORD_QUEUE_TIME_MS = - AttributeKey.longKey("kafka.record.queue_time_ms"); - private static final AttributeKey KAFKA_OFFSET = AttributeKey.longKey("kafka.offset"); - static { Set dbSystems = new HashSet<>(); dbSystems.add(SemanticAttributes.DbSystemValues.DB2); @@ -231,8 +193,7 @@ public static boolean isRequest( private static boolean checkIsPreAggregatedStandardMetric(SpanData span) { Boolean isPreAggregatedStandardMetric = - span.getAttributes() - .get(AttributeKey.booleanKey("applicationinsights.internal.is_pre_aggregated")); + span.getAttributes().get(AiSemanticAttributes.IS_PRE_AGGREGATED); return isPreAggregatedStandardMetric != null && isPreAggregatedStandardMetric; } @@ -352,7 +313,7 @@ private void applySemanticConventions( @Nullable private static String getMessagingSystem(Attributes attributes) { - String azureNamespace = attributes.get(AZURE_NAMESPACE); + String azureNamespace = attributes.get(AiSemanticAttributes.AZURE_SDK_NAMESPACE); if (isAzureSdkMessaging(azureNamespace)) { // special case needed until Azure SDK moves to OTel semantic conventions return azureNamespace; @@ -421,7 +382,7 @@ private void applyHttpClientSpan( @Nullable private static String getTargetAppId(Attributes attributes) { - List requestContextList = attributes.get(AI_REQUEST_CONTEXT_KEY); + List requestContextList = attributes.get(AiSemanticAttributes.REQUEST_CONTEXT); if (requestContextList == null || requestContextList.isEmpty()) { return null; } @@ -577,7 +538,7 @@ private TelemetryItem exportRequest(SpanData span, long itemCount) { telemetryBuilder.addTag(ContextTagKeys.AI_OPERATION_ID.toString(), span.getTraceId()); // see behavior specified at https://github.com/microsoft/ApplicationInsights-Java/issues/1174 - String aiLegacyParentId = span.getAttributes().get(AI_LEGACY_PARENT_ID_KEY); + String aiLegacyParentId = span.getAttributes().get(AiSemanticAttributes.LEGACY_PARENT_ID); if (aiLegacyParentId != null) { // this was the real (legacy) parent id, but it didn't fit span id format telemetryBuilder.addTag(ContextTagKeys.AI_OPERATION_PARENT_ID.toString(), aiLegacyParentId); @@ -586,7 +547,7 @@ private TelemetryItem exportRequest(SpanData span, long itemCount) { ContextTagKeys.AI_OPERATION_PARENT_ID.toString(), span.getParentSpanContext().getSpanId()); } - String aiLegacyRootId = span.getAttributes().get(AI_LEGACY_ROOT_ID_KEY); + String aiLegacyRootId = span.getAttributes().get(AiSemanticAttributes.LEGACY_ROOT_ID); if (aiLegacyRootId != null) { telemetryBuilder.addTag("ai_legacyRootID", aiLegacyRootId); } @@ -615,7 +576,7 @@ private TelemetryItem exportRequest(SpanData span, long itemCount) { String locationIp = attributes.get(SemanticAttributes.HTTP_CLIENT_IP); if (locationIp == null) { // only use net.peer.ip if http.client_ip is not available - locationIp = attributes.get(NET_SOCK_PEER_ADDR); + locationIp = attributes.get(AiSemanticAttributes.NET_SOCK_PEER_ADDR); } if (locationIp != null) { telemetryBuilder.addTag(ContextTagKeys.AI_LOCATION_IP.toString(), locationIp); @@ -623,19 +584,19 @@ private TelemetryItem exportRequest(SpanData span, long itemCount) { telemetryBuilder.setSource(getSource(attributes, span.getSpanContext())); - String sessionId = attributes.get(AI_SESSION_ID_KEY); + String sessionId = attributes.get(AiSemanticAttributes.SESSION_ID); if (sessionId != null) { // this is only used by the 2.x web interop bridge for // ThreadContext.getRequestTelemetryContext().getHttpRequestTelemetry().getContext().getSession().setId() telemetryBuilder.addTag(ContextTagKeys.AI_SESSION_ID.toString(), sessionId); } - String deviceOs = attributes.get(AI_DEVICE_OS_KEY); + String deviceOs = attributes.get(AiSemanticAttributes.DEVICE_OS); if (deviceOs != null) { // this is only used by the 2.x web interop bridge for // ThreadContext.getRequestTelemetryContext().getHttpRequestTelemetry().getContext().getDevice().setOperatingSystem() telemetryBuilder.addTag(AI_DEVICE_OS.toString(), deviceOs); } - String deviceOsVersion = attributes.get(AI_DEVICE_OS_VERSION_KEY); + String deviceOsVersion = attributes.get(AiSemanticAttributes.DEVICE_OS_VERSION); if (deviceOsVersion != null) { // this is only used by the 2.x web interop bridge for // ThreadContext.getRequestTelemetryContext().getHttpRequestTelemetry().getContext().getDevice().setOperatingSystemVersion() @@ -648,14 +609,14 @@ private TelemetryItem exportRequest(SpanData span, long itemCount) { // TODO(trask)? for batch consumer, enqueuedTime should be the average of this attribute // across all links - Long enqueuedTime = attributes.get(AZURE_SDK_ENQUEUED_TIME); + Long enqueuedTime = attributes.get(AiSemanticAttributes.AZURE_SDK_ENQUEUED_TIME); if (enqueuedTime != null) { long timeSinceEnqueuedMillis = Math.max( 0L, NANOSECONDS.toMillis(span.getStartEpochNanos()) - SECONDS.toMillis(enqueuedTime)); telemetryBuilder.addMeasurement("timeSinceEnqueued", (double) timeSinceEnqueuedMillis); } - Long timeSinceEnqueuedMillis = attributes.get(KAFKA_RECORD_QUEUE_TIME_MS); + Long timeSinceEnqueuedMillis = attributes.get(AiSemanticAttributes.KAFKA_RECORD_QUEUE_TIME_MS); if (timeSinceEnqueuedMillis != null) { telemetryBuilder.addMeasurement("timeSinceEnqueued", (double) timeSinceEnqueuedMillis); } @@ -705,7 +666,7 @@ public static String getHttpUrlFromServerSpan(Attributes attributes) { private String getSource(Attributes attributes, @Nullable SpanContext spanContext) { // this is only used by the 2.x web interop bridge // for ThreadContext.getRequestTelemetryContext().getHttpRequestTelemetry().setSource() - String source = attributes.get(AI_SPAN_SOURCE_KEY); + String source = attributes.get(AiSemanticAttributes.SPAN_SOURCE); if (source != null) { return source; } @@ -720,10 +681,10 @@ private String getSource(Attributes attributes, @Nullable SpanContext spanContex @Nullable private static String getMessagingTargetSource(Attributes attributes) { - if (isAzureSdkMessaging(attributes.get(AZURE_NAMESPACE))) { + if (isAzureSdkMessaging(attributes.get(AiSemanticAttributes.AZURE_SDK_NAMESPACE))) { // special case needed until Azure SDK moves to OTel semantic conventions - String peerAddress = attributes.get(AZURE_SDK_PEER_ADDRESS); - String destination = attributes.get(AZURE_SDK_MESSAGE_BUS_DESTINATION); + String peerAddress = attributes.get(AiSemanticAttributes.AZURE_SDK_PEER_ADDRESS); + String destination = attributes.get(AiSemanticAttributes.AZURE_SDK_MESSAGE_BUS_DESTINATION); return peerAddress + "/" + destination; } String messagingSystem = attributes.get(SemanticAttributes.MESSAGING_SYSTEM); @@ -893,18 +854,18 @@ private static void setExtraAttributes( if (stringKey.startsWith("applicationinsights.internal.")) { return; } - if (stringKey.equals(AZURE_NAMESPACE.getKey()) - || stringKey.equals(AZURE_SDK_MESSAGE_BUS_DESTINATION.getKey()) - || stringKey.equals(AZURE_SDK_ENQUEUED_TIME.getKey())) { + if (stringKey.equals(AiSemanticAttributes.AZURE_SDK_NAMESPACE.getKey()) + || stringKey.equals(AiSemanticAttributes.AZURE_SDK_MESSAGE_BUS_DESTINATION.getKey()) + || stringKey.equals(AiSemanticAttributes.AZURE_SDK_ENQUEUED_TIME.getKey())) { // these are from azure SDK (AZURE_SDK_PEER_ADDRESS gets filtered out automatically // since it uses the otel "peer." prefix) return; } - if (stringKey.equals(KAFKA_RECORD_QUEUE_TIME_MS.getKey()) - || stringKey.equals(KAFKA_OFFSET.getKey())) { + if (stringKey.equals(AiSemanticAttributes.KAFKA_RECORD_QUEUE_TIME_MS.getKey()) + || stringKey.equals(AiSemanticAttributes.KAFKA_OFFSET.getKey())) { return; } - if (stringKey.equals(AI_REQUEST_CONTEXT_KEY.getKey())) { + if (stringKey.equals(AiSemanticAttributes.REQUEST_CONTEXT.getKey())) { return; } if (stringKey.equals(SemanticAttributes.HTTP_USER_AGENT.getKey()) @@ -934,30 +895,27 @@ static boolean applyCommonTags( telemetryBuilder.addTag(ContextTagKeys.AI_USER_ID.toString(), (String) value); return true; } - if (stringKey.equals("ai.preview.instrumentation_key") && value instanceof String) { - telemetryBuilder.setInstrumentationKey((String) value); + if (stringKey.equals(AiSemanticAttributes.CONNECTION_STRING.getKey()) + && value instanceof String) { + telemetryBuilder.setConnectionString((String) value); return true; } - if (stringKey.equals("ai.preview.connection_string") && value instanceof String) { - // TODO set connection string somehow - // telemetryBuilder.setInstrumentationKey((String) value); - - // TODO split out 3 new smoke tests from TelemetryFiltering: - // * RoleNameOverrides - // * InstrumentationKeyOverrides - // * ConnectionStringOverrides - + if (stringKey.equals(AiSemanticAttributes.INSTRUMENTATION_KEY.getKey()) + && value instanceof String) { + telemetryBuilder.setInstrumentationKey((String) value); return true; } - if (stringKey.equals("ai.preview.service_name") && value instanceof String) { + if (stringKey.equals(AiSemanticAttributes.ROLE_NAME.getKey()) && value instanceof String) { telemetryBuilder.addTag(ContextTagKeys.AI_CLOUD_ROLE.toString(), (String) value); return true; } - if (stringKey.equals("ai.preview.service_instance_id") && value instanceof String) { + if (stringKey.equals(AiSemanticAttributes.ROLE_INSTANCE_ID.getKey()) + && value instanceof String) { telemetryBuilder.addTag(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString(), (String) value); return true; } - if (stringKey.equals("ai.preview.service_version") && value instanceof String) { + if (stringKey.equals(AiSemanticAttributes.APPLICATION_VERSION.getKey()) + && value instanceof String) { telemetryBuilder.addTag(ContextTagKeys.AI_APPLICATION_VER.toString(), (String) value); return true; } diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/AbstractTelemetryBuilder.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/AbstractTelemetryBuilder.java index 5b21c5d929e..47c85a2ba66 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/AbstractTelemetryBuilder.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/AbstractTelemetryBuilder.java @@ -67,6 +67,10 @@ public void setInstrumentationKey(String instrumentationKey) { telemetryItem.setInstrumentationKey(instrumentationKey); } + public void setConnectionString(String connectionString) { + telemetryItem.setConnectionString(connectionString); + } + public void addTag(String key, String value) { Map tags = telemetryItem.getTags(); if (tags == null) { diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java index 31f6aa21ca5..8d2418d7f94 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java @@ -22,6 +22,7 @@ package com.azure.monitor.opentelemetry.exporter.implementation.models; import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import java.time.OffsetDateTime; import java.util.Map; @@ -76,6 +77,8 @@ public final class TelemetryItem { @JsonProperty(value = "iKey") private String instrumentationKey; + @JsonIgnore private String connectionString; + /* * Key/value collection of context properties. See ContextTagKeys for * information on available properties. @@ -227,6 +230,14 @@ public TelemetryItem setInstrumentationKey(String instrumentationKey) { return this; } + public String getConnectionString() { + return connectionString; + } + + public void setConnectionString(String connectionString) { + this.connectionString = connectionString; + } + /** * Get the tags property: Key/value collection of context properties. See ContextTagKeys for * information on available properties. diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporter.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporter.java index d046183d12c..5bfccf1b139 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporter.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporter.java @@ -93,10 +93,9 @@ public CompletableResultCode send(List telemetryItems) { Map> instrumentationKeyMap = new HashMap<>(); for (TelemetryItem telemetryItem : telemetryItems) { String instrumentationKey = telemetryItem.getInstrumentationKey(); - if (!instrumentationKeyMap.containsKey(instrumentationKey)) { - instrumentationKeyMap.put(instrumentationKey, new ArrayList<>()); - } - instrumentationKeyMap.get(instrumentationKey).add(telemetryItem); + instrumentationKeyMap + .computeIfAbsent(instrumentationKey, k -> new ArrayList<>()) + .add(telemetryItem); } List resultCodeList = new ArrayList<>(); for (Map.Entry> entry : instrumentationKeyMap.entrySet()) { From 7701ac7f3562c77a84d4ded61b714fe696c03378 Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Fri, 26 Aug 2022 20:44:33 -0700 Subject: [PATCH 03/17] more --- .../internal/classicsdk/BytecodeUtilImpl.java | 28 ++++-- .../configuration/ConfigurationBuilder.java | 15 +++- .../internal/exporter/AgentLogExporter.java | 3 +- .../init/InheritedAttributesLogProcessor.java | 10 --- ...heritedInstrumentationKeyLogProcessor.java | 45 ---------- ...eritedInstrumentationKeySpanProcessor.java | 87 ------------------- .../agent/internal/init/SecondEntryPoint.java | 12 --- .../internal/statsbeat/BaseStatsbeat.java | 7 +- .../internal/telemetry/TelemetryClient.java | 16 ++-- .../exporter/AzureMonitorExporterBuilder.java | 23 +---- .../implementation/AiSemanticAttributes.java | 2 + .../implementation/SpanDataMapper.java | 13 ++- .../builders/AbstractTelemetryBuilder.java | 12 ++- .../localstorage/LocalFileLoader.java | 16 +++- .../localstorage/LocalFileSender.java | 1 + .../implementation/models/TelemetryItem.java | 11 +-- .../pipeline/TelemetryItemExporter.java | 10 ++- .../pipeline/TelemetryPipeline.java | 20 +++-- .../localstorage/IntegrationTests.java | 2 +- .../localstorage/LocalFileLoaderTests.java | 7 +- .../pipeline/TelemetryItemExporterTest.java | 2 +- 21 files changed, 118 insertions(+), 224 deletions(-) delete mode 100644 agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedInstrumentationKeyLogProcessor.java delete mode 100644 agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedInstrumentationKeySpanProcessor.java diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/classicsdk/BytecodeUtilImpl.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/classicsdk/BytecodeUtilImpl.java index e4786641206..b72c4385a72 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/classicsdk/BytecodeUtilImpl.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/classicsdk/BytecodeUtilImpl.java @@ -37,6 +37,7 @@ import com.azure.monitor.opentelemetry.exporter.implementation.builders.PageViewTelemetryBuilder; import com.azure.monitor.opentelemetry.exporter.implementation.builders.RemoteDependencyTelemetryBuilder; import com.azure.monitor.opentelemetry.exporter.implementation.builders.RequestTelemetryBuilder; +import com.azure.monitor.opentelemetry.exporter.implementation.configuration.ConnectionString; import com.azure.monitor.opentelemetry.exporter.implementation.models.ContextTagKeys; import com.azure.monitor.opentelemetry.exporter.implementation.models.SeverityLevel; import com.azure.monitor.opentelemetry.exporter.implementation.utils.FormattedDuration; @@ -48,6 +49,7 @@ import com.microsoft.applicationinsights.agent.internal.telemetry.TelemetryClient; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.instrumentation.api.internal.cache.Cache; import io.opentelemetry.sdk.trace.ReadableSpan; import java.net.URI; import java.net.URL; @@ -69,6 +71,9 @@ public class BytecodeUtilImpl implements BytecodeUtilDelegate { public static volatile FeatureStatsbeat featureStatsbeat; + // the key is just the instrumentation key, not the full connection string + private static final Cache connectionStringCache = Cache.bounded(100); + @Override public void trackEvent( @Nullable Date timestamp, @@ -98,7 +103,7 @@ public void trackEvent( } selectivelySetTags(telemetryBuilder, tags); if (instrumentationKey != null) { - telemetryBuilder.setInstrumentationKey(instrumentationKey); + setConnectionString(telemetryBuilder, instrumentationKey); } track(telemetryBuilder, tags, true); @@ -146,7 +151,7 @@ public void trackMetric( } selectivelySetTags(telemetryBuilder, tags); if (instrumentationKey != null) { - telemetryBuilder.setInstrumentationKey(instrumentationKey); + setConnectionString(telemetryBuilder, instrumentationKey); } track(telemetryBuilder, tags, false); @@ -202,7 +207,7 @@ public void trackDependency( } selectivelySetTags(telemetryBuilder, tags); if (instrumentationKey != null) { - telemetryBuilder.setInstrumentationKey(instrumentationKey); + setConnectionString(telemetryBuilder, instrumentationKey); } track(telemetryBuilder, tags, true); @@ -244,7 +249,7 @@ public void trackPageView( } selectivelySetTags(telemetryBuilder, tags); if (instrumentationKey != null) { - telemetryBuilder.setInstrumentationKey(instrumentationKey); + setConnectionString(telemetryBuilder, instrumentationKey); } track(telemetryBuilder, tags, true); @@ -280,7 +285,7 @@ public void trackTrace( } selectivelySetTags(telemetryBuilder, tags); if (instrumentationKey != null) { - telemetryBuilder.setInstrumentationKey(instrumentationKey); + setConnectionString(telemetryBuilder, instrumentationKey); } track(telemetryBuilder, tags, true); @@ -335,7 +340,7 @@ public void trackRequest( } selectivelySetTags(telemetryBuilder, tags); if (instrumentationKey != null) { - telemetryBuilder.setInstrumentationKey(instrumentationKey); + setConnectionString(telemetryBuilder, instrumentationKey); } track(telemetryBuilder, tags, true); @@ -376,7 +381,7 @@ public void trackException( } selectivelySetTags(telemetryBuilder, tags); if (instrumentationKey != null) { - telemetryBuilder.setInstrumentationKey(instrumentationKey); + setConnectionString(telemetryBuilder, instrumentationKey); } track(telemetryBuilder, tags, true); @@ -428,7 +433,7 @@ public void trackAvailability( } selectivelySetTags(telemetryBuilder, tags); if (instrumentationKey != null) { - telemetryBuilder.setInstrumentationKey(instrumentationKey); + setConnectionString(telemetryBuilder, instrumentationKey); } track(telemetryBuilder, tags, false); @@ -544,6 +549,13 @@ private static void setOperationTagsFromTheCurrentSpan( } } + private static void setConnectionString( + AbstractTelemetryBuilder telemetryBuilder, String instrumentationKey) { + telemetryBuilder.setConnectionString( + connectionStringCache.computeIfAbsent( + instrumentationKey, ikey -> ConnectionString.parse("InstrumentationKey=" + ikey))); + } + private static boolean sample(String operationId, double samplingPercentage) { if (samplingPercentage == 100) { // just an optimization diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/configuration/ConfigurationBuilder.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/configuration/ConfigurationBuilder.java index f14cc7538cb..28b97b1742c 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/configuration/ConfigurationBuilder.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/configuration/ConfigurationBuilder.java @@ -33,6 +33,8 @@ import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException; import com.microsoft.applicationinsights.agent.bootstrap.diagnostics.DiagnosticsHelper; import com.microsoft.applicationinsights.agent.internal.common.FriendlyException; +import com.microsoft.applicationinsights.agent.internal.configuration.Configuration.ConnectionStringOverride; +import com.microsoft.applicationinsights.agent.internal.configuration.Configuration.InstrumentationKeyOverride; import com.microsoft.applicationinsights.agent.internal.configuration.Configuration.JmxMetric; import com.microsoft.applicationinsights.agent.internal.configuration.Configuration.SamplingOverride; import java.io.IOException; @@ -128,7 +130,6 @@ public class ConfigurationBuilder { "https://go.microsoft.com/fwlink/?linkid=2153358"; // using deprecated fields to give warning message to user if they are still using them - @SuppressWarnings("deprecation") public static Configuration create(Path agentJarPath, @Nullable RpConfiguration rpConfiguration) throws IOException { Configuration config = loadConfigurationFile(agentJarPath); @@ -201,6 +202,18 @@ private static void logConfigurationWarnings(Configuration config) { + " \"spanKind\" to \"telemetryKind\"."); } } + if (!config.preview.instrumentationKeyOverrides.isEmpty()) { + configurationLogger.warn( + "Instrumentation key overrides hav been deprecated," + + " and support for it will be removed in a future release, please transition from" + + " \"instrumentationKeyOverrides\" to \"connectionStringOverrides\"."); + for (InstrumentationKeyOverride override : config.preview.instrumentationKeyOverrides) { + ConnectionStringOverride newOverride = new ConnectionStringOverride(); + newOverride.httpPathPrefix = override.httpPathPrefix; + newOverride.connectionString = "InstrumentationKey=" + override.instrumentationKey; + config.preview.connectionStringOverrides.add(newOverride); + } + } logWarningIfUsingInternalAttributes(config); } diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/exporter/AgentLogExporter.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/exporter/AgentLogExporter.java index d8924016758..3c5670249e6 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/exporter/AgentLogExporter.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/exporter/AgentLogExporter.java @@ -23,7 +23,6 @@ import static com.azure.monitor.opentelemetry.exporter.implementation.utils.AzureMonitorMsgId.EXPORTER_MAPPING_ERROR; -import com.azure.core.util.CoreUtils; import com.azure.monitor.opentelemetry.exporter.implementation.LogDataMapper; import com.azure.monitor.opentelemetry.exporter.implementation.logging.OperationLogger; import com.azure.monitor.opentelemetry.exporter.implementation.models.TelemetryItem; @@ -93,7 +92,7 @@ public void setThreshold(Severity threshold) { @Override public CompletableResultCode export(Collection logs) { - if (CoreUtils.isNullOrEmpty(TelemetryClient.getActive().getInstrumentationKey())) { + if (TelemetryClient.getActive().getConnectionString() == null) { // Azure Functions consumption plan logger.debug("Instrumentation key is null or empty. Fail to export logs."); return CompletableResultCode.ofFailure(); diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedAttributesLogProcessor.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedAttributesLogProcessor.java index 37f6699fbcf..d2e66f5ec05 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedAttributesLogProcessor.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedAttributesLogProcessor.java @@ -27,7 +27,6 @@ import io.opentelemetry.sdk.logs.LogProcessor; import io.opentelemetry.sdk.logs.ReadWriteLogRecord; import io.opentelemetry.sdk.trace.ReadableSpan; -import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -43,15 +42,6 @@ public InheritedAttributesLogProcessor( .collect(Collectors.toList()); } - private static List> buildInheritedAttributesList( - List inheritedAttributes) { - List> list = new ArrayList<>(); - for (Configuration.InheritedAttribute inheritedAttribute : inheritedAttributes) { - list.add(inheritedAttribute.getAttributeKey()); - } - return list; - } - @Override @SuppressWarnings("unchecked") public void onEmit(ReadWriteLogRecord logRecord) { diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedInstrumentationKeyLogProcessor.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedInstrumentationKeyLogProcessor.java deleted file mode 100644 index d21a6152122..00000000000 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedInstrumentationKeyLogProcessor.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * ApplicationInsights-Java - * Copyright (c) Microsoft Corporation - * All rights reserved. - * - * MIT License - * Permission is hereby granted, free of charge, to any person obtaining a copy of this - * software and associated documentation files (the ""Software""), to deal in the Software - * without restriction, including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, and to permit - * persons to whom the Software is furnished to do so, subject to the following conditions: - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE - * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package com.microsoft.applicationinsights.agent.internal.init; - -import com.azure.monitor.opentelemetry.exporter.implementation.AiSemanticAttributes; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.sdk.logs.LogProcessor; -import io.opentelemetry.sdk.logs.ReadWriteLogRecord; -import io.opentelemetry.sdk.trace.ReadableSpan; - -public class InheritedInstrumentationKeyLogProcessor implements LogProcessor { - - @Override - public void onEmit(ReadWriteLogRecord logRecord) { - Span currentSpan = Span.current(); - if (!(currentSpan instanceof ReadableSpan)) { - return; - } - ReadableSpan currentReadableSpan = (ReadableSpan) currentSpan; - String instrumentationKey = - currentReadableSpan.getAttribute(AiSemanticAttributes.INSTRUMENTATION_KEY); - if (instrumentationKey != null) { - logRecord.setAttribute(AiSemanticAttributes.INSTRUMENTATION_KEY, instrumentationKey); - } - } -} diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedInstrumentationKeySpanProcessor.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedInstrumentationKeySpanProcessor.java deleted file mode 100644 index 301386b7af8..00000000000 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/InheritedInstrumentationKeySpanProcessor.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * ApplicationInsights-Java - * Copyright (c) Microsoft Corporation - * All rights reserved. - * - * MIT License - * Permission is hereby granted, free of charge, to any person obtaining a copy of this - * software and associated documentation files (the ""Software""), to deal in the Software - * without restriction, including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, and to permit - * persons to whom the Software is furnished to do so, subject to the following conditions: - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE - * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package com.microsoft.applicationinsights.agent.internal.init; - -import com.azure.monitor.opentelemetry.exporter.implementation.AiSemanticAttributes; -import com.microsoft.applicationinsights.agent.internal.configuration.Configuration; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.SpanContext; -import io.opentelemetry.context.Context; -import io.opentelemetry.sdk.trace.ReadWriteSpan; -import io.opentelemetry.sdk.trace.ReadableSpan; -import io.opentelemetry.sdk.trace.SpanProcessor; -import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; -import java.util.List; - -public class InheritedInstrumentationKeySpanProcessor implements SpanProcessor { - - private final List overrides; - - public InheritedInstrumentationKeySpanProcessor( - List overrides) { - - this.overrides = overrides; - } - - @Override - public void onStart(Context parentContext, ReadWriteSpan span) { - Span parentSpan = Span.fromContext(parentContext); - SpanContext parentSpanContext = parentSpan.getSpanContext(); - if (!parentSpanContext.isValid() || parentSpanContext.isRemote()) { - // this part (setting the attribute on the local root span) could be moved to Sampler - String target = span.getAttribute(SemanticAttributes.HTTP_TARGET); - if (target == null) { - return; - } - for (Configuration.InstrumentationKeyOverride override : overrides) { - if (target.startsWith(override.httpPathPrefix)) { - span.setAttribute(AiSemanticAttributes.INSTRUMENTATION_KEY, override.instrumentationKey); - break; - } - } - return; - } - if (!(parentSpan instanceof ReadableSpan)) { - return; - } - ReadableSpan parentReadableSpan = (ReadableSpan) parentSpan; - - String instrumentationKey = - parentReadableSpan.getAttribute(AiSemanticAttributes.INSTRUMENTATION_KEY); - if (instrumentationKey != null) { - span.setAttribute(AiSemanticAttributes.INSTRUMENTATION_KEY, instrumentationKey); - } - } - - @Override - public boolean isStartRequired() { - return true; - } - - @Override - public void onEnd(ReadableSpan span) {} - - @Override - public boolean isEndRequired() { - return false; - } -} diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/SecondEntryPoint.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/SecondEntryPoint.java index 07339945909..74a1a87c845 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/SecondEntryPoint.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/SecondEntryPoint.java @@ -335,12 +335,6 @@ private static SdkTracerProviderBuilder configureTracing( // "ai.preview.service_name" being set programmatically on CONSUMER spans tracerProvider.addSpanProcessor( new InheritedRoleNameSpanProcessor(configuration.preview.roleNameOverrides)); - - if (!configuration.preview.instrumentationKeyOverrides.isEmpty()) { - tracerProvider.addSpanProcessor( - new InheritedInstrumentationKeySpanProcessor( - configuration.preview.instrumentationKeyOverrides)); - } if (configuration.preview.profiler.enabled && configuration.preview.profiler.enableRequestTriggering) { tracerProvider.addSpanProcessor(new AlertTriggerSpanProcessor()); @@ -468,12 +462,6 @@ private static SdkLogEmitterProviderBuilder configureLogging( // "ai.preview.service_name" being set programmatically on CONSUMER spans builder.addLogProcessor(new InheritedRoleNameLogProcessor()); - if (!configuration.preview.instrumentationKeyOverrides.isEmpty()) { - // adding this even if there are no instrumentationKeyOverrides, in order to support - // "ai.preview.instrumentation_key" being set programmatically on CONSUMER spans - builder.addLogProcessor(new InheritedInstrumentationKeyLogProcessor()); - } - String logsExporter = otelConfig.getString("otel.logs.exporter"); if ("none".equals(logsExporter)) { // "none" is the default set in AiConfigCustomizer LogExporter logExporter = createLogExporter(telemetryClient, quickPulse, configuration); diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/statsbeat/BaseStatsbeat.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/statsbeat/BaseStatsbeat.java index 82e83f56b3b..2f26dbb4d38 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/statsbeat/BaseStatsbeat.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/statsbeat/BaseStatsbeat.java @@ -22,6 +22,7 @@ package com.microsoft.applicationinsights.agent.internal.statsbeat; import com.azure.monitor.opentelemetry.exporter.implementation.builders.StatsbeatTelemetryBuilder; +import com.azure.monitor.opentelemetry.exporter.implementation.configuration.StatsbeatConnectionString; import com.microsoft.applicationinsights.agent.internal.telemetry.TelemetryClient; abstract class BaseStatsbeat { @@ -39,7 +40,11 @@ protected StatsbeatTelemetryBuilder createStatsbeatTelemetry( StatsbeatTelemetryBuilder telemetryBuilder = StatsbeatTelemetryBuilder.create(name, value); - telemetryBuilder.setInstrumentationKey(telemetryClient.getStatsbeatInstrumentationKey()); + StatsbeatConnectionString connectionString = telemetryClient.getStatsbeatConnectionString(); + if (connectionString != null) { + // not sure if connectionString can be null in Azure Functions + telemetryBuilder.setConnectionString(connectionString); + } customDimensions.populateProperties(telemetryBuilder, telemetryClient.getInstrumentationKey()); diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/telemetry/TelemetryClient.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/telemetry/TelemetryClient.java index f2ed653ce69..2508b2dd087 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/telemetry/TelemetryClient.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/telemetry/TelemetryClient.java @@ -247,8 +247,7 @@ private BatchItemProcessor initBatchItemProcessor( LazyHttpClient.newHttpPipeLine( aadAuthentication, new NetworkStatsbeatHttpPipelinePolicy(statsbeatModule.getNetworkStatsbeat())); - TelemetryPipeline telemetryPipeline = - new TelemetryPipeline(httpPipeline, () -> connectionString.getIngestionEndpoint()); + TelemetryPipeline telemetryPipeline = new TelemetryPipeline(httpPipeline); TelemetryPipelineListener telemetryPipelineListener; if (tempDir == null) { @@ -286,8 +285,7 @@ public BatchItemProcessor getStatsbeatBatchItemProcessor() { synchronized (batchItemProcessorInitLock) { if (statsbeatBatchItemProcessor == null) { HttpPipeline httpPipeline = LazyHttpClient.newHttpPipeLine(null); - TelemetryPipeline telemetryPipeline = - new TelemetryPipeline(httpPipeline, () -> statsbeatConnectionString.getEndpoint()); + TelemetryPipeline telemetryPipeline = new TelemetryPipeline(httpPipeline); TelemetryPipelineListener telemetryPipelineListener; if (tempDir == null) { @@ -329,9 +327,8 @@ public String getInstrumentationKey() { } @Nullable - public String getStatsbeatInstrumentationKey() { - StatsbeatConnectionString val = this.statsbeatConnectionString; - return val != null ? val.getInstrumentationKey() : null; + public StatsbeatConnectionString getStatsbeatConnectionString() { + return statsbeatConnectionString; } // convenience @@ -389,7 +386,10 @@ public void populateDefaults(AbstractTelemetryBuilder telemetryBuilder, Resource } private void populateDefaults(AbstractTelemetryBuilder telemetryBuilder) { - telemetryBuilder.setInstrumentationKey(getInstrumentationKey()); + if (connectionString != null) { + // not sure if connectionString can be null in Azure Functions + telemetryBuilder.setConnectionString(connectionString); + } for (Map.Entry entry : globalTags.entrySet()) { telemetryBuilder.addTag(entry.getKey(), entry.getValue()); } diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/AzureMonitorExporterBuilder.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/AzureMonitorExporterBuilder.java index ed895d69a7a..76ce72e7032 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/AzureMonitorExporterBuilder.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/AzureMonitorExporterBuilder.java @@ -57,7 +57,6 @@ import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.export.SpanExporter; import java.io.File; -import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -80,7 +79,6 @@ public final class AzureMonitorExporterBuilder { private String instrumentationKey; private String connectionString; - private URL endpoint; private TokenCredential credential; // suppress warnings is needed in ApplicationInsights-Java repo, can be removed when upstreaming @@ -99,23 +97,9 @@ public final class AzureMonitorExporterBuilder { /** Creates an instance of {@link AzureMonitorExporterBuilder}. */ public AzureMonitorExporterBuilder() {} - /** - * Sets the service endpoint for the Azure Monitor Exporter. - * - * @param endpoint The URL of the Azure Monitor Exporter endpoint. - * @return The updated {@link AzureMonitorExporterBuilder} object. - * @throws NullPointerException if {@code endpoint} is null. - * @throws IllegalArgumentException if {@code endpoint} cannot be parsed into a valid URL. - */ - AzureMonitorExporterBuilder endpoint(URL endpoint) { - Objects.requireNonNull(endpoint, "'endpoint' cannot be null."); - this.endpoint = endpoint; - return this; - } - /** * Sets the HTTP pipeline to use for the service client. If {@code httpPipeline} is set, all other - * settings are ignored, apart from {@link #endpoint(URL) endpoint}. + * settings are ignored. * * @param httpPipeline The HTTP pipeline to use for sending service requests and receiving * responses. @@ -217,7 +201,6 @@ public AzureMonitorExporterBuilder connectionString(String connectionString) { this.connectionString = connectionString; ConnectionString connectionStringObj = ConnectionString.parse(connectionString); this.instrumentationKey = connectionStringObj.getInstrumentationKey(); - this.endpoint(connectionStringObj.getIngestionEndpoint()); return this; } @@ -315,7 +298,7 @@ private TelemetryItemExporter initExporterBuilder() { httpPipeline = createHttpPipeline(); } - TelemetryPipeline pipeline = new TelemetryPipeline(httpPipeline, () -> endpoint); + TelemetryPipeline pipeline = new TelemetryPipeline(httpPipeline); File tempDir = TempDirs.getApplicationInsightsTempDir( @@ -368,7 +351,7 @@ private HttpPipeline createHttpPipeline() { } void populateDefaults(AbstractTelemetryBuilder builder, Resource resource) { - builder.setInstrumentationKey(instrumentationKey); + builder.setConnectionString(ConnectionString.parse("InstrumentationKey=" + instrumentationKey)); builder.addTag( ContextTagKeys.AI_INTERNAL_SDK_VERSION.toString(), VersionGenerator.getSdkVersion()); ResourceParser.updateRoleNameAndInstance(builder, resource); diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/AiSemanticAttributes.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/AiSemanticAttributes.java index a7fb44527f5..3b57796c412 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/AiSemanticAttributes.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/AiSemanticAttributes.java @@ -30,6 +30,8 @@ public final class AiSemanticAttributes { + // replaced by ai.preview.connection_string + @Deprecated public static final AttributeKey INSTRUMENTATION_KEY = AttributeKey.stringKey("ai.preview.instrumentation_key"); diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/SpanDataMapper.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/SpanDataMapper.java index 318031ae20d..f209db805f7 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/SpanDataMapper.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/SpanDataMapper.java @@ -31,6 +31,7 @@ import com.azure.monitor.opentelemetry.exporter.implementation.builders.MessageTelemetryBuilder; import com.azure.monitor.opentelemetry.exporter.implementation.builders.RemoteDependencyTelemetryBuilder; import com.azure.monitor.opentelemetry.exporter.implementation.builders.RequestTelemetryBuilder; +import com.azure.monitor.opentelemetry.exporter.implementation.configuration.ConnectionString; import com.azure.monitor.opentelemetry.exporter.implementation.models.ContextTagKeys; import com.azure.monitor.opentelemetry.exporter.implementation.models.TelemetryItem; import com.azure.monitor.opentelemetry.exporter.implementation.utils.FormattedDuration; @@ -43,6 +44,7 @@ import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.api.trace.SpanId; import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.instrumentation.api.internal.cache.Cache; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.ReadableSpan; @@ -75,6 +77,8 @@ public final class SpanDataMapper { // TODO (trask) add to generated ContextTagKeys class private static final ContextTagKeys AI_DEVICE_OS = ContextTagKeys.fromString("ai.device.os"); + private static final Cache connectionStringCache = Cache.bounded(100); + static { Set dbSystems = new HashSet<>(); dbSystems.add(SemanticAttributes.DbSystemValues.DB2); @@ -897,12 +901,17 @@ static boolean applyCommonTags( } if (stringKey.equals(AiSemanticAttributes.CONNECTION_STRING.getKey()) && value instanceof String) { - telemetryBuilder.setConnectionString((String) value); + // intentionally letting exceptions from parse bubble up + telemetryBuilder.setConnectionString( + connectionStringCache.computeIfAbsent((String) value, ConnectionString::parse)); return true; } if (stringKey.equals(AiSemanticAttributes.INSTRUMENTATION_KEY.getKey()) && value instanceof String) { - telemetryBuilder.setInstrumentationKey((String) value); + // intentionally letting exceptions from parse bubble up + telemetryBuilder.setConnectionString( + connectionStringCache.computeIfAbsent( + "InstrumentationKey=" + value, ConnectionString::parse)); return true; } if (stringKey.equals(AiSemanticAttributes.ROLE_NAME.getKey()) && value instanceof String) { diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/AbstractTelemetryBuilder.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/AbstractTelemetryBuilder.java index 47c85a2ba66..44d965a3220 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/AbstractTelemetryBuilder.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/AbstractTelemetryBuilder.java @@ -21,6 +21,8 @@ package com.azure.monitor.opentelemetry.exporter.implementation.builders; +import com.azure.monitor.opentelemetry.exporter.implementation.configuration.ConnectionString; +import com.azure.monitor.opentelemetry.exporter.implementation.configuration.StatsbeatConnectionString; import com.azure.monitor.opentelemetry.exporter.implementation.models.MonitorBase; import com.azure.monitor.opentelemetry.exporter.implementation.models.MonitorDomain; import com.azure.monitor.opentelemetry.exporter.implementation.models.TelemetryItem; @@ -63,12 +65,14 @@ public void setSampleRate(float sampleRate) { telemetryItem.setSampleRate(sampleRate); } - public void setInstrumentationKey(String instrumentationKey) { - telemetryItem.setInstrumentationKey(instrumentationKey); + public void setConnectionString(ConnectionString connectionString) { + telemetryItem.setInstrumentationKey(connectionString.getInstrumentationKey()); + telemetryItem.setIngestionEndpoint(connectionString.getIngestionEndpoint()); } - public void setConnectionString(String connectionString) { - telemetryItem.setConnectionString(connectionString); + public void setConnectionString(StatsbeatConnectionString connectionString) { + telemetryItem.setInstrumentationKey(connectionString.getInstrumentationKey()); + telemetryItem.setIngestionEndpoint(connectionString.getEndpoint()); } public void addTag(String key, String value) { diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoader.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoader.java index 75e53cbc2b5..c712fc68e9c 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoader.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoader.java @@ -30,6 +30,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.net.URL; import java.nio.ByteBuffer; import java.util.regex.Pattern; import javax.annotation.Nullable; @@ -118,7 +119,12 @@ PersistedFile loadTelemetriesFromDisk() { int rawByteLength = (int) tempFile.length() - 36; byte[] telemetryBytes = new byte[rawByteLength]; String instrumentationKey; + URL ingestionEndpoint; try (FileInputStream fileInputStream = new FileInputStream(tempFile)) { + int version = fileInputStream.read(); + if (version == 1) { + // FIXME INGESTION ENDPOINT + } readFully(fileInputStream, ikeyBytes, 36); instrumentationKey = new String(ikeyBytes, UTF_8); if (!isInstrumentationKeyValid(instrumentationKey)) { @@ -130,6 +136,8 @@ PersistedFile loadTelemetriesFromDisk() { } return null; } + // FIXME INGESTION ENDPOINT + ingestionEndpoint = null; readFully(fileInputStream, telemetryBytes, rawByteLength); } catch (IOException e) { @@ -140,7 +148,8 @@ PersistedFile loadTelemetriesFromDisk() { } operationLogger.recordSuccess(); - return new PersistedFile(tempFile, instrumentationKey, ByteBuffer.wrap(telemetryBytes)); + return new PersistedFile( + tempFile, instrumentationKey, ingestionEndpoint, ByteBuffer.wrap(telemetryBytes)); } static boolean isInstrumentationKeyValid(String instrumentationKey) { @@ -206,15 +215,18 @@ void updateProcessedFileStatus(boolean successOrNonRetryableError, File file) { static class PersistedFile { final File file; final String instrumentationKey; + final URL ingestionEndpoint; final ByteBuffer rawBytes; - PersistedFile(File file, String instrumentationKey, ByteBuffer byteBuffer) { + PersistedFile( + File file, String instrumentationKey, URL ingestionEndpoint, ByteBuffer byteBuffer) { if (instrumentationKey == null) { throw new IllegalArgumentException("instrumentation key can not be null."); } this.file = file; this.instrumentationKey = instrumentationKey; + this.ingestionEndpoint = ingestionEndpoint; this.rawBytes = byteBuffer; } } diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileSender.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileSender.java index e518e3f1f2c..706f52f3590 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileSender.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileSender.java @@ -84,6 +84,7 @@ public void run() { telemetryPipeline.send( singletonList(persistedFile.rawBytes), persistedFile.instrumentationKey, + persistedFile.ingestionEndpoint, TelemetryPipelineListener.composite( diagnosticListener, new LocalFileSenderTelemetryPipelineListener( diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java index 8d2418d7f94..119308fb784 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java @@ -24,6 +24,7 @@ import com.azure.core.annotation.Fluent; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; +import java.net.URL; import java.time.OffsetDateTime; import java.util.Map; @@ -77,7 +78,7 @@ public final class TelemetryItem { @JsonProperty(value = "iKey") private String instrumentationKey; - @JsonIgnore private String connectionString; + @JsonIgnore private URL ingestionEndpoint; /* * Key/value collection of context properties. See ContextTagKeys for @@ -230,12 +231,12 @@ public TelemetryItem setInstrumentationKey(String instrumentationKey) { return this; } - public String getConnectionString() { - return connectionString; + public URL getIngestionEndpoint() { + return ingestionEndpoint; } - public void setConnectionString(String connectionString) { - this.connectionString = connectionString; + public void setIngestionEndpoint(URL ingestionEndpoint) { + this.ingestionEndpoint = ingestionEndpoint; } /** diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporter.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporter.java index 5bfccf1b139..72f21db1f5f 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporter.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporter.java @@ -33,6 +33,7 @@ import io.opentelemetry.sdk.common.CompletableResultCode; import java.io.IOException; import java.io.StringWriter; +import java.net.URL; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; @@ -99,7 +100,10 @@ public CompletableResultCode send(List telemetryItems) { } List resultCodeList = new ArrayList<>(); for (Map.Entry> entry : instrumentationKeyMap.entrySet()) { - resultCodeList.add(internalSendByInstrumentationKey(entry.getValue(), entry.getKey())); + resultCodeList.add( + internalSendByInstrumentationKey( + // FIXME INGESTION ENDPOINT + entry.getValue(), entry.getKey(), telemetryItems.get(0).getIngestionEndpoint())); } return maybeAddToActiveExportResults(resultCodeList); } @@ -133,7 +137,7 @@ public CompletableResultCode shutdown() { } CompletableResultCode internalSendByInstrumentationKey( - List telemetryItems, String instrumentationKey) { + List telemetryItems, String instrumentationKey, URL ingestionEndpoint) { List byteBuffers; try { byteBuffers = encode(telemetryItems); @@ -142,7 +146,7 @@ CompletableResultCode internalSendByInstrumentationKey( encodeBatchOperationLogger.recordFailure(t.getMessage(), t); return CompletableResultCode.ofFailure(); } - return telemetryPipeline.send(byteBuffers, instrumentationKey, listener); + return telemetryPipeline.send(byteBuffers, instrumentationKey, ingestionEndpoint, listener); } List encode(List telemetryItems) throws IOException { diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryPipeline.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryPipeline.java index 0b3206c85cf..f8e08721e2e 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryPipeline.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryPipeline.java @@ -35,7 +35,6 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.function.Supplier; import reactor.core.publisher.Mono; public class TelemetryPipeline { @@ -44,7 +43,6 @@ public class TelemetryPipeline { private static final int MAX_REDIRECTS = 10; private final HttpPipeline pipeline; - private final Supplier endpoint; // key is instrumentationKey, value is redirectUrl private final Map redirectCache = @@ -56,15 +54,19 @@ protected boolean removeEldestEntry(Map.Entry eldest) { } }); - public TelemetryPipeline(HttpPipeline pipeline, Supplier endpoint) { + public TelemetryPipeline(HttpPipeline pipeline) { this.pipeline = pipeline; - this.endpoint = endpoint; } public CompletableResultCode send( - List telemetry, String instrumentationKey, TelemetryPipelineListener listener) { - - URL url = redirectCache.computeIfAbsent(instrumentationKey, k -> defaultUrl()); + List telemetry, + String instrumentationKey, + URL ingestionEndpoint, + TelemetryPipelineListener listener) { + + URL url = + redirectCache.computeIfAbsent( + instrumentationKey, ikey -> getFullIngestionUrl(ingestionEndpoint)); TelemetryPipelineRequest request = new TelemetryPipelineRequest(url, instrumentationKey, telemetry); @@ -78,9 +80,9 @@ public CompletableResultCode send( } } - private URL defaultUrl() { + private static URL getFullIngestionUrl(URL endpoint) { try { - return new URL(endpoint.get(), "v2.1/track"); + return new URL(endpoint, "v2.1/track"); } catch (MalformedURLException e) { throw new IllegalArgumentException("Invalid endpoint: " + endpoint, e); } diff --git a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/IntegrationTests.java b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/IntegrationTests.java index 33b195731a9..c3fa5591332 100644 --- a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/IntegrationTests.java +++ b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/IntegrationTests.java @@ -89,7 +89,7 @@ public void setup() throws Exception { HttpPipelineBuilder pipelineBuilder = new HttpPipelineBuilder().httpClient(mockedClient); URL url = new URL("http://foo.bar"); - TelemetryPipeline telemetryPipeline = new TelemetryPipeline(pipelineBuilder.build(), () -> url); + TelemetryPipeline telemetryPipeline = new TelemetryPipeline(pipelineBuilder.build()); telemetryItemExporter = new TelemetryItemExporter( telemetryPipeline, diff --git a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoaderTests.java b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoaderTests.java index b4822e1bcce..67367d7981d 100644 --- a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoaderTests.java +++ b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoaderTests.java @@ -247,7 +247,7 @@ public void testDeleteFilePermanentlyOnSuccess() throws Exception { LocalFileLoader localFileLoader = new LocalFileLoader(localFileCache, tempFolder, null, false); URL url = new URL("http://foo.bar"); - TelemetryPipeline telemetryPipeline = new TelemetryPipeline(pipelineBuilder.build(), () -> url); + TelemetryPipeline telemetryPipeline = new TelemetryPipeline(pipelineBuilder.build()); // persist 10 files to disk for (int i = 0; i < 10; i++) { @@ -269,6 +269,7 @@ public void testDeleteFilePermanentlyOnSuccess() throws Exception { telemetryPipeline.send( singletonList(persistedFile.rawBytes), persistedFile.instrumentationKey, + persistedFile.ingestionEndpoint, new LocalFileSenderTelemetryPipelineListener(localFileLoader, persistedFile.file)); completableResultCode.join(10, SECONDS); assertThat(completableResultCode.isSuccess()).isEqualTo(true); @@ -298,8 +299,7 @@ public void testDeleteFilePermanentlyOnFailure() throws Exception { LocalFileWriter localFileWriter = new LocalFileWriter(50, localFileCache, tempFolder, null, false); - URL url = new URL("http://foo.bar"); - TelemetryPipeline telemetryPipeline = new TelemetryPipeline(pipelineBuilder.build(), () -> url); + TelemetryPipeline telemetryPipeline = new TelemetryPipeline(pipelineBuilder.build()); // persist 10 files to disk for (int i = 0; i < 10; i++) { @@ -321,6 +321,7 @@ public void testDeleteFilePermanentlyOnFailure() throws Exception { telemetryPipeline.send( singletonList(persistedFile.rawBytes), persistedFile.instrumentationKey, + persistedFile.ingestionEndpoint, new LocalFileSenderTelemetryPipelineListener(localFileLoader, persistedFile.file)); completableResultCode.join(10, SECONDS); assertThat(completableResultCode.isSuccess()).isEqualTo(false); diff --git a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporterTest.java b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporterTest.java index 96c53597979..7efd21c4672 100644 --- a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporterTest.java +++ b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporterTest.java @@ -67,7 +67,7 @@ public class TelemetryItemExporterTest { private TelemetryItemExporter getExporter() throws MalformedURLException { HttpPipelineBuilder pipelineBuilder = new HttpPipelineBuilder().httpClient(recordingHttpClient); URL url = new URL(END_POINT_URL); - TelemetryPipeline telemetryPipeline = new TelemetryPipeline(pipelineBuilder.build(), () -> url); + TelemetryPipeline telemetryPipeline = new TelemetryPipeline(pipelineBuilder.build()); return new TelemetryItemExporter( telemetryPipeline, From 5e1c40ad8f8ffbd14cb544c3bcf99d3cecb5ea84 Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Fri, 26 Aug 2022 21:50:57 -0700 Subject: [PATCH 04/17] Smoke tests --- .../configuration/ConfigurationBuilder.java | 2 +- .../DiagnosticTelemetryPipelineListener.java | 26 ++-- settings.gradle | 3 + .../build.gradle.kts | 7 + .../ConnectionStringOverridesServlet.java | 128 +++++++++++++++++ .../ConnectionStringOverridesTest.java | 133 ++++++++++++++++++ .../resources/applicationinsights.json | 21 +++ .../src/smokeTest/resources/logback-test.xml | 11 ++ .../build.gradle.kts | 7 + .../InstrumentationKeyOverridesServlet.java | 128 +++++++++++++++++ .../InstrumentationKeyOverridesTest.java | 107 ++++++++++++++ .../resources/applicationinsights.json | 21 +++ .../src/smokeTest/resources/logback-test.xml | 11 ++ .../apps/RoleNameOverrides/build.gradle.kts | 7 + .../RoleNameOverridesServlet.java | 128 +++++++++++++++++ .../smoketest/RoleNameOverridesTest.java | 131 +++++++++++++++++ .../resources/applicationinsights.json | 21 +++ .../src/smokeTest/resources/logback-test.xml | 11 ++ .../smoketest/SamplingOverridesTest.java | 8 +- .../resources/applicationinsights.json | 22 +-- .../SamplingOverridesBackCompatTest.java | 2 +- 21 files changed, 893 insertions(+), 42 deletions(-) create mode 100644 smoke-tests/apps/ConnectionStringOverrides/build.gradle.kts create mode 100644 smoke-tests/apps/ConnectionStringOverrides/src/main/java/com/microsoft/applicationinsights/smoketestapp/ConnectionStringOverridesServlet.java create mode 100644 smoke-tests/apps/ConnectionStringOverrides/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/ConnectionStringOverridesTest.java create mode 100644 smoke-tests/apps/ConnectionStringOverrides/src/smokeTest/resources/applicationinsights.json create mode 100644 smoke-tests/apps/ConnectionStringOverrides/src/smokeTest/resources/logback-test.xml create mode 100644 smoke-tests/apps/InstrumentationKeyOverrides/build.gradle.kts create mode 100644 smoke-tests/apps/InstrumentationKeyOverrides/src/main/java/com/microsoft/applicationinsights/smoketestapp/InstrumentationKeyOverridesServlet.java create mode 100644 smoke-tests/apps/InstrumentationKeyOverrides/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/InstrumentationKeyOverridesTest.java create mode 100644 smoke-tests/apps/InstrumentationKeyOverrides/src/smokeTest/resources/applicationinsights.json create mode 100644 smoke-tests/apps/InstrumentationKeyOverrides/src/smokeTest/resources/logback-test.xml create mode 100644 smoke-tests/apps/RoleNameOverrides/build.gradle.kts create mode 100644 smoke-tests/apps/RoleNameOverrides/src/main/java/com/microsoft/applicationinsights/smoketestapp/RoleNameOverridesServlet.java create mode 100644 smoke-tests/apps/RoleNameOverrides/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/RoleNameOverridesTest.java create mode 100644 smoke-tests/apps/RoleNameOverrides/src/smokeTest/resources/applicationinsights.json create mode 100644 smoke-tests/apps/RoleNameOverrides/src/smokeTest/resources/logback-test.xml diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/configuration/ConfigurationBuilder.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/configuration/ConfigurationBuilder.java index 28b97b1742c..d270d5d5bb8 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/configuration/ConfigurationBuilder.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/configuration/ConfigurationBuilder.java @@ -204,7 +204,7 @@ private static void logConfigurationWarnings(Configuration config) { } if (!config.preview.instrumentationKeyOverrides.isEmpty()) { configurationLogger.warn( - "Instrumentation key overrides hav been deprecated," + "Instrumentation key overrides have been deprecated," + " and support for it will be removed in a future release, please transition from" + " \"instrumentationKeyOverrides\" to \"connectionStringOverrides\"."); for (InstrumentationKeyOverride override : config.preview.instrumentationKeyOverrides) { diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/logging/DiagnosticTelemetryPipelineListener.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/logging/DiagnosticTelemetryPipelineListener.java index d7c9cfb2908..f1812626afc 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/logging/DiagnosticTelemetryPipelineListener.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/logging/DiagnosticTelemetryPipelineListener.java @@ -33,7 +33,9 @@ import io.opentelemetry.sdk.common.CompletableResultCode; import java.util.ArrayList; import java.util.List; +import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -65,7 +67,9 @@ public void onResponse(TelemetryPipelineRequest request, TelemetryPipelineRespon case 206: // PARTIAL CONTENT, Breeze-specific: PARTIAL SUCCESS case 400: // breeze returns if json content is bad (e.g. missing required field) operationLogger.recordFailure( - getErrorMessageFromPartialSuccessResponse(response.getBody(), responseCode), + "Received response code 400 (" + + getErrorMessageFromPartialSuccessResponse(response.getBody()) + + ")", INGESTION_ERROR); break; case 307: @@ -120,23 +124,21 @@ public CompletableResultCode shutdown() { return CompletableResultCode.ofSuccess(); } - private static String getErrorMessageFromPartialSuccessResponse(String body, int responseCode) { + private static String getErrorMessageFromPartialSuccessResponse(String body) { JsonNode jsonNode; try { jsonNode = new ObjectMapper().readTree(body); } catch (JsonProcessingException e) { // fallback to generic message - return "received response code: " + responseCode; + return "Could not parse response"; } - List errors = new ArrayList<>(); - jsonNode.get("errors").forEach(errors::add); - StringBuilder message = new StringBuilder(); - message.append(errors.get(0).get("message").asText()); - int moreErrors = errors.size() - 1; - if (moreErrors > 0) { - message.append(" (and ").append(moreErrors).append(" more)"); - } - return message.toString(); + List errorNodes = new ArrayList<>(); + jsonNode.get("errors").forEach(errorNodes::add); + Set errors = + errorNodes.stream() + .map(errorNode -> errorNode.get("message").asText()) + .collect(Collectors.toSet()); + return String.join(", ", errors); } private static String getErrorMessageFromCredentialRelatedResponse( diff --git a/settings.gradle b/settings.gradle index 469a811bbeb..dce3f4f6ffb 100644 --- a/settings.gradle +++ b/settings.gradle @@ -82,6 +82,7 @@ include ':smoke-tests:apps:AzureSdk' include ':smoke-tests:apps:Cassandra' include ':smoke-tests:apps:ClassicSdkWebInterop2x' include ':smoke-tests:apps:ClassicSdkWebInterop3x' +include ':smoke-tests:apps:ConnectionStringOverrides' include ':smoke-tests:apps:CoreAndFilter2x' include ':smoke-tests:apps:CoreAndFilter3x' include ':smoke-tests:apps:CustomDimensions' @@ -93,6 +94,7 @@ include ':smoke-tests:apps:HttpHeaders' include ':smoke-tests:apps:HttpPreaggregatedMetrics' include ':smoke-tests:apps:HttpServer4xx' include ':smoke-tests:apps:InheritedAttributes' +include ':smoke-tests:apps:InstrumentationKeyOverrides' include ':smoke-tests:apps:Jdbc' include ':smoke-tests:apps:Jedis' include ':smoke-tests:apps:JettyNativeHandler' @@ -106,6 +108,7 @@ include ':smoke-tests:apps:OpenTelemetryApiSupport' include ':smoke-tests:apps:OpenTelemetryMetric' include ':smoke-tests:apps:RateLimitedSampling' include ':smoke-tests:apps:ReadOnly' +include ':smoke-tests:apps:RoleNameOverrides' include ':smoke-tests:apps:Sampling' include ':smoke-tests:apps:SamplingOverrides' include ':smoke-tests:apps:SamplingOverridesBackCompat' diff --git a/smoke-tests/apps/ConnectionStringOverrides/build.gradle.kts b/smoke-tests/apps/ConnectionStringOverrides/build.gradle.kts new file mode 100644 index 00000000000..1b1cfb106e9 --- /dev/null +++ b/smoke-tests/apps/ConnectionStringOverrides/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + id("ai.smoke-test-war") +} + +dependencies { + implementation("org.hsqldb:hsqldb:2.5.1") +} diff --git a/smoke-tests/apps/ConnectionStringOverrides/src/main/java/com/microsoft/applicationinsights/smoketestapp/ConnectionStringOverridesServlet.java b/smoke-tests/apps/ConnectionStringOverrides/src/main/java/com/microsoft/applicationinsights/smoketestapp/ConnectionStringOverridesServlet.java new file mode 100644 index 00000000000..b7aaf01869a --- /dev/null +++ b/smoke-tests/apps/ConnectionStringOverrides/src/main/java/com/microsoft/applicationinsights/smoketestapp/ConnectionStringOverridesServlet.java @@ -0,0 +1,128 @@ +/* + * ApplicationInsights-Java + * Copyright (c) Microsoft Corporation + * All rights reserved. + * + * MIT License + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the ""Software""), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package com.microsoft.applicationinsights.smoketestapp; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.concurrent.Callable; +import java.util.logging.Logger; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.hsqldb.jdbc.JDBCDriver; + +@WebServlet("/*") +public class ConnectionStringOverridesServlet extends HttpServlet { + + private static final Logger logger = Logger.getLogger("smoketestapp"); + + public void init() throws ServletException { + try { + setupHsqldb(); + } catch (Exception e) { + // surprisingly not all application servers seem to log init exceptions to stdout + e.printStackTrace(); + throw new ServletException(e); + } + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException { + try { + int statusCode = doGetInternal(req); + resp.getWriter().println(statusCode); + } catch (ServletException e) { + throw e; + } catch (Exception e) { + throw new ServletException(e); + } + } + + private int doGetInternal(HttpServletRequest req) throws Exception { + String pathInfo = req.getPathInfo(); + if (pathInfo.equals("/")) { + return 200; + } else if (pathInfo.startsWith("/app")) { + Connection connection = getHsqldbConnection(); + executeStatement(connection); + connection.close(); + logger.info("hello"); + return 200; + } else { + throw new ServletException("Unexpected url: " + pathInfo); + } + } + + private static Connection getHsqldbConnection() throws Exception { + return JDBCDriver.getConnection("jdbc:hsqldb:mem:testdb", null); + } + + private void executeStatement(Connection connection) throws SQLException { + Statement statement = connection.createStatement(); + ResultSet rs = statement.executeQuery("select * from abc"); + while (rs.next()) {} + rs.close(); + statement.close(); + } + + private static void setupHsqldb() throws Exception { + Connection connection = + getConnection( + new Callable() { + @Override + public Connection call() throws Exception { + return getHsqldbConnection(); + } + }); + setup(connection); + connection.close(); + } + + private static Connection getConnection(Callable callable) throws Exception { + Exception exception; + long startTimeMillis = System.currentTimeMillis(); + do { + try { + return callable.call(); + } catch (Exception e) { + exception = e; + } + } while (System.currentTimeMillis() - startTimeMillis < 30000); + throw exception; + } + + private static void setup(Connection connection) throws SQLException { + Statement statement = connection.createStatement(); + try { + statement.execute("create table abc (xyz varchar(10))"); + statement.execute("insert into abc (xyz) values ('x')"); + statement.execute("insert into abc (xyz) values ('y')"); + statement.execute("insert into abc (xyz) values ('z')"); + } finally { + statement.close(); + } + } +} diff --git a/smoke-tests/apps/ConnectionStringOverrides/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/ConnectionStringOverridesTest.java b/smoke-tests/apps/ConnectionStringOverrides/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/ConnectionStringOverridesTest.java new file mode 100644 index 00000000000..ecd156c4e12 --- /dev/null +++ b/smoke-tests/apps/ConnectionStringOverrides/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/ConnectionStringOverridesTest.java @@ -0,0 +1,133 @@ +/* + * ApplicationInsights-Java + * Copyright (c) Microsoft Corporation + * All rights reserved. + * + * MIT License + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the ""Software""), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package com.microsoft.applicationinsights.smoketest; + +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.TOMCAT_8_JAVA_11; +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.TOMCAT_8_JAVA_11_OPENJ9; +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.TOMCAT_8_JAVA_17; +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.TOMCAT_8_JAVA_18; +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.TOMCAT_8_JAVA_19; +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.TOMCAT_8_JAVA_8; +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.TOMCAT_8_JAVA_8_OPENJ9; +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.WILDFLY_13_JAVA_8; +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.WILDFLY_13_JAVA_8_OPENJ9; +import static org.assertj.core.api.Assertions.assertThat; + +import com.microsoft.applicationinsights.smoketest.schemav2.Data; +import com.microsoft.applicationinsights.smoketest.schemav2.Envelope; +import com.microsoft.applicationinsights.smoketest.schemav2.MessageData; +import com.microsoft.applicationinsights.smoketest.schemav2.RemoteDependencyData; +import com.microsoft.applicationinsights.smoketest.schemav2.RequestData; +import com.microsoft.applicationinsights.smoketest.schemav2.SeverityLevel; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +@UseAgent +abstract class ConnectionStringOverridesTest { + + @RegisterExtension static final SmokeTestExtension testing = SmokeTestExtension.create(); + + @Test + @TargetUri("/app2") + void testApp2() throws Exception { + testApp("12345678-0000-0000-0000-0FEEDDADBEEF"); + } + + @Test + @TargetUri("/app3") + void testApp3() throws Exception { + testApp("87654321-0000-0000-0000-0FEEDDADBEEF"); + } + + private static void testApp(String iKey) throws Exception { + List rdList = testing.mockedIngestion.waitForItems("RequestData", 1); + + Envelope rdEnvelope = rdList.get(0); + String operationId = rdEnvelope.getTags().get("ai.operation.id"); + + List rddList = + testing.mockedIngestion.waitForItemsInOperation("RemoteDependencyData", 1, operationId); + List mdList = + testing.mockedIngestion.waitForItemsInOperation("MessageData", 1, operationId); + assertThat(testing.mockedIngestion.getCountForType("EventData")).isZero(); + + Envelope rddEnvelope = rddList.get(0); + Envelope mdEnvelope = mdList.get(0); + + RequestData rd = (RequestData) ((Data) rdEnvelope.getData()).getBaseData(); + RemoteDependencyData rdd = + (RemoteDependencyData) ((Data) rddEnvelope.getData()).getBaseData(); + MessageData md = (MessageData) ((Data) mdEnvelope.getData()).getBaseData(); + + assertThat(rdEnvelope.getIKey()).isEqualTo(iKey); + assertThat(rddEnvelope.getIKey()).isEqualTo(iKey); + assertThat(mdEnvelope.getIKey()).isEqualTo(iKey); + + assertThat(rd.getSuccess()).isTrue(); + + assertThat(rdd.getType()).isEqualTo("SQL"); + assertThat(rdd.getTarget()).isEqualTo("hsqldb | testdb"); + assertThat(rdd.getName()).isEqualTo("SELECT testdb.abc"); + assertThat(rdd.getData()).isEqualTo("select * from abc"); + assertThat(rdd.getSuccess()).isTrue(); + + assertThat(md.getMessage()).isEqualTo("hello"); + assertThat(md.getSeverityLevel()).isEqualTo(SeverityLevel.INFORMATION); + assertThat(md.getProperties()).containsEntry("SourceType", "Logger"); + assertThat(md.getProperties()).containsEntry("LoggerName", "smoketestapp"); + assertThat(md.getProperties()).containsKey("ThreadName"); + assertThat(md.getProperties()).hasSize(3); + + SmokeTestExtension.assertParentChild( + rd, rdEnvelope, rddEnvelope, "GET /ConnectionStringOverrides/*"); + SmokeTestExtension.assertParentChild( + rd, rdEnvelope, mdEnvelope, "GET /ConnectionStringOverrides/*"); + } + + @Environment(TOMCAT_8_JAVA_8) + static class Tomcat8Java8Test extends ConnectionStringOverridesTest {} + + @Environment(TOMCAT_8_JAVA_8_OPENJ9) + static class Tomcat8Java8OpenJ9Test extends ConnectionStringOverridesTest {} + + @Environment(TOMCAT_8_JAVA_11) + static class Tomcat8Java11Test extends ConnectionStringOverridesTest {} + + @Environment(TOMCAT_8_JAVA_11_OPENJ9) + static class Tomcat8Java11OpenJ9Test extends ConnectionStringOverridesTest {} + + @Environment(TOMCAT_8_JAVA_17) + static class Tomcat8Java17Test extends ConnectionStringOverridesTest {} + + @Environment(TOMCAT_8_JAVA_18) + static class Tomcat8Java18Test extends ConnectionStringOverridesTest {} + + @Environment(TOMCAT_8_JAVA_19) + static class Tomcat8Java19Test extends ConnectionStringOverridesTest {} + + @Environment(WILDFLY_13_JAVA_8) + static class Wildfly13Java8Test extends ConnectionStringOverridesTest {} + + @Environment(WILDFLY_13_JAVA_8_OPENJ9) + static class Wildfly13Java8OpenJ9Test extends ConnectionStringOverridesTest {} +} diff --git a/smoke-tests/apps/ConnectionStringOverrides/src/smokeTest/resources/applicationinsights.json b/smoke-tests/apps/ConnectionStringOverrides/src/smokeTest/resources/applicationinsights.json new file mode 100644 index 00000000000..01f70f841b4 --- /dev/null +++ b/smoke-tests/apps/ConnectionStringOverrides/src/smokeTest/resources/applicationinsights.json @@ -0,0 +1,21 @@ +{ + "role": { + "name": "testrolename", + "instance": "testroleinstance" + }, + "sampling": { + "percentage": 100 + }, + "preview": { + "connectionStringOverrides": [ + { + "httpPathPrefix": "/ConnectionStringOverrides/app2", + "connectionString": "InstrumentationKey=12345678-0000-0000-0000-0FEEDDADBEEF;IngestionEndpoint=http://host.testcontainers.internal:6060/" + }, + { + "httpPathPrefix": "/ConnectionStringOverrides/app3", + "connectionString": "InstrumentationKey=87654321-0000-0000-0000-0FEEDDADBEEF;IngestionEndpoint=http://host.testcontainers.internal:6060/" + } + ] + } +} diff --git a/smoke-tests/apps/ConnectionStringOverrides/src/smokeTest/resources/logback-test.xml b/smoke-tests/apps/ConnectionStringOverrides/src/smokeTest/resources/logback-test.xml new file mode 100644 index 00000000000..0cbbecd57ce --- /dev/null +++ b/smoke-tests/apps/ConnectionStringOverrides/src/smokeTest/resources/logback-test.xml @@ -0,0 +1,11 @@ + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger{36} - %msg%n + + + + + + diff --git a/smoke-tests/apps/InstrumentationKeyOverrides/build.gradle.kts b/smoke-tests/apps/InstrumentationKeyOverrides/build.gradle.kts new file mode 100644 index 00000000000..1b1cfb106e9 --- /dev/null +++ b/smoke-tests/apps/InstrumentationKeyOverrides/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + id("ai.smoke-test-war") +} + +dependencies { + implementation("org.hsqldb:hsqldb:2.5.1") +} diff --git a/smoke-tests/apps/InstrumentationKeyOverrides/src/main/java/com/microsoft/applicationinsights/smoketestapp/InstrumentationKeyOverridesServlet.java b/smoke-tests/apps/InstrumentationKeyOverrides/src/main/java/com/microsoft/applicationinsights/smoketestapp/InstrumentationKeyOverridesServlet.java new file mode 100644 index 00000000000..5a70c27c37d --- /dev/null +++ b/smoke-tests/apps/InstrumentationKeyOverrides/src/main/java/com/microsoft/applicationinsights/smoketestapp/InstrumentationKeyOverridesServlet.java @@ -0,0 +1,128 @@ +/* + * ApplicationInsights-Java + * Copyright (c) Microsoft Corporation + * All rights reserved. + * + * MIT License + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the ""Software""), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package com.microsoft.applicationinsights.smoketestapp; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.concurrent.Callable; +import java.util.logging.Logger; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.hsqldb.jdbc.JDBCDriver; + +@WebServlet("/*") +public class InstrumentationKeyOverridesServlet extends HttpServlet { + + private static final Logger logger = Logger.getLogger("smoketestapp"); + + public void init() throws ServletException { + try { + setupHsqldb(); + } catch (Exception e) { + // surprisingly not all application servers seem to log init exceptions to stdout + e.printStackTrace(); + throw new ServletException(e); + } + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException { + try { + int statusCode = doGetInternal(req); + resp.getWriter().println(statusCode); + } catch (ServletException e) { + throw e; + } catch (Exception e) { + throw new ServletException(e); + } + } + + private int doGetInternal(HttpServletRequest req) throws Exception { + String pathInfo = req.getPathInfo(); + if (pathInfo.equals("/")) { + return 200; + } else if (pathInfo.startsWith("/app")) { + Connection connection = getHsqldbConnection(); + executeStatement(connection); + connection.close(); + logger.info("hello"); + return 200; + } else { + throw new ServletException("Unexpected url: " + pathInfo); + } + } + + private static Connection getHsqldbConnection() throws Exception { + return JDBCDriver.getConnection("jdbc:hsqldb:mem:testdb", null); + } + + private void executeStatement(Connection connection) throws SQLException { + Statement statement = connection.createStatement(); + ResultSet rs = statement.executeQuery("select * from abc"); + while (rs.next()) {} + rs.close(); + statement.close(); + } + + private static void setupHsqldb() throws Exception { + Connection connection = + getConnection( + new Callable() { + @Override + public Connection call() throws Exception { + return getHsqldbConnection(); + } + }); + setup(connection); + connection.close(); + } + + private static Connection getConnection(Callable callable) throws Exception { + Exception exception; + long startTimeMillis = System.currentTimeMillis(); + do { + try { + return callable.call(); + } catch (Exception e) { + exception = e; + } + } while (System.currentTimeMillis() - startTimeMillis < 30000); + throw exception; + } + + private static void setup(Connection connection) throws SQLException { + Statement statement = connection.createStatement(); + try { + statement.execute("create table abc (xyz varchar(10))"); + statement.execute("insert into abc (xyz) values ('x')"); + statement.execute("insert into abc (xyz) values ('y')"); + statement.execute("insert into abc (xyz) values ('z')"); + } finally { + statement.close(); + } + } +} diff --git a/smoke-tests/apps/InstrumentationKeyOverrides/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/InstrumentationKeyOverridesTest.java b/smoke-tests/apps/InstrumentationKeyOverrides/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/InstrumentationKeyOverridesTest.java new file mode 100644 index 00000000000..829ad0853cb --- /dev/null +++ b/smoke-tests/apps/InstrumentationKeyOverrides/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/InstrumentationKeyOverridesTest.java @@ -0,0 +1,107 @@ +/* + * ApplicationInsights-Java + * Copyright (c) Microsoft Corporation + * All rights reserved. + * + * MIT License + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the ""Software""), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package com.microsoft.applicationinsights.smoketest; + +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.TOMCAT_8_JAVA_8; +import static org.assertj.core.api.Assertions.assertThat; + +import com.microsoft.applicationinsights.smoketest.schemav2.Data; +import com.microsoft.applicationinsights.smoketest.schemav2.Envelope; +import com.microsoft.applicationinsights.smoketest.schemav2.MessageData; +import com.microsoft.applicationinsights.smoketest.schemav2.RemoteDependencyData; +import com.microsoft.applicationinsights.smoketest.schemav2.RequestData; +import com.microsoft.applicationinsights.smoketest.schemav2.SeverityLevel; +import java.util.List; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +@UseAgent +@Environment(TOMCAT_8_JAVA_8) +class InstrumentationKeyOverridesTest { + + @RegisterExtension static final SmokeTestExtension testing = SmokeTestExtension.create(); + + // unfortunately, these tests don't pass, because instrumentation keys without ingestion endpoints + // (correctly) send to the default ingestion endpoint (https://dc.services.visualstudio.com/) + @Disabled + @Test + @TargetUri("/app2") + void testApp2() throws Exception { + testApp("12345678-0000-0000-0000-0FEEDDADBEEF"); + } + + // unfortunately, these tests don't pass, because instrumentation keys without ingestion endpoints + // (correctly) send to the default ingestion endpoint (https://dc.services.visualstudio.com/) + @Disabled + @Test + @TargetUri("/app3") + void testApp3() throws Exception { + testApp("87654321-0000-0000-0000-0FEEDDADBEEF"); + } + + private static void testApp(String iKey) throws Exception { + List rdList = testing.mockedIngestion.waitForItems("RequestData", 1); + + Envelope rdEnvelope = rdList.get(0); + String operationId = rdEnvelope.getTags().get("ai.operation.id"); + + List rddList = + testing.mockedIngestion.waitForItemsInOperation("RemoteDependencyData", 1, operationId); + List mdList = + testing.mockedIngestion.waitForItemsInOperation("MessageData", 1, operationId); + assertThat(testing.mockedIngestion.getCountForType("EventData")).isZero(); + + Envelope rddEnvelope = rddList.get(0); + Envelope mdEnvelope = mdList.get(0); + + RequestData rd = (RequestData) ((Data) rdEnvelope.getData()).getBaseData(); + RemoteDependencyData rdd = + (RemoteDependencyData) ((Data) rddEnvelope.getData()).getBaseData(); + MessageData md = (MessageData) ((Data) mdEnvelope.getData()).getBaseData(); + + assertThat(rdEnvelope.getIKey()).isEqualTo(iKey); + assertThat(rddEnvelope.getIKey()).isEqualTo(iKey); + assertThat(mdEnvelope.getIKey()).isEqualTo(iKey); + + assertThat(rd.getSuccess()).isTrue(); + + assertThat(rdd.getType()).isEqualTo("SQL"); + assertThat(rdd.getTarget()).isEqualTo("hsqldb | testdb"); + assertThat(rdd.getName()).isEqualTo("SELECT testdb.abc"); + assertThat(rdd.getData()).isEqualTo("select * from abc"); + assertThat(rddEnvelope.getIKey()).isEqualTo(iKey); + assertThat(rdd.getSuccess()).isTrue(); + + assertThat(md.getMessage()).isEqualTo("hello"); + assertThat(md.getSeverityLevel()).isEqualTo(SeverityLevel.INFORMATION); + assertThat(md.getProperties()).containsEntry("SourceType", "Logger"); + assertThat(md.getProperties()).containsEntry("LoggerName", "smoketestapp"); + assertThat(md.getProperties()).containsKey("ThreadName"); + assertThat(md.getProperties()).hasSize(3); + + SmokeTestExtension.assertParentChild( + rd, rdEnvelope, rddEnvelope, "GET /ConnectionStringOverrides/*"); + SmokeTestExtension.assertParentChild( + rd, rdEnvelope, mdEnvelope, "GET /ConnectionStringOverrides/*"); + } +} diff --git a/smoke-tests/apps/InstrumentationKeyOverrides/src/smokeTest/resources/applicationinsights.json b/smoke-tests/apps/InstrumentationKeyOverrides/src/smokeTest/resources/applicationinsights.json new file mode 100644 index 00000000000..c5ecd59f56e --- /dev/null +++ b/smoke-tests/apps/InstrumentationKeyOverrides/src/smokeTest/resources/applicationinsights.json @@ -0,0 +1,21 @@ +{ + "role": { + "name": "testrolename", + "instance": "testroleinstance" + }, + "sampling": { + "percentage": 100 + }, + "preview": { + "instrumentationKeyOverrides": [ + { + "httpPathPrefix": "/InstrumentationKeyOverrides/app2", + "instrumentationKey": "12345678-0000-0000-0000-0FEEDDADBEEF" + }, + { + "httpPathPrefix": "/InstrumentationKeyOverrides/app3", + "instrumentationKey": "87654321-0000-0000-0000-0FEEDDADBEEF" + } + ] + } +} diff --git a/smoke-tests/apps/InstrumentationKeyOverrides/src/smokeTest/resources/logback-test.xml b/smoke-tests/apps/InstrumentationKeyOverrides/src/smokeTest/resources/logback-test.xml new file mode 100644 index 00000000000..0cbbecd57ce --- /dev/null +++ b/smoke-tests/apps/InstrumentationKeyOverrides/src/smokeTest/resources/logback-test.xml @@ -0,0 +1,11 @@ + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger{36} - %msg%n + + + + + + diff --git a/smoke-tests/apps/RoleNameOverrides/build.gradle.kts b/smoke-tests/apps/RoleNameOverrides/build.gradle.kts new file mode 100644 index 00000000000..1b1cfb106e9 --- /dev/null +++ b/smoke-tests/apps/RoleNameOverrides/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + id("ai.smoke-test-war") +} + +dependencies { + implementation("org.hsqldb:hsqldb:2.5.1") +} diff --git a/smoke-tests/apps/RoleNameOverrides/src/main/java/com/microsoft/applicationinsights/smoketestapp/RoleNameOverridesServlet.java b/smoke-tests/apps/RoleNameOverrides/src/main/java/com/microsoft/applicationinsights/smoketestapp/RoleNameOverridesServlet.java new file mode 100644 index 00000000000..db2d8786547 --- /dev/null +++ b/smoke-tests/apps/RoleNameOverrides/src/main/java/com/microsoft/applicationinsights/smoketestapp/RoleNameOverridesServlet.java @@ -0,0 +1,128 @@ +/* + * ApplicationInsights-Java + * Copyright (c) Microsoft Corporation + * All rights reserved. + * + * MIT License + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the ""Software""), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package com.microsoft.applicationinsights.smoketestapp; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.concurrent.Callable; +import java.util.logging.Logger; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.hsqldb.jdbc.JDBCDriver; + +@WebServlet("/*") +public class RoleNameOverridesServlet extends HttpServlet { + + private static final Logger logger = Logger.getLogger("smoketestapp"); + + public void init() throws ServletException { + try { + setupHsqldb(); + } catch (Exception e) { + // surprisingly not all application servers seem to log init exceptions to stdout + e.printStackTrace(); + throw new ServletException(e); + } + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException { + try { + int statusCode = doGetInternal(req); + resp.getWriter().println(statusCode); + } catch (ServletException e) { + throw e; + } catch (Exception e) { + throw new ServletException(e); + } + } + + private int doGetInternal(HttpServletRequest req) throws Exception { + String pathInfo = req.getPathInfo(); + if (pathInfo.equals("/")) { + return 200; + } else if (pathInfo.startsWith("/app")) { + Connection connection = getHsqldbConnection(); + executeStatement(connection); + connection.close(); + logger.info("hello"); + return 200; + } else { + throw new ServletException("Unexpected url: " + pathInfo); + } + } + + private static Connection getHsqldbConnection() throws Exception { + return JDBCDriver.getConnection("jdbc:hsqldb:mem:testdb", null); + } + + private void executeStatement(Connection connection) throws SQLException { + Statement statement = connection.createStatement(); + ResultSet rs = statement.executeQuery("select * from abc"); + while (rs.next()) {} + rs.close(); + statement.close(); + } + + private static void setupHsqldb() throws Exception { + Connection connection = + getConnection( + new Callable() { + @Override + public Connection call() throws Exception { + return getHsqldbConnection(); + } + }); + setup(connection); + connection.close(); + } + + private static Connection getConnection(Callable callable) throws Exception { + Exception exception; + long startTimeMillis = System.currentTimeMillis(); + do { + try { + return callable.call(); + } catch (Exception e) { + exception = e; + } + } while (System.currentTimeMillis() - startTimeMillis < 30000); + throw exception; + } + + private static void setup(Connection connection) throws SQLException { + Statement statement = connection.createStatement(); + try { + statement.execute("create table abc (xyz varchar(10))"); + statement.execute("insert into abc (xyz) values ('x')"); + statement.execute("insert into abc (xyz) values ('y')"); + statement.execute("insert into abc (xyz) values ('z')"); + } finally { + statement.close(); + } + } +} diff --git a/smoke-tests/apps/RoleNameOverrides/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/RoleNameOverridesTest.java b/smoke-tests/apps/RoleNameOverrides/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/RoleNameOverridesTest.java new file mode 100644 index 00000000000..4afa9bd9d68 --- /dev/null +++ b/smoke-tests/apps/RoleNameOverrides/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/RoleNameOverridesTest.java @@ -0,0 +1,131 @@ +/* + * ApplicationInsights-Java + * Copyright (c) Microsoft Corporation + * All rights reserved. + * + * MIT License + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the ""Software""), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package com.microsoft.applicationinsights.smoketest; + +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.TOMCAT_8_JAVA_11; +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.TOMCAT_8_JAVA_11_OPENJ9; +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.TOMCAT_8_JAVA_17; +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.TOMCAT_8_JAVA_18; +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.TOMCAT_8_JAVA_19; +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.TOMCAT_8_JAVA_8; +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.TOMCAT_8_JAVA_8_OPENJ9; +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.WILDFLY_13_JAVA_8; +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.WILDFLY_13_JAVA_8_OPENJ9; +import static org.assertj.core.api.Assertions.assertThat; + +import com.microsoft.applicationinsights.smoketest.schemav2.Data; +import com.microsoft.applicationinsights.smoketest.schemav2.Envelope; +import com.microsoft.applicationinsights.smoketest.schemav2.MessageData; +import com.microsoft.applicationinsights.smoketest.schemav2.RemoteDependencyData; +import com.microsoft.applicationinsights.smoketest.schemav2.RequestData; +import com.microsoft.applicationinsights.smoketest.schemav2.SeverityLevel; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +@UseAgent +abstract class RoleNameOverridesTest { + + @RegisterExtension static final SmokeTestExtension testing = SmokeTestExtension.create(); + + @Test + @TargetUri("/app2") + void testApp2() throws Exception { + testApp("app2"); + } + + @Test + @TargetUri("/app3") + void testApp3() throws Exception { + testApp("app3"); + } + + private static void testApp(String roleName) throws Exception { + List rdList = testing.mockedIngestion.waitForItems("RequestData", 1); + + Envelope rdEnvelope = rdList.get(0); + String operationId = rdEnvelope.getTags().get("ai.operation.id"); + + List rddList = + testing.mockedIngestion.waitForItemsInOperation("RemoteDependencyData", 1, operationId); + List mdList = + testing.mockedIngestion.waitForItemsInOperation("MessageData", 1, operationId); + assertThat(testing.mockedIngestion.getCountForType("EventData")).isZero(); + + Envelope rddEnvelope = rddList.get(0); + Envelope mdEnvelope = mdList.get(0); + + RequestData rd = (RequestData) ((Data) rdEnvelope.getData()).getBaseData(); + RemoteDependencyData rdd = + (RemoteDependencyData) ((Data) rddEnvelope.getData()).getBaseData(); + MessageData md = (MessageData) ((Data) mdEnvelope.getData()).getBaseData(); + + assertThat(rdEnvelope.getTags()).containsEntry("ai.cloud.role", roleName); + assertThat(rddEnvelope.getTags()).containsEntry("ai.cloud.role", roleName); + assertThat(mdEnvelope.getTags()).containsEntry("ai.cloud.role", roleName); + + assertThat(rd.getSuccess()).isTrue(); + + assertThat(rdd.getType()).isEqualTo("SQL"); + assertThat(rdd.getTarget()).isEqualTo("hsqldb | testdb"); + assertThat(rdd.getName()).isEqualTo("SELECT testdb.abc"); + assertThat(rdd.getData()).isEqualTo("select * from abc"); + assertThat(rdd.getSuccess()).isTrue(); + + assertThat(md.getMessage()).isEqualTo("hello"); + assertThat(md.getSeverityLevel()).isEqualTo(SeverityLevel.INFORMATION); + assertThat(md.getProperties()).containsEntry("SourceType", "Logger"); + assertThat(md.getProperties()).containsEntry("LoggerName", "smoketestapp"); + assertThat(md.getProperties()).containsKey("ThreadName"); + assertThat(md.getProperties()).hasSize(3); + + SmokeTestExtension.assertParentChild(rd, rdEnvelope, rddEnvelope, "GET /RoleNameOverrides/*"); + SmokeTestExtension.assertParentChild(rd, rdEnvelope, mdEnvelope, "GET /RoleNameOverrides/*"); + } + + @Environment(TOMCAT_8_JAVA_8) + static class Tomcat8Java8Test extends RoleNameOverridesTest {} + + @Environment(TOMCAT_8_JAVA_8_OPENJ9) + static class Tomcat8Java8OpenJ9Test extends RoleNameOverridesTest {} + + @Environment(TOMCAT_8_JAVA_11) + static class Tomcat8Java11Test extends RoleNameOverridesTest {} + + @Environment(TOMCAT_8_JAVA_11_OPENJ9) + static class Tomcat8Java11OpenJ9Test extends RoleNameOverridesTest {} + + @Environment(TOMCAT_8_JAVA_17) + static class Tomcat8Java17Test extends RoleNameOverridesTest {} + + @Environment(TOMCAT_8_JAVA_18) + static class Tomcat8Java18Test extends RoleNameOverridesTest {} + + @Environment(TOMCAT_8_JAVA_19) + static class Tomcat8Java19Test extends RoleNameOverridesTest {} + + @Environment(WILDFLY_13_JAVA_8) + static class Wildfly13Java8Test extends RoleNameOverridesTest {} + + @Environment(WILDFLY_13_JAVA_8_OPENJ9) + static class Wildfly13Java8OpenJ9Test extends RoleNameOverridesTest {} +} diff --git a/smoke-tests/apps/RoleNameOverrides/src/smokeTest/resources/applicationinsights.json b/smoke-tests/apps/RoleNameOverrides/src/smokeTest/resources/applicationinsights.json new file mode 100644 index 00000000000..124efc017f8 --- /dev/null +++ b/smoke-tests/apps/RoleNameOverrides/src/smokeTest/resources/applicationinsights.json @@ -0,0 +1,21 @@ +{ + "role": { + "name": "testrolename", + "instance": "testroleinstance" + }, + "sampling": { + "percentage": 100 + }, + "preview": { + "roleNameOverrides": [ + { + "httpPathPrefix": "/RoleNameOverrides/app2", + "roleName": "app2" + }, + { + "httpPathPrefix": "/RoleNameOverrides/app3", + "roleName": "app3" + } + ] + } +} diff --git a/smoke-tests/apps/RoleNameOverrides/src/smokeTest/resources/logback-test.xml b/smoke-tests/apps/RoleNameOverrides/src/smokeTest/resources/logback-test.xml new file mode 100644 index 00000000000..0cbbecd57ce --- /dev/null +++ b/smoke-tests/apps/RoleNameOverrides/src/smokeTest/resources/logback-test.xml @@ -0,0 +1,11 @@ + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger{36} - %msg%n + + + + + + diff --git a/smoke-tests/apps/SamplingOverrides/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/SamplingOverridesTest.java b/smoke-tests/apps/SamplingOverrides/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/SamplingOverridesTest.java index 8b3b4013400..461d20e9a79 100644 --- a/smoke-tests/apps/SamplingOverrides/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/SamplingOverridesTest.java +++ b/smoke-tests/apps/SamplingOverrides/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/SamplingOverridesTest.java @@ -42,7 +42,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; -@UseAgent("applicationinsights.json") +@UseAgent abstract class SamplingOverridesTest { @RegisterExtension static final SmokeTestExtension testing = SmokeTestExtension.create(); @@ -81,8 +81,6 @@ void testNoisyJdbc() throws Exception { RequestData rd = (RequestData) ((Data) rdEnvelope.getData()).getBaseData(); - assertThat(rdEnvelope.getIKey()).isEqualTo("00000000-0000-0000-0000-0FEEDDADBEEF"); - assertThat(rdEnvelope.getTags()).containsEntry("ai.cloud.role", "testrolename"); assertThat(rd.getSuccess()).isTrue(); } @@ -107,16 +105,12 @@ void testRegularJdbc() throws Exception { RemoteDependencyData rdd = (RemoteDependencyData) ((Data) rddEnvelope.getData()).getBaseData(); - assertThat(rdEnvelope.getIKey()).isEqualTo("87654321-0000-0000-0000-0FEEDDADBEEF"); - assertThat(rdEnvelope.getTags()).containsEntry("ai.cloud.role", "app3"); assertThat(rd.getSuccess()).isTrue(); assertThat(rdd.getType()).isEqualTo("SQL"); assertThat(rdd.getTarget()).isEqualTo("hsqldb | testdb"); assertThat(rdd.getName()).isEqualTo("SELECT testdb.abc"); assertThat(rdd.getData()).isEqualTo("select * from abc"); - assertThat(rddEnvelope.getIKey()).isEqualTo("87654321-0000-0000-0000-0FEEDDADBEEF"); - assertThat(rddEnvelope.getTags()).containsEntry("ai.cloud.role", "app3"); assertThat(rdd.getSuccess()).isTrue(); SmokeTestExtension.assertParentChild(rd, rdEnvelope, rddEnvelope, "GET /SamplingOverrides/*"); diff --git a/smoke-tests/apps/SamplingOverrides/src/smokeTest/resources/applicationinsights.json b/smoke-tests/apps/SamplingOverrides/src/smokeTest/resources/applicationinsights.json index 9609cea21a9..8a8c3730ac3 100644 --- a/smoke-tests/apps/SamplingOverrides/src/smokeTest/resources/applicationinsights.json +++ b/smoke-tests/apps/SamplingOverrides/src/smokeTest/resources/applicationinsights.json @@ -38,26 +38,6 @@ "percentage": 100 } ] - }, - "instrumentationKeyOverrides": [ - { - "httpPathPrefix": "/SamplingOverrides/login", - "instrumentationKey": "12345678-0000-0000-0000-0FEEDDADBEEF" - }, - { - "httpPathPrefix": "/SamplingOverrides/regular-jdbc", - "instrumentationKey": "87654321-0000-0000-0000-0FEEDDADBEEF" - } - ], - "roleNameOverrides": [ - { - "httpPathPrefix": "/SamplingOverrides/login", - "roleName": "app2" - }, - { - "httpPathPrefix": "/SamplingOverrides/regular-jdbc", - "roleName": "app3" - } - ] + } } } diff --git a/smoke-tests/apps/SamplingOverridesBackCompat/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/SamplingOverridesBackCompatTest.java b/smoke-tests/apps/SamplingOverridesBackCompat/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/SamplingOverridesBackCompatTest.java index 1e827d50c37..7864d550a74 100644 --- a/smoke-tests/apps/SamplingOverridesBackCompat/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/SamplingOverridesBackCompatTest.java +++ b/smoke-tests/apps/SamplingOverridesBackCompat/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/SamplingOverridesBackCompatTest.java @@ -42,7 +42,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; -@UseAgent("applicationinsights.json") +@UseAgent abstract class SamplingOverridesBackCompatTest { @RegisterExtension static final SmokeTestExtension testing = SmokeTestExtension.create(); From 3e79115f2c144332bd0c6bd3aa31d3ea7cdc7dd5 Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Sat, 27 Aug 2022 09:22:26 -0700 Subject: [PATCH 05/17] More --- .../agent/bootstrap/BytecodeUtil.java | 52 ++- .../diagnostics/status/StatusFileTests.java | 3 +- .../internal/classicsdk/BytecodeUtilImpl.java | 55 ++- .../TelemetryClientClassFileTransformer.java | 232 +++++++++--- .../TelemetryContextClassFileTransformer.java | 114 ++++++ .../agent/internal/init/AppIdSupplier.java | 2 +- .../internal/init/LegacyInstrumentation.java | 2 + .../builders/AbstractTelemetryBuilder.java | 6 +- .../configuration/ConnectionString.java | 6 +- .../configuration/DefaultEndpoints.java | 9 +- .../StatsbeatConnectionString.java | 20 +- .../localstorage/LocalFileLoader.java | 87 +++-- .../localstorage/LocalFileWriter.java | 24 +- ...LocalStorageTelemetryPipelineListener.java | 6 +- .../implementation/models/TelemetryItem.java | 32 +- .../pipeline/TelemetryItemExporter.java | 26 +- .../pipeline/TelemetryPipeline.java | 10 +- .../pipeline/TelemetryPipelineRequest.java | 13 +- .../AzureMonitorExportersEndToEndTest.java | 13 +- .../MonitorExporterClientTestBase.java | 22 +- .../ConnectionStringParsingTests.java | 101 +++--- .../StatsbeatConnectionStringTest.java | 16 +- .../localstorage/IntegrationTests.java | 53 +-- .../localstorage/LocalFileLoaderTests.java | 338 +----------------- .../localstorage/LocalFilePurgerTests.java | 3 +- .../localstorage/LocalFileWriterTests.java | 44 +-- .../localstorage/Resources.java | 49 +++ .../pipeline/TelemetryItemExporterTest.java | 65 ++-- .../quickpulse/QuickPulseCoordinatorTest.java | 3 +- .../QuickPulseDataCollectorTests.java | 18 +- .../QuickPulseIntegrationTests.java | 6 +- .../implementation/utils/TestUtils.java | 5 +- ...-raw-bytes-without-ingestion-endpoint.trn} | Bin .../src/test/resources/read-transmission.txt | 10 - .../telemetry/TelemetryContext.java | 14 + .../smoketest/CoreAndFilter2xTest.java | 5 +- .../SimpleTrackPageViewServlet.java | 11 +- .../InstrumentationKeyOverridesTest.java | 16 +- .../smoketest/JdbcTest.java | 9 +- .../KafkaControllerSpansEnabledTest.java | 6 +- .../smoketest/KafkaDisabledTest.java | 6 +- .../smoketest/KafkaTest.java | 6 +- .../smoketestapp/TestController.java | 6 +- ...yApiSupportControllerSpansEnabledTest.java | 44 --- ...metryApiSupportInstrumentationKeyTest.java | 91 +++++ .../OpenTelemetryApiSupportTest.java | 28 -- .../smoketest/ReadOnlyTest.java | 3 +- .../SamplingOverridesBackCompatTest.java | 6 - .../resources/applicationinsights.json | 22 +- ...CloudStreamControllerSpansEnabledTest.java | 6 +- .../smoketest/SpringCloudStreamTest.java | 6 +- .../smoketest/SmokeTestExtension.java | 31 +- .../smoketest/SmokeTestExtensionBuilder.java | 64 ++++ 53 files changed, 944 insertions(+), 881 deletions(-) create mode 100644 agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/classicsdk/TelemetryContextClassFileTransformer.java create mode 100644 agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/Resources.java rename agent/azure-monitor-exporter/src/test/resources/{gzipped-raw-bytes.trn => gzipped-raw-bytes-without-ingestion-endpoint.trn} (100%) delete mode 100644 agent/azure-monitor-exporter/src/test/resources/read-transmission.txt create mode 100644 smoke-tests/apps/OpenTelemetryApiSupport/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/OpenTelemetryApiSupportInstrumentationKeyTest.java create mode 100644 smoke-tests/framework/src/main/java/com/microsoft/applicationinsights/smoketest/SmokeTestExtensionBuilder.java diff --git a/agent/agent-bootstrap/src/main/java/com/microsoft/applicationinsights/agent/bootstrap/BytecodeUtil.java b/agent/agent-bootstrap/src/main/java/com/microsoft/applicationinsights/agent/bootstrap/BytecodeUtil.java index 7e079f2cbeb..016c5297b11 100644 --- a/agent/agent-bootstrap/src/main/java/com/microsoft/applicationinsights/agent/bootstrap/BytecodeUtil.java +++ b/agent/agent-bootstrap/src/main/java/com/microsoft/applicationinsights/agent/bootstrap/BytecodeUtil.java @@ -65,6 +65,7 @@ public void trackMetric( null, properties, Collections.emptyMap(), + null, null); } }); @@ -77,9 +78,11 @@ public static void trackEvent( Map properties, Map tags, Map metrics, + @Nullable String connectionString, @Nullable String instrumentationKey) { if (delegate != null) { - delegate.trackEvent(timestamp, name, properties, tags, metrics, instrumentationKey); + delegate.trackEvent( + timestamp, name, properties, tags, metrics, connectionString, instrumentationKey); } } @@ -94,6 +97,7 @@ public static void trackMetric( @Nullable Double stdDev, Map properties, Map tags, + @Nullable String connectionString, @Nullable String instrumentationKey) { if (delegate != null) { delegate.trackMetric( @@ -107,6 +111,7 @@ public static void trackMetric( stdDev, properties, tags, + connectionString, instrumentationKey); } } @@ -124,6 +129,7 @@ public static void trackDependency( Map properties, Map tags, Map metrics, + @Nullable String connectionString, @Nullable String instrumentationKey) { if (delegate != null) { delegate.trackDependency( @@ -139,6 +145,7 @@ public static void trackDependency( properties, tags, metrics, + connectionString, instrumentationKey); } } @@ -151,10 +158,19 @@ public static void trackPageView( Map properties, Map tags, Map metrics, + @Nullable String connectionString, @Nullable String instrumentationKey) { if (delegate != null) { delegate.trackPageView( - timestamp, name, uri, totalMillis, properties, tags, metrics, instrumentationKey); + timestamp, + name, + uri, + totalMillis, + properties, + tags, + metrics, + connectionString, + instrumentationKey); } } @@ -164,9 +180,17 @@ public static void trackTrace( int severityLevel, Map properties, Map tags, + @Nullable String connectionString, @Nullable String instrumentationKey) { if (delegate != null) { - delegate.trackTrace(timestamp, message, severityLevel, properties, tags, instrumentationKey); + delegate.trackTrace( + timestamp, + message, + severityLevel, + properties, + tags, + connectionString, + instrumentationKey); } } @@ -182,6 +206,7 @@ public static void trackRequest( Map properties, Map tags, Map metrics, + @Nullable String connectionString, @Nullable String instrumentationKey) { if (delegate != null) { delegate.trackRequest( @@ -196,6 +221,7 @@ public static void trackRequest( properties, tags, metrics, + connectionString, instrumentationKey); } } @@ -207,10 +233,18 @@ public static void trackException( Map properties, Map tags, Map metrics, + @Nullable String connectionString, @Nullable String instrumentationKey) { if (delegate != null) { delegate.trackException( - timestamp, throwable, severityLevel, properties, tags, metrics, instrumentationKey); + timestamp, + throwable, + severityLevel, + properties, + tags, + metrics, + connectionString, + instrumentationKey); } } @@ -225,6 +259,7 @@ public static void trackAvailability( Map properties, Map tags, Map metrics, + @Nullable String connectionString, @Nullable String instrumentationKey) { if (delegate != null) { delegate.trackAvailability( @@ -238,6 +273,7 @@ public static void trackAvailability( properties, tags, metrics, + connectionString, instrumentationKey); } } @@ -322,6 +358,7 @@ void trackEvent( Map properties, Map tags, Map metrics, + @Nullable String connectionString, @Nullable String instrumentationKey); void trackMetric( @@ -335,6 +372,7 @@ void trackMetric( @Nullable Double stdDev, Map properties, Map tags, + @Nullable String connectionString, @Nullable String instrumentationKey); void trackDependency( @@ -350,6 +388,7 @@ void trackDependency( Map properties, Map tags, Map metrics, + @Nullable String connectionString, @Nullable String instrumentationKey); void trackPageView( @@ -360,6 +399,7 @@ void trackPageView( Map properties, Map tags, Map metrics, + @Nullable String connectionString, @Nullable String instrumentationKey); void trackTrace( @@ -368,6 +408,7 @@ void trackTrace( int severityLevel, Map properties, Map tags, + @Nullable String connectionString, @Nullable String instrumentationKey); void trackRequest( @@ -382,6 +423,7 @@ void trackRequest( Map properties, Map tags, Map metrics, + @Nullable String connectionString, @Nullable String instrumentationKey); void trackException( @@ -391,6 +433,7 @@ void trackException( Map properties, Map tags, Map metrics, + @Nullable String connectionString, @Nullable String instrumentationKey); void trackAvailability( @@ -404,6 +447,7 @@ void trackAvailability( Map properties, Map tags, Map metrics, + @Nullable String connectionString, @Nullable String instrumentationKey); void flush(); diff --git a/agent/agent-bootstrap/src/test/java/com/microsoft/applicationinsights/agent/bootstrap/diagnostics/status/StatusFileTests.java b/agent/agent-bootstrap/src/test/java/com/microsoft/applicationinsights/agent/bootstrap/diagnostics/status/StatusFileTests.java index 8c99d61f4a9..6da9d08cbc3 100644 --- a/agent/agent-bootstrap/src/test/java/com/microsoft/applicationinsights/agent/bootstrap/diagnostics/status/StatusFileTests.java +++ b/agent/agent-bootstrap/src/test/java/com/microsoft/applicationinsights/agent/bootstrap/diagnostics/status/StatusFileTests.java @@ -47,8 +47,7 @@ import uk.org.webcompere.systemstubs.jupiter.SystemStub; import uk.org.webcompere.systemstubs.jupiter.SystemStubsExtension; -// FIXME (trask) failing in CI on deleting the the @TempDir -@Disabled +@Disabled("failing on CI when deleted the @TempDir") @ExtendWith(SystemStubsExtension.class) class StatusFileTests { diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/classicsdk/BytecodeUtilImpl.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/classicsdk/BytecodeUtilImpl.java index b72c4385a72..9625c96a439 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/classicsdk/BytecodeUtilImpl.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/classicsdk/BytecodeUtilImpl.java @@ -71,7 +71,6 @@ public class BytecodeUtilImpl implements BytecodeUtilDelegate { public static volatile FeatureStatsbeat featureStatsbeat; - // the key is just the instrumentation key, not the full connection string private static final Cache connectionStringCache = Cache.bounded(100); @Override @@ -81,6 +80,7 @@ public void trackEvent( Map properties, Map tags, Map measurements, + @Nullable String connectionString, @Nullable String instrumentationKey) { if (Strings.isNullOrEmpty(name)) { @@ -102,9 +102,7 @@ public void trackEvent( telemetryBuilder.setTime(FormattedTime.offSetDateTimeFromNow()); } selectivelySetTags(telemetryBuilder, tags); - if (instrumentationKey != null) { - setConnectionString(telemetryBuilder, instrumentationKey); - } + setConnectionString(telemetryBuilder, connectionString, instrumentationKey); track(telemetryBuilder, tags, true); } @@ -122,6 +120,7 @@ public void trackMetric( @Nullable Double stdDev, Map properties, Map tags, + @Nullable String connectionString, @Nullable String instrumentationKey) { if (Strings.isNullOrEmpty(name)) { @@ -150,9 +149,7 @@ public void trackMetric( telemetryBuilder.setTime(FormattedTime.offSetDateTimeFromNow()); } selectivelySetTags(telemetryBuilder, tags); - if (instrumentationKey != null) { - setConnectionString(telemetryBuilder, instrumentationKey); - } + setConnectionString(telemetryBuilder, connectionString, instrumentationKey); track(telemetryBuilder, tags, false); } @@ -171,6 +168,7 @@ public void trackDependency( Map properties, Map tags, Map measurements, + @Nullable String connectionString, @Nullable String instrumentationKey) { if (Strings.isNullOrEmpty(name)) { @@ -206,9 +204,7 @@ public void trackDependency( telemetryBuilder.setTime(FormattedTime.offSetDateTimeFromNow()); } selectivelySetTags(telemetryBuilder, tags); - if (instrumentationKey != null) { - setConnectionString(telemetryBuilder, instrumentationKey); - } + setConnectionString(telemetryBuilder, connectionString, instrumentationKey); track(telemetryBuilder, tags, true); } @@ -222,6 +218,7 @@ public void trackPageView( Map properties, Map tags, Map measurements, + @Nullable String connectionString, @Nullable String instrumentationKey) { if (Strings.isNullOrEmpty(name)) { @@ -248,9 +245,7 @@ public void trackPageView( telemetryBuilder.setTime(FormattedTime.offSetDateTimeFromNow()); } selectivelySetTags(telemetryBuilder, tags); - if (instrumentationKey != null) { - setConnectionString(telemetryBuilder, instrumentationKey); - } + setConnectionString(telemetryBuilder, connectionString, instrumentationKey); track(telemetryBuilder, tags, true); } @@ -262,6 +257,7 @@ public void trackTrace( int severityLevel, Map properties, Map tags, + @Nullable String connectionString, @Nullable String instrumentationKey) { if (message == null) { return; @@ -284,9 +280,7 @@ public void trackTrace( telemetryBuilder.setTime(FormattedTime.offSetDateTimeFromNow()); } selectivelySetTags(telemetryBuilder, tags); - if (instrumentationKey != null) { - setConnectionString(telemetryBuilder, instrumentationKey); - } + setConnectionString(telemetryBuilder, connectionString, instrumentationKey); track(telemetryBuilder, tags, true); } @@ -304,6 +298,7 @@ public void trackRequest( Map properties, Map tags, Map measurements, + @Nullable String connectionString, @Nullable String instrumentationKey) { if (Strings.isNullOrEmpty(name)) { return; @@ -339,9 +334,7 @@ public void trackRequest( telemetryBuilder.setTime(FormattedTime.offSetDateTimeFromNow()); } selectivelySetTags(telemetryBuilder, tags); - if (instrumentationKey != null) { - setConnectionString(telemetryBuilder, instrumentationKey); - } + setConnectionString(telemetryBuilder, connectionString, instrumentationKey); track(telemetryBuilder, tags, true); } @@ -354,6 +347,7 @@ public void trackException( Map properties, Map tags, Map measurements, + @Nullable String connectionString, @Nullable String instrumentationKey) { if (throwable == null) { return; @@ -380,9 +374,7 @@ public void trackException( telemetryBuilder.setTime(FormattedTime.offSetDateTimeFromNow()); } selectivelySetTags(telemetryBuilder, tags); - if (instrumentationKey != null) { - setConnectionString(telemetryBuilder, instrumentationKey); - } + setConnectionString(telemetryBuilder, connectionString, instrumentationKey); track(telemetryBuilder, tags, true); } @@ -399,6 +391,7 @@ public void trackAvailability( Map properties, Map tags, Map measurements, + @Nullable String connectionString, @Nullable String instrumentationKey) { if (Strings.isNullOrEmpty(name)) { @@ -432,9 +425,7 @@ public void trackAvailability( telemetryBuilder.setTime(FormattedTime.offSetDateTimeFromNow()); } selectivelySetTags(telemetryBuilder, tags); - if (instrumentationKey != null) { - setConnectionString(telemetryBuilder, instrumentationKey); - } + setConnectionString(telemetryBuilder, connectionString, instrumentationKey); track(telemetryBuilder, tags, false); } @@ -550,10 +541,16 @@ private static void setOperationTagsFromTheCurrentSpan( } private static void setConnectionString( - AbstractTelemetryBuilder telemetryBuilder, String instrumentationKey) { - telemetryBuilder.setConnectionString( - connectionStringCache.computeIfAbsent( - instrumentationKey, ikey -> ConnectionString.parse("InstrumentationKey=" + ikey))); + AbstractTelemetryBuilder telemetryBuilder, + @Nullable String connectionString, + @Nullable String instrumentationKey) { + if (connectionString == null && instrumentationKey != null) { + connectionString = "InstrumentationKey=" + instrumentationKey; + } + if (connectionString != null) { + telemetryBuilder.setConnectionString( + connectionStringCache.computeIfAbsent(connectionString, ConnectionString::parse)); + } } private static boolean sample(String operationId, double samplingPercentage) { diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/classicsdk/TelemetryClientClassFileTransformer.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/classicsdk/TelemetryClientClassFileTransformer.java index f0352299123..e60f7307253 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/classicsdk/TelemetryClientClassFileTransformer.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/classicsdk/TelemetryClientClassFileTransformer.java @@ -505,23 +505,38 @@ private void writeAgentTrackEventTelemetryMethod() { mv.visitMethodInsn( INVOKEVIRTUAL, unshadedPrefix + "/telemetry/TelemetryContext", - "getInstrumentationKey", + "getConnectionString", "()Ljava/lang/String;", false); + mv.visitVarInsn(ALOAD, 0); Label label7 = new Label(); mv.visitLabel(label7); + mv.visitMethodInsn( + INVOKEVIRTUAL, + unshadedPrefix + "/telemetry/EventTelemetry", + "getContext", + "()L" + unshadedPrefix + "/telemetry/TelemetryContext;", + false); + mv.visitMethodInsn( + INVOKEVIRTUAL, + unshadedPrefix + "/telemetry/TelemetryContext", + "getInstrumentationKey", + "()Ljava/lang/String;", + false); + Label label8 = new Label(); + mv.visitLabel(label8); mv.visitMethodInsn( INVOKESTATIC, BYTECODE_UTIL_INTERNAL_NAME, "trackEvent", - "(Ljava/util/Date;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/lang/String;)V", + "(Ljava/util/Date;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;)V", false); - Label label8 = new Label(); - mv.visitLabel(label8); - mv.visitInsn(RETURN); Label label9 = new Label(); mv.visitLabel(label9); - mv.visitMaxs(6, 1); + mv.visitInsn(RETURN); + Label label10 = new Label(); + mv.visitLabel(label10); + mv.visitMaxs(7, 1); mv.visitEnd(); } @@ -640,23 +655,38 @@ private void writeAgentTrackMetricTelemetryMethod() { mv.visitMethodInsn( INVOKEVIRTUAL, unshadedPrefix + "/telemetry/TelemetryContext", - "getInstrumentationKey", + "getConnectionString", "()Ljava/lang/String;", false); + mv.visitVarInsn(ALOAD, 0); Label label12 = new Label(); mv.visitLabel(label12); + mv.visitMethodInsn( + INVOKEVIRTUAL, + unshadedPrefix + "/telemetry/MetricTelemetry", + "getContext", + "()L" + unshadedPrefix + "/telemetry/TelemetryContext;", + false); + mv.visitMethodInsn( + INVOKEVIRTUAL, + unshadedPrefix + "/telemetry/TelemetryContext", + "getInstrumentationKey", + "()Ljava/lang/String;", + false); + Label label13 = new Label(); + mv.visitLabel(label13); mv.visitMethodInsn( INVOKESTATIC, BYTECODE_UTIL_INTERNAL_NAME, "trackMetric", - "(Ljava/util/Date;Ljava/lang/String;Ljava/lang/String;DLjava/lang/Integer;Ljava/lang/Double;Ljava/lang/Double;Ljava/lang/Double;Ljava/util/Map;Ljava/util/Map;Ljava/lang/String;)V", + "(Ljava/util/Date;Ljava/lang/String;Ljava/lang/String;DLjava/lang/Integer;Ljava/lang/Double;Ljava/lang/Double;Ljava/lang/Double;Ljava/util/Map;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;)V", false); - Label label13 = new Label(); - mv.visitLabel(label13); - mv.visitInsn(RETURN); Label label14 = new Label(); mv.visitLabel(label14); - mv.visitMaxs(12, 1); + mv.visitInsn(RETURN); + Label label15 = new Label(); + mv.visitLabel(label15); + mv.visitMaxs(13, 1); mv.visitEnd(); } @@ -803,23 +833,38 @@ private void writeAgentTrackRemoteDependencyTelemetryMethod() { mv.visitMethodInsn( INVOKEVIRTUAL, unshadedPrefix + "/telemetry/TelemetryContext", - "getInstrumentationKey", + "getConnectionString", "()Ljava/lang/String;", false); + mv.visitVarInsn(ALOAD, 0); Label label14 = new Label(); mv.visitLabel(label14); + mv.visitMethodInsn( + INVOKEVIRTUAL, + unshadedPrefix + "/telemetry/RemoteDependencyTelemetry", + "getContext", + "()L" + unshadedPrefix + "/telemetry/TelemetryContext;", + false); + mv.visitMethodInsn( + INVOKEVIRTUAL, + unshadedPrefix + "/telemetry/TelemetryContext", + "getInstrumentationKey", + "()Ljava/lang/String;", + false); + Label label15 = new Label(); + mv.visitLabel(label15); mv.visitMethodInsn( INVOKESTATIC, BYTECODE_UTIL_INTERNAL_NAME, "trackDependency", - "(Ljava/util/Date;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/lang/String;)V", + "(Ljava/util/Date;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;)V", false); - Label label15 = new Label(); - mv.visitLabel(label15); - mv.visitInsn(RETURN); Label label16 = new Label(); mv.visitLabel(label16); - mv.visitMaxs(13, 1); + mv.visitInsn(RETURN); + Label label17 = new Label(); + mv.visitLabel(label17); + mv.visitMaxs(14, 1); mv.visitEnd(); } @@ -915,23 +960,38 @@ private void writeAgentTrackPageViewTelemetryMethod() { mv.visitMethodInsn( INVOKEVIRTUAL, unshadedPrefix + "/telemetry/TelemetryContext", - "getInstrumentationKey", + "getConnectionString", "()Ljava/lang/String;", false); + mv.visitVarInsn(ALOAD, 0); Label label9 = new Label(); mv.visitLabel(label9); + mv.visitMethodInsn( + INVOKEVIRTUAL, + unshadedPrefix + "/telemetry/PageViewTelemetry", + "getContext", + "()L" + unshadedPrefix + "/telemetry/TelemetryContext;", + false); + mv.visitMethodInsn( + INVOKEVIRTUAL, + unshadedPrefix + "/telemetry/TelemetryContext", + "getInstrumentationKey", + "()Ljava/lang/String;", + false); + Label label10 = new Label(); + mv.visitLabel(label10); mv.visitMethodInsn( INVOKESTATIC, BYTECODE_UTIL_INTERNAL_NAME, "trackPageView", - "(Ljava/util/Date;Ljava/lang/String;Ljava/net/URI;JLjava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/lang/String;)V", + "(Ljava/util/Date;Ljava/lang/String;Ljava/net/URI;JLjava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;)V", false); - Label label10 = new Label(); - mv.visitLabel(label10); - mv.visitInsn(RETURN); Label label11 = new Label(); mv.visitLabel(label11); - mv.visitMaxs(9, 1); + mv.visitInsn(RETURN); + Label label12 = new Label(); + mv.visitLabel(label12); + mv.visitMaxs(10, 1); mv.visitEnd(); } @@ -1028,23 +1088,38 @@ private void writeAgentTrackTraceTelemetryMethod() { mv.visitMethodInsn( INVOKEVIRTUAL, unshadedPrefix + "/telemetry/TelemetryContext", - "getInstrumentationKey", + "getConnectionString", "()Ljava/lang/String;", false); + mv.visitVarInsn(ALOAD, 0); Label label10 = new Label(); mv.visitLabel(label10); + mv.visitMethodInsn( + INVOKEVIRTUAL, + unshadedPrefix + "/telemetry/TraceTelemetry", + "getContext", + "()L" + unshadedPrefix + "/telemetry/TelemetryContext;", + false); + mv.visitMethodInsn( + INVOKEVIRTUAL, + unshadedPrefix + "/telemetry/TelemetryContext", + "getInstrumentationKey", + "()Ljava/lang/String;", + false); + Label label11 = new Label(); + mv.visitLabel(label11); mv.visitMethodInsn( INVOKESTATIC, BYTECODE_UTIL_INTERNAL_NAME, "trackTrace", - "(Ljava/util/Date;Ljava/lang/String;ILjava/util/Map;Ljava/util/Map;Ljava/lang/String;)V", + "(Ljava/util/Date;Ljava/lang/String;ILjava/util/Map;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;)V", false); - Label label11 = new Label(); - mv.visitLabel(label11); - mv.visitInsn(RETURN); Label label12 = new Label(); mv.visitLabel(label12); - mv.visitMaxs(6, 3); + mv.visitInsn(RETURN); + Label label13 = new Label(); + mv.visitLabel(label13); + mv.visitMaxs(7, 3); mv.visitEnd(); } @@ -1181,25 +1256,40 @@ private void writeAgentTrackRequestTelemetryMethod() { mv.visitMethodInsn( INVOKEVIRTUAL, unshadedPrefix + "/telemetry/TelemetryContext", - "getInstrumentationKey", + "getConnectionString", "()Ljava/lang/String;", false); + mv.visitVarInsn(ALOAD, 0); Label label15 = new Label(); mv.visitLabel(label15); + mv.visitMethodInsn( + INVOKEVIRTUAL, + unshadedPrefix + "/telemetry/RequestTelemetry", + "getContext", + "()L" + unshadedPrefix + "/telemetry/TelemetryContext;", + false); + mv.visitMethodInsn( + INVOKEVIRTUAL, + unshadedPrefix + "/telemetry/TelemetryContext", + "getInstrumentationKey", + "()Ljava/lang/String;", + false); + Label label16 = new Label(); + mv.visitLabel(label16); mv.visitMethodInsn( INVOKESTATIC, BYTECODE_UTIL_INTERNAL_NAME, "trackRequest", - "(Ljava/lang/String;Ljava/lang/String;Ljava/net/URL;Ljava/util/Date;Ljava/lang/Long;Ljava/lang/String;ZLjava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/lang/String;)V", + "(Ljava/lang/String;Ljava/lang/String;Ljava/net/URL;Ljava/util/Date;Ljava/lang/Long;Ljava/lang/String;ZLjava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;)V", false); mv.visitLabel(label1); - Label label16 = new Label(); - mv.visitJumpInsn(GOTO, label16); + Label label17 = new Label(); + mv.visitJumpInsn(GOTO, label17); mv.visitLabel(label2); mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/net/MalformedURLException"}); mv.visitVarInsn(ASTORE, 1); - Label label17 = new Label(); - mv.visitLabel(label17); + Label label18 = new Label(); + mv.visitLabel(label18); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn( INVOKESTATIC, @@ -1207,12 +1297,12 @@ private void writeAgentTrackRequestTelemetryMethod() { "logErrorOnce", "(Ljava/lang/Throwable;)V", false); - mv.visitLabel(label16); + mv.visitLabel(label17); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); mv.visitInsn(RETURN); - Label label18 = new Label(); - mv.visitLabel(label18); - mv.visitMaxs(12, 2); + Label label19 = new Label(); + mv.visitLabel(label19); + mv.visitMaxs(13, 2); mv.visitEnd(); } @@ -1318,23 +1408,38 @@ private void writeAgentTrackExceptionTelemetryMethod() { mv.visitMethodInsn( INVOKEVIRTUAL, unshadedPrefix + "/telemetry/TelemetryContext", - "getInstrumentationKey", + "getConnectionString", "()Ljava/lang/String;", false); + mv.visitVarInsn(ALOAD, 0); Label label11 = new Label(); mv.visitLabel(label11); + mv.visitMethodInsn( + INVOKEVIRTUAL, + unshadedPrefix + "/telemetry/ExceptionTelemetry", + "getContext", + "()L" + unshadedPrefix + "/telemetry/TelemetryContext;", + false); + mv.visitMethodInsn( + INVOKEVIRTUAL, + unshadedPrefix + "/telemetry/TelemetryContext", + "getInstrumentationKey", + "()Ljava/lang/String;", + false); + Label label12 = new Label(); + mv.visitLabel(label12); mv.visitMethodInsn( INVOKESTATIC, BYTECODE_UTIL_INTERNAL_NAME, "trackException", - "(Ljava/util/Date;Ljava/lang/Throwable;ILjava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/lang/String;)V", + "(Ljava/util/Date;Ljava/lang/Throwable;ILjava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;)V", false); - Label label12 = new Label(); - mv.visitLabel(label12); - mv.visitInsn(RETURN); Label label13 = new Label(); mv.visitLabel(label13); - mv.visitMaxs(7, 3); + mv.visitInsn(RETURN); + Label label14 = new Label(); + mv.visitLabel(label14); + mv.visitMaxs(8, 3); mv.visitEnd(); } @@ -1456,23 +1561,38 @@ private void overwriteTrackAvailabilityMethod(MethodVisitor mv) { mv.visitMethodInsn( INVOKEVIRTUAL, unshadedPrefix + "/telemetry/TelemetryContext", - "getInstrumentationKey", + "getConnectionString", "()Ljava/lang/String;", false); + mv.visitVarInsn(ALOAD, 1); Label label12 = new Label(); mv.visitLabel(label12); + mv.visitMethodInsn( + INVOKEVIRTUAL, + unshadedPrefix + "/telemetry/AvailabilityTelemetry", + "getContext", + "()L" + unshadedPrefix + "/telemetry/TelemetryContext;", + false); + mv.visitMethodInsn( + INVOKEVIRTUAL, + unshadedPrefix + "/telemetry/TelemetryContext", + "getInstrumentationKey", + "()Ljava/lang/String;", + false); + Label label13 = new Label(); + mv.visitLabel(label13); mv.visitMethodInsn( INVOKESTATIC, BYTECODE_UTIL_INTERNAL_NAME, "trackAvailability", - "(Ljava/util/Date;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;ZLjava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/lang/String;)V", + "(Ljava/util/Date;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;ZLjava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;)V", false); - Label label13 = new Label(); - mv.visitLabel(label13); - mv.visitInsn(RETURN); Label label14 = new Label(); mv.visitLabel(label14); - mv.visitMaxs(11, 2); + mv.visitInsn(RETURN); + Label label15 = new Label(); + mv.visitLabel(label15); + mv.visitMaxs(12, 2); mv.visitEnd(); } @@ -1611,6 +1731,7 @@ public void trackAvailability( t.getProperties(), t.getContext().getTags(), t.getMetrics(), + t.getContext().getConnectionString(), t.getContext().getInstrumentationKey()); } @@ -1678,6 +1799,7 @@ public void track(com.microsoft.applicationinsights.telemetry.Telemetry telemetr t.getProperties(), t.getContext().getTags(), t.getMetrics(), + t.getContext().getConnectionString(), t.getContext().getInstrumentationKey()); } @@ -1694,6 +1816,7 @@ public void track(com.microsoft.applicationinsights.telemetry.Telemetry telemetr t.getStandardDeviation(), t.getProperties(), t.getContext().getTags(), + t.getContext().getConnectionString(), t.getContext().getInstrumentationKey()); } @@ -1712,6 +1835,7 @@ public void track(com.microsoft.applicationinsights.telemetry.Telemetry telemetr t.getProperties(), t.getContext().getTags(), t.getMetrics(), + t.getContext().getConnectionString(), t.getContext().getInstrumentationKey()); } @@ -1725,6 +1849,7 @@ public void track(com.microsoft.applicationinsights.telemetry.Telemetry telemetr t.getProperties(), t.getContext().getTags(), t.getMetrics(), + t.getContext().getConnectionString(), t.getContext().getInstrumentationKey()); } @@ -1738,6 +1863,7 @@ public void track(com.microsoft.applicationinsights.telemetry.Telemetry telemetr severityLevel, t.getProperties(), t.getContext().getTags(), + t.getContext().getConnectionString(), t.getContext().getInstrumentationKey()); } @@ -1756,6 +1882,7 @@ public void track(com.microsoft.applicationinsights.telemetry.Telemetry telemetr t.getProperties(), t.getContext().getTags(), t.getMetrics(), + t.getContext().getConnectionString(), t.getContext().getInstrumentationKey()); } catch (java.net.MalformedURLException e) { com.microsoft.applicationinsights.agent.bootstrap.BytecodeUtil.logErrorOnce(e); @@ -1773,6 +1900,7 @@ public void track(com.microsoft.applicationinsights.telemetry.Telemetry telemetr t.getProperties(), t.getContext().getTags(), t.getMetrics(), + t.getContext().getConnectionString(), t.getContext().getInstrumentationKey()); } diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/classicsdk/TelemetryContextClassFileTransformer.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/classicsdk/TelemetryContextClassFileTransformer.java new file mode 100644 index 00000000000..0c7fa15c859 --- /dev/null +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/classicsdk/TelemetryContextClassFileTransformer.java @@ -0,0 +1,114 @@ +/* + * ApplicationInsights-Java + * Copyright (c) Microsoft Corporation + * All rights reserved. + * + * MIT License + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the ""Software""), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package com.microsoft.applicationinsights.agent.internal.classicsdk; + +import static org.objectweb.asm.Opcodes.ACC_PUBLIC; +import static org.objectweb.asm.Opcodes.ACONST_NULL; +import static org.objectweb.asm.Opcodes.ARETURN; +import static org.objectweb.asm.Opcodes.ASM9; + +import java.lang.instrument.ClassFileTransformer; +import java.security.ProtectionDomain; +import javax.annotation.Nullable; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +// this is used to supplement old versions of TelemetryContext with getters from the latest +// version of TelemetryContext +public class TelemetryContextClassFileTransformer implements ClassFileTransformer { + + private static final Logger logger = + LoggerFactory.getLogger(TelemetryContextClassFileTransformer.class); + + private final String unshadedClassName = + UnshadedSdkPackageName.get() + "/telemetry/TelemetryContext"; + + @Override + @Nullable + public byte[] transform( + @Nullable ClassLoader loader, + @Nullable String className, + @Nullable Class classBeingRedefined, + @Nullable ProtectionDomain protectionDomain, + byte[] classfileBuffer) { + + if (!unshadedClassName.equals(className)) { + return null; + } + try { + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); + TelemetryContextClassVisitor cv = new TelemetryContextClassVisitor(cw); + ClassReader cr = new ClassReader(classfileBuffer); + cr.accept(cv, 0); + return cw.toByteArray(); + } catch (Throwable t) { + logger.error(t.getMessage(), t); + return null; + } + } + + private static class TelemetryContextClassVisitor extends ClassVisitor { + + private final ClassWriter cw; + + private boolean foundGetConnectionStringMethod; + + private TelemetryContextClassVisitor(ClassWriter cw) { + super(ASM9, cw); + this.cw = cw; + } + + @Override + public MethodVisitor visitMethod( + int access, + String name, + String descriptor, + @Nullable String signature, + @Nullable String[] exceptions) { + if (name.equals("getConnectionString") && descriptor.equals("()Ljava/lang/String;")) { + foundGetConnectionStringMethod = true; + } + return super.visitMethod(access, name, descriptor, signature, exceptions); + } + + @Override + public void visitEnd() { + if (!foundGetConnectionStringMethod) { + writeGetConnectionStringMethod(); + } + } + + private void writeGetConnectionStringMethod() { + MethodVisitor mv = + cw.visitMethod(ACC_PUBLIC, "getConnectionString", "()Ljava/lang/String;", null, null); + mv.visitCode(); + mv.visitInsn(ACONST_NULL); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + } +} diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/AppIdSupplier.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/AppIdSupplier.java index 1c881712e99..16cd693efb3 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/AppIdSupplier.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/AppIdSupplier.java @@ -106,7 +106,7 @@ public void updateAppId() { // visible for testing static URL getAppIdUrl(ConnectionString connectionString) throws MalformedURLException { return new URL( - connectionString.getIngestionEndpoint(), + new URL(connectionString.getIngestionEndpoint()), "api/profiles/" + connectionString.getInstrumentationKey() + "/appId"); } diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/LegacyInstrumentation.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/LegacyInstrumentation.java index 16f4b689c8d..f8ae576de8e 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/LegacyInstrumentation.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/LegacyInstrumentation.java @@ -33,6 +33,7 @@ import com.microsoft.applicationinsights.agent.internal.classicsdk.RequestNameHandlerClassFileTransformer; import com.microsoft.applicationinsights.agent.internal.classicsdk.RequestTelemetryClassFileTransformer; import com.microsoft.applicationinsights.agent.internal.classicsdk.TelemetryClientClassFileTransformer; +import com.microsoft.applicationinsights.agent.internal.classicsdk.TelemetryContextClassFileTransformer; import com.microsoft.applicationinsights.agent.internal.classicsdk.WebRequestTrackingFilterClassFileTransformer; import io.opentelemetry.javaagent.bootstrap.InstrumentationHolder; import java.lang.instrument.Instrumentation; @@ -48,6 +49,7 @@ static void registerTransformers() { instrumentation.addTransformer(new RequestTelemetryClassFileTransformer()); instrumentation.addTransformer(new ExceptionTelemetryClassFileTransformer()); instrumentation.addTransformer(new MetricTelemetryClassFileTransformer()); + instrumentation.addTransformer(new TelemetryContextClassFileTransformer()); instrumentation.addTransformer(new PerformanceCounterModuleClassFileTransformer()); instrumentation.addTransformer(new QuickPulseClassFileTransformer()); instrumentation.addTransformer(new HeartBeatModuleClassFileTransformer()); diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/AbstractTelemetryBuilder.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/AbstractTelemetryBuilder.java index 44d965a3220..bcec2fdb26b 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/AbstractTelemetryBuilder.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/AbstractTelemetryBuilder.java @@ -66,13 +66,11 @@ public void setSampleRate(float sampleRate) { } public void setConnectionString(ConnectionString connectionString) { - telemetryItem.setInstrumentationKey(connectionString.getInstrumentationKey()); - telemetryItem.setIngestionEndpoint(connectionString.getIngestionEndpoint()); + telemetryItem.setConnectionString(connectionString); } public void setConnectionString(StatsbeatConnectionString connectionString) { - telemetryItem.setInstrumentationKey(connectionString.getInstrumentationKey()); - telemetryItem.setIngestionEndpoint(connectionString.getEndpoint()); + telemetryItem.setConnectionString(connectionString); } public void addTag(String key, String value) { diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/ConnectionString.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/ConnectionString.java index db940232298..1b1fbb1b53f 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/ConnectionString.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/ConnectionString.java @@ -26,14 +26,14 @@ public final class ConnectionString { private final String instrumentationKey; - private final URL ingestionEndpoint; + private final String ingestionEndpoint; private final URL liveEndpoint; private final URL profilerEndpoint; ConnectionString( String instrumentationKey, URL ingestionEndpoint, URL liveEndpoint, URL profilerEndpoint) { this.instrumentationKey = instrumentationKey; - this.ingestionEndpoint = ingestionEndpoint; + this.ingestionEndpoint = ingestionEndpoint.toExternalForm(); this.liveEndpoint = liveEndpoint; this.profilerEndpoint = profilerEndpoint; } @@ -46,7 +46,7 @@ public String getInstrumentationKey() { return instrumentationKey; } - public URL getIngestionEndpoint() { + public String getIngestionEndpoint() { return ingestionEndpoint; } diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/DefaultEndpoints.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/DefaultEndpoints.java index 6f248e565c8..7920410dda9 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/DefaultEndpoints.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/DefaultEndpoints.java @@ -23,8 +23,15 @@ class DefaultEndpoints { - static final String INGESTION_ENDPOINT = "https://dc.services.visualstudio.com/"; + static final String INGESTION_ENDPOINT = + System.getProperty( + // this property is needed for testing 2.x SDK which only sets instrumentationKey (without + // endpoint) and also needed for testing the (deprecated) instrumentationKeyOverrides + "applicationinsights.testing.global-ingestion-endpoint", + "https://dc.services.visualstudio.com/"); + static final String LIVE_ENDPOINT = "https://rt.services.visualstudio.com/"; + static final String PROFILER_ENDPOINT = "https://agent.azureserviceprofiler.net/"; private DefaultEndpoints() {} diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/StatsbeatConnectionString.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/StatsbeatConnectionString.java index 9d6e9877627..223e1eba4ba 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/StatsbeatConnectionString.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/StatsbeatConnectionString.java @@ -58,13 +58,13 @@ public final class StatsbeatConnectionString { EU_REGION_GEO_SET.add("switzerlandwest"); } - private final URL endpoint; + private final String ingestionEndpoint; private final String instrumentationKey; public static StatsbeatConnectionString create( ConnectionString connectionString, @Nullable String instrumentationKey, - @Nullable String endpoint) { + @Nullable String ingestionEndpoint) { // if customer is in EU region and their statsbeat config is not in EU region, customer is // responsible for breaking the EU data boundary violation. @@ -74,15 +74,15 @@ public static StatsbeatConnectionString create( StatsbeatConnectionString.getInstrumentationKeyAndEndpointPair( connectionString.getIngestionEndpoint().toString()); instrumentationKey = pair.instrumentationKey; - endpoint = pair.endpoint; + ingestionEndpoint = pair.endpoint; } URL endpointUrl; - if (!endpoint.endsWith("/")) { - endpoint += "/"; + if (!ingestionEndpoint.endsWith("/")) { + ingestionEndpoint += "/"; } try { - endpointUrl = new URL(endpoint); + endpointUrl = new URL(ingestionEndpoint); } catch (MalformedURLException e) { throw new IllegalArgumentException("could not construct statsbeat endpoint uri", e); } @@ -90,13 +90,13 @@ public static StatsbeatConnectionString create( return new StatsbeatConnectionString(endpointUrl, instrumentationKey); } - private StatsbeatConnectionString(URL endpoint, String instrumentationKey) { - this.endpoint = endpoint; + private StatsbeatConnectionString(URL ingestionEndpoint, String instrumentationKey) { + this.ingestionEndpoint = ingestionEndpoint.toExternalForm(); this.instrumentationKey = instrumentationKey; } - public URL getEndpoint() { - return endpoint; + public String getIngestionEndpoint() { + return ingestionEndpoint; } public String getInstrumentationKey() { diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoader.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoader.java index c712fc68e9c..557c45ffbaa 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoader.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoader.java @@ -22,16 +22,14 @@ package com.azure.monitor.opentelemetry.exporter.implementation.localstorage; import static com.azure.monitor.opentelemetry.exporter.implementation.utils.AzureMonitorMsgId.DISK_PERSISTENCE_LOADER_ERROR; -import static java.nio.charset.StandardCharsets.UTF_8; import com.azure.monitor.opentelemetry.exporter.implementation.logging.OperationLogger; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import java.io.EOFException; +import java.io.DataInputStream; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; -import java.net.URL; import java.nio.ByteBuffer; +import java.nio.file.Files; import java.util.regex.Pattern; import javax.annotation.Nullable; @@ -108,38 +106,44 @@ PersistedFile loadTelemetriesFromDisk() { } if (tempFile.length() <= 36) { - if (!FileUtil.deleteFileWithRetries(tempFile)) { - operationLogger.recordFailure( - "Unable to delete file: " + tempFile.getAbsolutePath(), DISK_PERSISTENCE_LOADER_ERROR); - } + deleteFile(tempFile); return null; } - byte[] ikeyBytes = new byte[36]; - int rawByteLength = (int) tempFile.length() - 36; - byte[] telemetryBytes = new byte[rawByteLength]; String instrumentationKey; - URL ingestionEndpoint; - try (FileInputStream fileInputStream = new FileInputStream(tempFile)) { - int version = fileInputStream.read(); - if (version == 1) { - // FIXME INGESTION ENDPOINT + String ingestionEndpoint; + byte[] telemetryBytes; + + try (DataInputStream dataInputStream = + new DataInputStream(Files.newInputStream(tempFile.toPath()))) { + + int version = dataInputStream.readInt(); + if (version != 1) { + // probably old format where ikey chars were written first + // note: ikey character int values would be minimum 48 (ascii value for '0') + + // need to close FileInputStream before delete + dataInputStream.close(); + deleteFile(tempFile); + return null; } - readFully(fileInputStream, ikeyBytes, 36); - instrumentationKey = new String(ikeyBytes, UTF_8); + + instrumentationKey = dataInputStream.readUTF(); if (!isInstrumentationKeyValid(instrumentationKey)) { - fileInputStream.close(); // need to close FileInputStream before delete - if (!FileUtil.deleteFileWithRetries(tempFile)) { - operationLogger.recordFailure( - "Unable to delete file: " + tempFile.getAbsolutePath(), - DISK_PERSISTENCE_LOADER_ERROR); - } + // probably really old format where content was written directly with no ikey + + // need to close FileInputStream before delete + dataInputStream.close(); + deleteFile(tempFile); return null; } - // FIXME INGESTION ENDPOINT - ingestionEndpoint = null; - readFully(fileInputStream, telemetryBytes, rawByteLength); + ingestionEndpoint = dataInputStream.readUTF(); + + int numBytes = dataInputStream.readInt(); + telemetryBytes = new byte[numBytes]; + dataInputStream.readFully(telemetryBytes); + } catch (IOException e) { operationLogger.recordFailure( "Error reading file: " + tempFile.getAbsolutePath(), e, DISK_PERSISTENCE_LOADER_ERROR); @@ -152,26 +156,15 @@ PersistedFile loadTelemetriesFromDisk() { tempFile, instrumentationKey, ingestionEndpoint, ByteBuffer.wrap(telemetryBytes)); } - static boolean isInstrumentationKeyValid(String instrumentationKey) { - return Pattern.matches(INSTRUMENTATION_KEY_REGEX, instrumentationKey.toLowerCase()); - } - - // reads bytes from a FileInputStream and allocates those into the buffer array byteArray. - private static void readFully(FileInputStream fileInputStream, byte[] byteArray, int length) - throws IOException { - if (length < 0) { - throw new IndexOutOfBoundsException(); + private void deleteFile(File tempFile) { + if (!FileUtil.deleteFileWithRetries(tempFile)) { + operationLogger.recordFailure( + "Unable to delete file: " + tempFile.getAbsolutePath(), DISK_PERSISTENCE_LOADER_ERROR); } + } - int totalRead = 0; - while (totalRead < length) { - int numRead = fileInputStream.read(byteArray, totalRead, length - totalRead); - if (numRead < 0) { - throw new EOFException(); - } - - totalRead += numRead; - } + static boolean isInstrumentationKeyValid(String instrumentationKey) { + return Pattern.matches(INSTRUMENTATION_KEY_REGEX, instrumentationKey.toLowerCase()); } // either delete it permanently on success or add it back to cache to be processed again later on @@ -215,11 +208,11 @@ void updateProcessedFileStatus(boolean successOrNonRetryableError, File file) { static class PersistedFile { final File file; final String instrumentationKey; - final URL ingestionEndpoint; + final String ingestionEndpoint; final ByteBuffer rawBytes; PersistedFile( - File file, String instrumentationKey, URL ingestionEndpoint, ByteBuffer byteBuffer) { + File file, String instrumentationKey, String ingestionEndpoint, ByteBuffer byteBuffer) { if (instrumentationKey == null) { throw new IllegalArgumentException("instrumentation key can not be null."); } diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileWriter.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileWriter.java index bda14149f56..67616a89c57 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileWriter.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileWriter.java @@ -22,10 +22,10 @@ package com.azure.monitor.opentelemetry.exporter.implementation.localstorage; import static com.azure.monitor.opentelemetry.exporter.implementation.utils.AzureMonitorMsgId.DISK_PERSISTENCE_WRITER_ERROR; -import static java.nio.charset.StandardCharsets.UTF_8; import com.azure.monitor.opentelemetry.exporter.implementation.logging.OperationLogger; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -68,7 +68,7 @@ final class LocalFileWriter { value = "SECPTI", // Potential Path Traversal justification = "The constructed file path cannot be controlled by an end user of the instrumented application") - void writeToDisk(String instrumentationKey, List buffers) { + void writeToDisk(String instrumentationKey, String ingestionEndpoint, List buffers) { long size = getTotalSizeOfPersistedFiles(telemetryFolder); if (size >= diskPersistenceMaxSizeBytes) { operationLogger.recordFailure( @@ -93,7 +93,7 @@ void writeToDisk(String instrumentationKey, List buffers) { } try { - write(tempFile, buffers, instrumentationKey); + write(tempFile, instrumentationKey, ingestionEndpoint, buffers); } catch (IOException e) { operationLogger.recordFailure( "Error writing file: " + tempFile.getAbsolutePath(), e, DISK_PERSISTENCE_WRITER_ERROR); @@ -118,12 +118,22 @@ void writeToDisk(String instrumentationKey, List buffers) { operationLogger.recordSuccess(); } - private static void write(File file, List buffers, String instrumentationKey) + private static void write( + File file, String instrumentationKey, String ingestionEndpoint, List buffers) throws IOException { - try (FileChannel channel = new FileOutputStream(file).getChannel()) { - channel.write(ByteBuffer.wrap(instrumentationKey.getBytes(UTF_8))); + + try (FileOutputStream fileOut = new FileOutputStream(file); + DataOutputStream dataOut = new DataOutputStream(fileOut)) { + dataOut.writeInt(1); // version + dataOut.writeUTF(instrumentationKey); + dataOut.writeUTF(ingestionEndpoint); + + int numBytes = buffers.stream().mapToInt(ByteBuffer::remaining).sum(); + dataOut.writeInt(numBytes); + + FileChannel fileChannel = fileOut.getChannel(); for (ByteBuffer byteBuffer : buffers) { - channel.write(byteBuffer); + fileChannel.write(byteBuffer); } } } diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalStorageTelemetryPipelineListener.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalStorageTelemetryPipelineListener.java index f04140c419e..fdaf2239bea 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalStorageTelemetryPipelineListener.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalStorageTelemetryPipelineListener.java @@ -63,14 +63,16 @@ public LocalStorageTelemetryPipelineListener( @Override public void onResponse(TelemetryPipelineRequest request, TelemetryPipelineResponse response) { if (StatusCode.isRetryable(response.getStatusCode())) { - localFileWriter.writeToDisk(request.getInstrumentationKey(), request.getTelemetry()); + localFileWriter.writeToDisk( + request.getInstrumentationKey(), request.getIngestionEndpoint(), request.getTelemetry()); } } @Override public void onException( TelemetryPipelineRequest request, String errorMessage, Throwable throwable) { - localFileWriter.writeToDisk(request.getInstrumentationKey(), request.getTelemetry()); + localFileWriter.writeToDisk( + request.getInstrumentationKey(), request.getIngestionEndpoint(), request.getTelemetry()); } @Override diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java index 119308fb784..9f794b41893 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java @@ -22,9 +22,10 @@ package com.azure.monitor.opentelemetry.exporter.implementation.models; import com.azure.core.annotation.Fluent; +import com.azure.monitor.opentelemetry.exporter.implementation.configuration.ConnectionString; +import com.azure.monitor.opentelemetry.exporter.implementation.configuration.StatsbeatConnectionString; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; -import java.net.URL; import java.time.OffsetDateTime; import java.util.Map; @@ -78,7 +79,7 @@ public final class TelemetryItem { @JsonProperty(value = "iKey") private String instrumentationKey; - @JsonIgnore private URL ingestionEndpoint; + @JsonIgnore private String ingestionEndpoint; /* * Key/value collection of context properties. See ContextTagKeys for @@ -219,24 +220,23 @@ public String getInstrumentationKey() { return this.instrumentationKey; } - /** - * Set the instrumentationKey property: The instrumentation key of the Application Insights - * resource. - * - * @param instrumentationKey the instrumentationKey value to set. - * @return the TelemetryItem object itself. - */ - public TelemetryItem setInstrumentationKey(String instrumentationKey) { - this.instrumentationKey = instrumentationKey; - return this; + @JsonIgnore + public String getIngestionEndpoint() { + return ingestionEndpoint; } - public URL getIngestionEndpoint() { - return ingestionEndpoint; + @JsonIgnore + public TelemetryItem setConnectionString(ConnectionString connectionString) { + instrumentationKey = connectionString.getInstrumentationKey(); + ingestionEndpoint = connectionString.getIngestionEndpoint(); + return this; } - public void setIngestionEndpoint(URL ingestionEndpoint) { - this.ingestionEndpoint = ingestionEndpoint; + @JsonIgnore + public TelemetryItem setConnectionString(StatsbeatConnectionString connectionString) { + instrumentationKey = connectionString.getInstrumentationKey(); + ingestionEndpoint = connectionString.getIngestionEndpoint(); + return this; } /** diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporter.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporter.java index 72f21db1f5f..32da04e2163 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporter.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporter.java @@ -33,7 +33,6 @@ import io.opentelemetry.sdk.common.CompletableResultCode; import java.io.IOException; import java.io.StringWriter; -import java.net.URL; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; @@ -91,19 +90,24 @@ public TelemetryItemExporter( } public CompletableResultCode send(List telemetryItems) { - Map> instrumentationKeyMap = new HashMap<>(); + // second level (ingestion endpoint) is just to protect against scenario where some telemetry + // is stamped with same ikey but bad ingestion endpoint, so only the bad telemetry will fail + Map>> groupings = new HashMap<>(); for (TelemetryItem telemetryItem : telemetryItems) { - String instrumentationKey = telemetryItem.getInstrumentationKey(); - instrumentationKeyMap - .computeIfAbsent(instrumentationKey, k -> new ArrayList<>()) + groupings + .computeIfAbsent(telemetryItem.getInstrumentationKey(), k -> new HashMap<>()) + .computeIfAbsent(telemetryItem.getIngestionEndpoint(), k -> new ArrayList<>()) .add(telemetryItem); } List resultCodeList = new ArrayList<>(); - for (Map.Entry> entry : instrumentationKeyMap.entrySet()) { - resultCodeList.add( - internalSendByInstrumentationKey( - // FIXME INGESTION ENDPOINT - entry.getValue(), entry.getKey(), telemetryItems.get(0).getIngestionEndpoint())); + for (Map.Entry>> outerEntry : groupings.entrySet()) { + for (Map.Entry> innerEntry : outerEntry.getValue().entrySet()) { + String instrumentationKey = outerEntry.getKey(); + String ingestionEndpoint = innerEntry.getKey(); + resultCodeList.add( + internalSendByInstrumentationKey( + innerEntry.getValue(), instrumentationKey, ingestionEndpoint)); + } } return maybeAddToActiveExportResults(resultCodeList); } @@ -137,7 +141,7 @@ public CompletableResultCode shutdown() { } CompletableResultCode internalSendByInstrumentationKey( - List telemetryItems, String instrumentationKey, URL ingestionEndpoint) { + List telemetryItems, String instrumentationKey, String ingestionEndpoint) { List byteBuffers; try { byteBuffers = encode(telemetryItems); diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryPipeline.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryPipeline.java index f8e08721e2e..40496798871 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryPipeline.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryPipeline.java @@ -61,14 +61,14 @@ public TelemetryPipeline(HttpPipeline pipeline) { public CompletableResultCode send( List telemetry, String instrumentationKey, - URL ingestionEndpoint, + String ingestionEndpoint, TelemetryPipelineListener listener) { URL url = redirectCache.computeIfAbsent( instrumentationKey, ikey -> getFullIngestionUrl(ingestionEndpoint)); TelemetryPipelineRequest request = - new TelemetryPipelineRequest(url, instrumentationKey, telemetry); + new TelemetryPipelineRequest(url, instrumentationKey, ingestionEndpoint, telemetry); try { CompletableResultCode result = new CompletableResultCode(); @@ -80,11 +80,11 @@ public CompletableResultCode send( } } - private static URL getFullIngestionUrl(URL endpoint) { + private static URL getFullIngestionUrl(String ingestionEndpoint) { try { - return new URL(endpoint, "v2.1/track"); + return new URL(new URL(ingestionEndpoint), "v2.1/track"); } catch (MalformedURLException e) { - throw new IllegalArgumentException("Invalid endpoint: " + endpoint, e); + throw new IllegalArgumentException("Invalid endpoint: " + ingestionEndpoint, e); } } diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryPipelineRequest.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryPipelineRequest.java index 01a3e354e9e..7283df2b431 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryPipelineRequest.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryPipelineRequest.java @@ -32,12 +32,15 @@ public class TelemetryPipelineRequest { private volatile URL url; private final String instrumentationKey; + private final String ingestionEndpoint; private final List telemetry; private final int contentLength; - TelemetryPipelineRequest(URL url, String instrumentationKey, List telemetry) { + TelemetryPipelineRequest( + URL url, String instrumentationKey, String ingestionEndpoint, List telemetry) { this.url = url; this.instrumentationKey = instrumentationKey; + this.ingestionEndpoint = ingestionEndpoint; this.telemetry = telemetry; contentLength = telemetry.stream().mapToInt(ByteBuffer::limit).sum(); } @@ -50,12 +53,16 @@ void setUrl(URL url) { this.url = url; } + public List getTelemetry() { + return telemetry; + } + public String getInstrumentationKey() { return instrumentationKey; } - public List getTelemetry() { - return telemetry; + public String getIngestionEndpoint() { + return ingestionEndpoint; } HttpRequest createHttpRequest() { diff --git a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/AzureMonitorExportersEndToEndTest.java b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/AzureMonitorExportersEndToEndTest.java index 67f20a12a49..4f0b4f82a1f 100644 --- a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/AzureMonitorExportersEndToEndTest.java +++ b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/AzureMonitorExportersEndToEndTest.java @@ -142,7 +142,7 @@ private void validateLogExporterEndToEnd() throws Exception { getClientBuilder().connectionString(TRACE_CONNECTION_STRING).buildLogExporter(); CompletableResultCode export = azureMonitorLogExporter.export(Collections.singleton(new MockLogData())); - export.join(30, TimeUnit.SECONDS); + export.join(10, TimeUnit.SECONDS); Assertions.assertTrue(export.isDone()); Assertions.assertTrue(export.isSuccess()); } @@ -159,7 +159,7 @@ private static List generateTraces(String testName) throws Except } finally { span.end(); } - traceExporterCountDown.await(60, TimeUnit.SECONDS); + traceExporterCountDown.await(10, TimeUnit.SECONDS); return customValidationPolicy.actualTelemetryItems; } @@ -173,7 +173,7 @@ private static List generateMetrics(String testName) throws Excep 1L, Attributes.of( AttributeKey.stringKey("name"), "apple", AttributeKey.stringKey("color"), "red")); - metricExporterCountDown.await(60, TimeUnit.SECONDS); + metricExporterCountDown.await(10, TimeUnit.SECONDS); return customValidationPolicy.actualTelemetryItems; } @@ -191,10 +191,7 @@ public Mono process( HttpPipelineCallContext context, HttpPipelineNextPolicy next) { Mono asyncBytes = FluxUtil.collectBytesInByteBufferStream(context.getHttpRequest().getBody()) - .map( - bytes -> { - return ungzip(bytes); - }); + .map(CustomValidationPolicy::ungzip); asyncBytes.subscribe( value -> { ObjectMapper objectMapper = createObjectMapper(); @@ -205,7 +202,7 @@ public Mono process( } countDown.countDown(); } catch (Exception e) { - // e.printStackTrace(); + throw new RuntimeException(e); } }); return next.process(); diff --git a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/MonitorExporterClientTestBase.java b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/MonitorExporterClientTestBase.java index 36a438d0e2f..2e3c540f1dd 100644 --- a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/MonitorExporterClientTestBase.java +++ b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/MonitorExporterClientTestBase.java @@ -30,6 +30,7 @@ import com.azure.core.test.TestMode; import com.azure.core.test.utils.TestResourceNamer; import com.azure.core.util.Configuration; +import com.azure.monitor.opentelemetry.exporter.implementation.configuration.ConnectionString; import com.azure.monitor.opentelemetry.exporter.implementation.models.MonitorBase; import com.azure.monitor.opentelemetry.exporter.implementation.models.MonitorDomain; import com.azure.monitor.opentelemetry.exporter.implementation.models.RequestData; @@ -42,8 +43,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.Objects; import java.util.UUID; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.TestInfo; @@ -127,29 +126,12 @@ TelemetryItem createRequestData( String connectionString = Configuration.getGlobalConfiguration().get("APPLICATIONINSIGHTS_CONNECTION_STRING", ""); - Map keyValues = parseConnectionString(connectionString); - String instrumentationKey = - keyValues.getOrDefault("InstrumentationKey", "{instrumentation-key}"); - return new TelemetryItem() .setVersion(1) - .setInstrumentationKey(instrumentationKey) + .setConnectionString(ConnectionString.parse(connectionString)) .setName("test-event-name") .setSampleRate(100.0f) .setTime(time.atOffset(ZoneOffset.UTC)) .setData(monitorBase); } - - private static Map parseConnectionString(String connectionString) { - Objects.requireNonNull(connectionString); - Map keyValues = new HashMap<>(); - String[] splits = connectionString.split(";"); - for (String split : splits) { - String[] keyValPair = split.split("="); - if (keyValPair.length == 2) { - keyValues.put(keyValPair[0], keyValPair[1]); - } - } - return keyValues; - } } diff --git a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/ConnectionStringParsingTests.java b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/ConnectionStringParsingTests.java index 62739596005..e04dfbfb227 100644 --- a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/ConnectionStringParsingTests.java +++ b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/ConnectionStringParsingTests.java @@ -38,8 +38,7 @@ void minimalString() throws Exception { ConnectionString parsed = ConnectionString.parse(cs); assertThat(parsed.getInstrumentationKey()).isEqualTo(ikey); - assertThat(parsed.getIngestionEndpoint()) - .isEqualTo(new URL(DefaultEndpoints.INGESTION_ENDPOINT)); + assertThat(parsed.getIngestionEndpoint()).isEqualTo(DefaultEndpoints.INGESTION_ENDPOINT); assertThat(parsed.getLiveEndpoint()).isEqualTo(new URL(DefaultEndpoints.LIVE_ENDPOINT)); } @@ -48,13 +47,12 @@ void ikeyWithSuffix() throws Exception { String ikey = "fake-ikey"; String suffix = "ai.example.com"; String cs = "InstrumentationKey=" + ikey + ";EndpointSuffix=" + suffix; - URL expectedIngestionEndpointUrl = - new URL( - "https://" - + ConnectionStringBuilder.EndpointPrefixes.INGESTION_ENDPOINT_PREFIX - + "." - + suffix - + "/"); + String expectedIngestionEndpoint = + "https://" + + ConnectionStringBuilder.EndpointPrefixes.INGESTION_ENDPOINT_PREFIX + + "." + + suffix + + "/"; URL expectedLiveEndpoint = new URL( "https://" @@ -65,7 +63,7 @@ void ikeyWithSuffix() throws Exception { ConnectionString parsed = ConnectionString.parse(cs); assertThat(parsed.getInstrumentationKey()).isEqualTo(ikey); - assertThat(parsed.getIngestionEndpoint()).isEqualTo(expectedIngestionEndpointUrl); + assertThat(parsed.getIngestionEndpoint()).isEqualTo(expectedIngestionEndpoint); assertThat(parsed.getLiveEndpoint()).isEqualTo(expectedLiveEndpoint); } @@ -74,13 +72,12 @@ void suffixWithPathRetainsThePath() throws Exception { String ikey = "fake-ikey"; String suffix = "ai.example.com/my-proxy-app/doProxy"; String cs = "InstrumentationKey=" + ikey + ";EndpointSuffix=" + suffix; - URL expectedIngestionEndpointUrl = - new URL( - "https://" - + ConnectionStringBuilder.EndpointPrefixes.INGESTION_ENDPOINT_PREFIX - + "." - + suffix - + "/"); + String expectedIngestionEndpoint = + "https://" + + ConnectionStringBuilder.EndpointPrefixes.INGESTION_ENDPOINT_PREFIX + + "." + + suffix + + "/"; URL expectedLiveEndpoint = new URL( "https://" @@ -91,7 +88,7 @@ void suffixWithPathRetainsThePath() throws Exception { ConnectionString parsed = ConnectionString.parse(cs); assertThat(parsed.getInstrumentationKey()).isEqualTo(ikey); - assertThat(parsed.getIngestionEndpoint()).isEqualTo(expectedIngestionEndpointUrl); + assertThat(parsed.getIngestionEndpoint()).isEqualTo(expectedIngestionEndpoint); assertThat(parsed.getLiveEndpoint()).isEqualTo(expectedLiveEndpoint); } @@ -100,13 +97,12 @@ void suffixSupportsPort() throws Exception { String ikey = "fake-ikey"; String suffix = "ai.example.com:9999"; String cs = "InstrumentationKey=" + ikey + ";EndpointSuffix=" + suffix; - URL expectedIngestionEndpointUrl = - new URL( - "https://" - + ConnectionStringBuilder.EndpointPrefixes.INGESTION_ENDPOINT_PREFIX - + "." - + suffix - + "/"); + String expectedIngestionEndpoint = + "https://" + + ConnectionStringBuilder.EndpointPrefixes.INGESTION_ENDPOINT_PREFIX + + "." + + suffix + + "/"; URL expectedLiveEndpoint = new URL( "https://" @@ -117,15 +113,14 @@ void suffixSupportsPort() throws Exception { ConnectionString parsed = ConnectionString.parse(cs); assertThat(parsed.getInstrumentationKey()).isEqualTo(ikey); - assertThat(parsed.getIngestionEndpoint()).isEqualTo(expectedIngestionEndpointUrl); + assertThat(parsed.getIngestionEndpoint()).isEqualTo(expectedIngestionEndpoint); assertThat(parsed.getLiveEndpoint()).isEqualTo(expectedLiveEndpoint); } @Test void ikeyWithExplicitEndpoints() throws Exception { String ikey = "fake-ikey"; - URL expectedIngestionEndpoint = new URL("https://ingestion.example.com"); - URL expectedIngestionEndpointUrl = new URL("https://ingestion.example.com/"); + String expectedIngestionEndpoint = "https://ingestion.example.com/"; String liveHost = "https://live.example.com"; URL expectedLiveEndpoint = new URL(liveHost + "/"); @@ -139,7 +134,7 @@ void ikeyWithExplicitEndpoints() throws Exception { ConnectionString parsed = ConnectionString.parse(cs); assertThat(parsed.getInstrumentationKey()).isEqualTo(ikey); - assertThat(parsed.getIngestionEndpoint()).isEqualTo(expectedIngestionEndpointUrl); + assertThat(parsed.getIngestionEndpoint()).isEqualTo(expectedIngestionEndpoint); assertThat(parsed.getLiveEndpoint()).isEqualTo(expectedLiveEndpoint); } @@ -147,8 +142,7 @@ void ikeyWithExplicitEndpoints() throws Exception { void explicitEndpointOverridesSuffix() throws Exception { String ikey = "fake-ikey"; String suffix = "ai.example.com"; - URL expectedIngestionEndpoint = new URL("https://ingestion.example.com"); - URL expectedIngestionEndpointUrl = new URL("https://ingestion.example.com/"); + String expectedIngestionEndpoint = "https://ingestion.example.com/"; URL expectedLiveEndpoint = new URL( "https://" @@ -166,7 +160,7 @@ void explicitEndpointOverridesSuffix() throws Exception { ConnectionString parsed = ConnectionString.parse(cs); assertThat(parsed.getInstrumentationKey()).isEqualTo(ikey); - assertThat(parsed.getIngestionEndpoint()).isEqualTo(expectedIngestionEndpointUrl); + assertThat(parsed.getIngestionEndpoint()).isEqualTo(expectedIngestionEndpoint); assertThat(parsed.getLiveEndpoint()).isEqualTo(expectedLiveEndpoint); } @@ -175,13 +169,12 @@ void emptyPairIsIgnored() throws MalformedURLException { String ikey = "fake-ikey"; String suffix = "ai.example.com"; String cs = "InstrumentationKey=" + ikey + ";;EndpointSuffix=" + suffix + ";"; - URL expectedIngestionEndpointUrl = - new URL( - "https://" - + ConnectionStringBuilder.EndpointPrefixes.INGESTION_ENDPOINT_PREFIX - + "." - + suffix - + "/"); + String expectedIngestionEndpoint = + "https://" + + ConnectionStringBuilder.EndpointPrefixes.INGESTION_ENDPOINT_PREFIX + + "." + + suffix + + "/"; URL expectedLiveEndpoint = new URL( "https://" @@ -192,7 +185,7 @@ void emptyPairIsIgnored() throws MalformedURLException { ConnectionString parsed = ConnectionString.parse(cs); assertThat(parsed.getInstrumentationKey()).isEqualTo(ikey); - assertThat(parsed.getIngestionEndpoint()).isEqualTo(expectedIngestionEndpointUrl); + assertThat(parsed.getIngestionEndpoint()).isEqualTo(expectedIngestionEndpoint); assertThat(parsed.getLiveEndpoint()).isEqualTo(expectedLiveEndpoint); } @@ -200,12 +193,12 @@ void emptyPairIsIgnored() throws MalformedURLException { void emptyKeyIsIgnored() throws MalformedURLException { String ikey = "fake-ikey"; String cs = "InstrumentationKey=" + ikey + ";=1234"; - URL expectedIngestionEndpointUrl = new URL(DefaultEndpoints.INGESTION_ENDPOINT); + String expectedIngestionEndpoint = DefaultEndpoints.INGESTION_ENDPOINT; URL expectedLiveEndpoint = new URL(DefaultEndpoints.LIVE_ENDPOINT); ConnectionString parsed = ConnectionString.parse(cs); assertThat(parsed.getInstrumentationKey()).isEqualTo(ikey); - assertThat(parsed.getIngestionEndpoint()).isEqualTo(expectedIngestionEndpointUrl); + assertThat(parsed.getIngestionEndpoint()).isEqualTo(expectedIngestionEndpoint); assertThat(parsed.getLiveEndpoint()).isEqualTo(expectedLiveEndpoint); } @@ -216,8 +209,7 @@ void emptyValueIsSameAsUnset() throws Exception { ConnectionString parsed = ConnectionString.parse(cs); assertThat(parsed.getInstrumentationKey()).isEqualTo(ikey); - assertThat(parsed.getIngestionEndpoint()) - .isEqualTo(new URL(DefaultEndpoints.INGESTION_ENDPOINT)); + assertThat(parsed.getIngestionEndpoint()).isEqualTo(DefaultEndpoints.INGESTION_ENDPOINT); assertThat(parsed.getLiveEndpoint()).isEqualTo(new URL(DefaultEndpoints.LIVE_ENDPOINT)); } @@ -236,7 +228,6 @@ void caseInsensitiveParsing() { assertThat(parsed2.getInstrumentationKey()).isEqualTo(parsed.getInstrumentationKey()); assertThat(parsed2.getIngestionEndpoint()).isEqualTo(parsed.getIngestionEndpoint()); - assertThat(parsed2.getIngestionEndpoint()).isEqualTo(parsed.getIngestionEndpoint()); assertThat(parsed2.getLiveEndpoint()).isEqualTo(parsed.getLiveEndpoint()); assertThat(parsed2.getProfilerEndpoint()).isEqualTo(parsed.getProfilerEndpoint()); } @@ -271,7 +262,6 @@ void orderDoesNotMatter() { assertThat(parsed2.getInstrumentationKey()).isEqualTo(parsed.getInstrumentationKey()); assertThat(parsed2.getIngestionEndpoint()).isEqualTo(parsed.getIngestionEndpoint()); - assertThat(parsed2.getIngestionEndpoint()).isEqualTo(parsed.getIngestionEndpoint()); assertThat(parsed2.getLiveEndpoint()).isEqualTo(parsed.getLiveEndpoint()); assertThat(parsed2.getProfilerEndpoint()).isEqualTo(parsed.getProfilerEndpoint()); } @@ -311,7 +301,7 @@ void httpEndpointKeepsScheme() throws Exception { ConnectionString parsed = ConnectionString.parse( "InstrumentationKey=fake-ikey;IngestionEndpoint=http://my-ai.example.com"); - assertThat(parsed.getIngestionEndpoint()).isEqualTo(new URL("http://my-ai.example.com/")); + assertThat(parsed.getIngestionEndpoint()).isEqualTo("http://my-ai.example.com/"); } @Test @@ -364,24 +354,23 @@ void resetEndpointUrlTest() { "InstrumentationKey=fake-key;IngestionEndpoint=https://ingestion.example.com/;LiveEndpoint=https://live.example.com/"; ConnectionString parsed = ConnectionString.parse(fakeConnectionString); - assertThat(parsed.getIngestionEndpoint().toString()) - .isEqualTo("https://ingestion.example.com/"); - assertThat(parsed.getLiveEndpoint().toString()).isEqualTo("https://live.example.com/"); + assertThat(parsed.getIngestionEndpoint()).isEqualTo("https://ingestion.example.com/"); + assertThat(parsed.getLiveEndpoint().toExternalForm()).isEqualTo("https://live.example.com/"); String newFakeConnectionString = "InstrumentationKey=new-fake-key;IngestionEndpoint=https://new-ingestion.example.com/;LiveEndpoint=https://new-live.example.com/"; parsed = ConnectionString.parse(newFakeConnectionString); - assertThat(parsed.getIngestionEndpoint().toString()) - .isEqualTo("https://new-ingestion.example.com/"); - assertThat(parsed.getLiveEndpoint().toString()).isEqualTo("https://new-live.example.com/"); + assertThat(parsed.getIngestionEndpoint()).isEqualTo("https://new-ingestion.example.com/"); + assertThat(parsed.getLiveEndpoint().toExternalForm()) + .isEqualTo("https://new-live.example.com/"); String newerFakeConnectionString = "InstrumentationKey=newer-fake-key;IngestionEndpoint=https://newer-ingestion.example.com/;LiveEndpoint=https://newer-live.example.com/"; parsed = ConnectionString.parse(newerFakeConnectionString); - assertThat(parsed.getIngestionEndpoint().toString()) - .isEqualTo("https://newer-ingestion.example.com/"); - assertThat(parsed.getLiveEndpoint().toString()).isEqualTo("https://newer-live.example.com/"); + assertThat(parsed.getIngestionEndpoint()).isEqualTo("https://newer-ingestion.example.com/"); + assertThat(parsed.getLiveEndpoint().toExternalForm()) + .isEqualTo("https://newer-live.example.com/"); } } diff --git a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/StatsbeatConnectionStringTest.java b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/StatsbeatConnectionStringTest.java index c5c7749c829..1f7a2a9b87d 100644 --- a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/StatsbeatConnectionStringTest.java +++ b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/StatsbeatConnectionStringTest.java @@ -88,7 +88,8 @@ public void testUpdateStatsbeatConnectionString() throws Exception { StatsbeatConnectionString statsbeatConnectionString = StatsbeatConnectionString.create(connectionString, ikeyConfig, endpointConfig); assertThat(statsbeatConnectionString.getInstrumentationKey()).isEqualTo(ikeyConfig); - assertThat(statsbeatConnectionString.getEndpoint().toString()).isEqualTo(endpointConfig + "/"); + assertThat(statsbeatConnectionString.getIngestionEndpoint().toString()) + .isEqualTo(endpointConfig + "/"); // case 2 // customer ikey is in non-eu @@ -102,7 +103,8 @@ public void testUpdateStatsbeatConnectionString() throws Exception { statsbeatConnectionString = StatsbeatConnectionString.create(connectionString, ikeyConfig, endpointConfig); assertThat(statsbeatConnectionString.getInstrumentationKey()).isEqualTo(ikeyConfig); - assertThat(statsbeatConnectionString.getEndpoint().toString()).isEqualTo(endpointConfig + "/"); + assertThat(statsbeatConnectionString.getIngestionEndpoint().toString()) + .isEqualTo(endpointConfig + "/"); // case 3 // customer ikey is in non-eu @@ -114,7 +116,7 @@ public void testUpdateStatsbeatConnectionString() throws Exception { statsbeatConnectionString = StatsbeatConnectionString.create(connectionString, null, null); assertThat(statsbeatConnectionString.getInstrumentationKey()) .isEqualTo(StatsbeatConnectionString.NON_EU_REGION_STATSBEAT_IKEY); - assertThat(statsbeatConnectionString.getEndpoint().toString()) + assertThat(statsbeatConnectionString.getIngestionEndpoint().toString()) .isEqualTo(StatsbeatConnectionString.NON_EU_REGION_STATSBEAT_ENDPOINT); // case 4 @@ -129,7 +131,8 @@ public void testUpdateStatsbeatConnectionString() throws Exception { statsbeatConnectionString = StatsbeatConnectionString.create(connectionString, ikeyConfig, endpointConfig); assertThat(statsbeatConnectionString.getInstrumentationKey()).isEqualTo(ikeyConfig); - assertThat(statsbeatConnectionString.getEndpoint().toString()).isEqualTo(endpointConfig + "/"); + assertThat(statsbeatConnectionString.getIngestionEndpoint().toString()) + .isEqualTo(endpointConfig + "/"); // case 5 // customer is in eu @@ -143,7 +146,8 @@ public void testUpdateStatsbeatConnectionString() throws Exception { statsbeatConnectionString = StatsbeatConnectionString.create(connectionString, ikeyConfig, endpointConfig); assertThat(statsbeatConnectionString.getInstrumentationKey()).isEqualTo(ikeyConfig); - assertThat(statsbeatConnectionString.getEndpoint().toString()).isEqualTo(endpointConfig + "/"); + assertThat(statsbeatConnectionString.getIngestionEndpoint().toString()) + .isEqualTo(endpointConfig + "/"); // case 6 // customer is in eu @@ -155,7 +159,7 @@ public void testUpdateStatsbeatConnectionString() throws Exception { statsbeatConnectionString = StatsbeatConnectionString.create(connectionString, null, null); assertThat(statsbeatConnectionString.getInstrumentationKey()) .isEqualTo(StatsbeatConnectionString.EU_REGION_STATSBEAT_IKEY); - assertThat(statsbeatConnectionString.getEndpoint().toString()) + assertThat(statsbeatConnectionString.getIngestionEndpoint().toString()) .isEqualTo(StatsbeatConnectionString.EU_REGION_STATSBEAT_ENDPOINT); } diff --git a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/IntegrationTests.java b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/IntegrationTests.java index c3fa5591332..cca32d76f55 100644 --- a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/IntegrationTests.java +++ b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/IntegrationTests.java @@ -21,7 +21,6 @@ package com.azure.monitor.opentelemetry.exporter.implementation.localstorage; -import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; @@ -32,6 +31,7 @@ import com.azure.core.http.HttpRequest; import com.azure.core.test.http.MockHttpResponse; import com.azure.core.util.Context; +import com.azure.monitor.opentelemetry.exporter.implementation.configuration.ConnectionString; import com.azure.monitor.opentelemetry.exporter.implementation.models.TelemetryItem; import com.azure.monitor.opentelemetry.exporter.implementation.pipeline.TelemetryItemExporter; import com.azure.monitor.opentelemetry.exporter.implementation.pipeline.TelemetryPipeline; @@ -39,11 +39,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; -import java.net.URL; -import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.List; @@ -58,8 +54,11 @@ public class IntegrationTests { + private static final ConnectionString CONNECTION_STRING = + ConnectionString.parse( + "InstrumentationKey=00000000-0000-0000-0000-0FEEDDADBEEF;IngestionEndpoint=http://foo.bar/"); private static final String INSTRUMENTATION_KEY = "00000000-0000-0000-0000-0FEEDDADBEEF"; - private static final String PERSISTED_FILENAME = "gzipped-raw-bytes.trn"; + private static final String INGESTION_ENDPOINT = "http://foo.bar/"; private TelemetryItemExporter telemetryItemExporter; @@ -69,7 +68,7 @@ public class IntegrationTests { private static final boolean testWithException = false; @BeforeEach - public void setup() throws Exception { + public void setup() { HttpClient mockedClient = mock(HttpClient.class); if (testWithException) { when(mockedClient.send(any(HttpRequest.class), any(Context.class))) @@ -88,7 +87,6 @@ public void setup() throws Exception { } HttpPipelineBuilder pipelineBuilder = new HttpPipelineBuilder().httpClient(mockedClient); - URL url = new URL("http://foo.bar"); TelemetryPipeline telemetryPipeline = new TelemetryPipeline(pipelineBuilder.build()); telemetryItemExporter = new TelemetryItemExporter( @@ -101,7 +99,7 @@ public void setup() throws Exception { public void integrationTest() throws Exception { List telemetryItems = new ArrayList<>(); for (int i = 0; i < 10; i++) { - TelemetryItem item = TestUtils.createMetricTelemetry("metric" + i, i, INSTRUMENTATION_KEY); + TelemetryItem item = TestUtils.createMetricTelemetry("metric" + i, i, CONNECTION_STRING); item.setTime(OffsetDateTime.parse("2021-11-09T03:12:19.06Z")); telemetryItems.add(item); } @@ -129,48 +127,19 @@ public void integrationTest() throws Exception { assertThat(localFileCache.getPersistedFilesCache().size()).isEqualTo(100); + String expected = Resources.readString("ungzip-source.txt"); + for (int i = 100; i > 0; i--) { LocalFileLoader.PersistedFile file = localFileLoader.loadTelemetriesFromDisk(); - assertThat(ungzip(file.rawBytes.array())) - .isEqualTo(new String(getByteBufferFromFile("ungzip-source.txt").array(), UTF_8)); assertThat(file.instrumentationKey).isEqualTo(INSTRUMENTATION_KEY); + assertThat(file.ingestionEndpoint).isEqualTo(INGESTION_ENDPOINT); + assertThat(ungzip(file.rawBytes.array())).isEqualTo(expected); assertThat(localFileCache.getPersistedFilesCache().size()).isEqualTo(i - 1); } assertThat(localFileCache.getPersistedFilesCache().size()).isEqualTo(0); } - @Test - public void verifyGzipRawBytesTest() throws Exception { - File sourceFile = - new File(getClass().getClassLoader().getResource(PERSISTED_FILENAME).getPath()); - File persistedFile = new File(tempFolder, PERSISTED_FILENAME); - Files.copy(sourceFile.toPath(), persistedFile.toPath()); - - assertThat(persistedFile.exists()).isTrue(); - - LocalFileCache localFileCache = new LocalFileCache(tempFolder); - localFileCache.addPersistedFile(persistedFile); - - LocalFileLoader localFileLoader = new LocalFileLoader(localFileCache, tempFolder, null, false); - LocalFileLoader.PersistedFile loadedPersistedFile = localFileLoader.loadTelemetriesFromDisk(); - - ByteBuffer expectedGzipByteBuffer = getByteBufferFromFile(PERSISTED_FILENAME); - byte[] ikeyBytes = new byte[36]; - expectedGzipByteBuffer.get(ikeyBytes, 0, 36); - assertThat(new String(ikeyBytes, UTF_8)).isEqualTo(INSTRUMENTATION_KEY); - int length = expectedGzipByteBuffer.remaining(); - byte[] telemetryBytes = new byte[length]; - - expectedGzipByteBuffer.get(telemetryBytes, 0, length); - assertThat(loadedPersistedFile.rawBytes).isEqualTo(ByteBuffer.wrap(telemetryBytes)); - } - - private ByteBuffer getByteBufferFromFile(String filename) throws Exception { - Path path = new File(getClass().getClassLoader().getResource(filename).getPath()).toPath(); - return ByteBuffer.wrap(Files.readAllBytes(path)); - } - private static String ungzip(byte[] rawBytes) throws Exception { try (GZIPInputStream in = new GZIPInputStream(new ByteArrayInputStream(rawBytes))) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); diff --git a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoaderTests.java b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoaderTests.java index 67367d7981d..ddb1392e57c 100644 --- a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoaderTests.java +++ b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoaderTests.java @@ -36,22 +36,13 @@ import com.azure.core.util.Context; import com.azure.monitor.opentelemetry.exporter.implementation.MockHttpResponse; import com.azure.monitor.opentelemetry.exporter.implementation.pipeline.TelemetryPipeline; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import io.opentelemetry.sdk.common.CompletableResultCode; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; -import java.net.URL; import java.nio.ByteBuffer; import java.nio.file.Files; -import java.util.Arrays; import java.util.List; import java.util.function.Function; -import java.util.zip.GZIPInputStream; -import java.util.zip.GZIPOutputStream; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import reactor.core.publisher.Mono; @@ -59,15 +50,13 @@ public class LocalFileLoaderTests { private static final String GZIPPED_RAW_BYTES_WITHOUT_IKEY = "gzipped-raw-bytes-without-ikey.trn"; - private static final String BYTE_BUFFERS_TEST_FILE = "read-transmission.txt"; + private static final String GZIPPED_RAW_BYTES_WITHOUT_INGESTION_ENDPOINT = + "gzipped-raw-bytes-without-ingestion-endpoint.trn"; private static final String INSTRUMENTATION_KEY = "00000000-0000-0000-0000-0FEEDDADBEEF"; - private static final ObjectMapper MAPPER = new ObjectMapper(); + private static final String INGESTION_ENDPOINT = "http://foo.bar/"; @TempDir File tempFolder; - @AfterEach - public void cleanup() {} - @Test public void testInstrumentationKeyRegex() { assertThat(LocalFileLoader.isInstrumentationKeyValid(INSTRUMENTATION_KEY)).isTrue(); @@ -81,11 +70,9 @@ public void testInstrumentationKeyRegex() { @Test public void testPersistedFileWithoutInstrumentationKey() throws IOException { - File sourceFile = - new File(getClass().getClassLoader().getResource(GZIPPED_RAW_BYTES_WITHOUT_IKEY).getPath()); - File persistedFile = new File(tempFolder, GZIPPED_RAW_BYTES_WITHOUT_IKEY); - Files.copy(sourceFile.toPath(), persistedFile.toPath()); + byte[] bytes = Resources.readBytes(GZIPPED_RAW_BYTES_WITHOUT_IKEY); + Files.write(persistedFile.toPath(), bytes); assertThat(persistedFile.exists()).isTrue(); LocalFileCache localFileCache = new LocalFileCache(tempFolder); @@ -99,13 +86,11 @@ public void testPersistedFileWithoutInstrumentationKey() throws IOException { } @Test - public void testLoadFile() throws IOException { - File sourceFile = - new File(getClass().getClassLoader().getResource(BYTE_BUFFERS_TEST_FILE).getPath()); - - File persistedFile = new File(tempFolder, BYTE_BUFFERS_TEST_FILE); + public void testPersistedFileWithoutIngestionEndpoint() throws IOException { - Files.copy(sourceFile.toPath(), persistedFile.toPath()); + File persistedFile = new File(tempFolder, GZIPPED_RAW_BYTES_WITHOUT_INGESTION_ENDPOINT); + byte[] bytes = Resources.readBytes(GZIPPED_RAW_BYTES_WITHOUT_INGESTION_ENDPOINT); + Files.write(persistedFile.toPath(), bytes); assertThat(persistedFile.exists()).isTrue(); LocalFileCache localFileCache = new LocalFileCache(tempFolder); @@ -113,128 +98,9 @@ public void testLoadFile() throws IOException { LocalFileLoader localFileLoader = new LocalFileLoader(localFileCache, tempFolder, null, false); LocalFileLoader.PersistedFile loadedPersistedFile = localFileLoader.loadTelemetriesFromDisk(); - assertThat(loadedPersistedFile.instrumentationKey).isEqualTo(INSTRUMENTATION_KEY); - String bytesString = new String(loadedPersistedFile.rawBytes.array(), UTF_8); - - String[] stringArray = bytesString.split("\n"); - assertThat(stringArray.length).isEqualTo(10); - - for (int i = 0; i < stringArray.length; i++) { - JsonNode jsonNode = MAPPER.readTree(stringArray[i]); - - // verify common properties - assertThat(jsonNode).hasSize(7); - assertThat(jsonNode.get("ver").asInt()).isEqualTo(1); - verifyTelemetryName(i, jsonNode.get("name").asText()); - verifyTelemetryTime(i, jsonNode.get("time").asText()); - assertThat(jsonNode.get("sampleRate").asInt()).isEqualTo(100); - assertThat(jsonNode.get("iKey").asText()).isEqualTo(INSTRUMENTATION_KEY); - - // verify tags - JsonNode tagsNode = jsonNode.get("tags"); - verifyTagsNodeSize(i, tagsNode.size()); - - assertThat(tagsNode.get("ai.internal.sdkVersion").asText()).isEqualTo("java:3.1.1"); - assertThat(tagsNode.get("ai.internal.nodeName").asText()).isEqualTo("test-role-name"); - assertThat(tagsNode.get("ai.cloud.roleInstance").asText()).isEqualTo("test-role-instance"); - if (i == 8) { // RemoteDependency - assertThat(tagsNode.get("ai.operation.id").asText()) - .isEqualTo("891b332db33c65cc6497c014f02db26d"); - } else if (i == 9) { - assertThat(tagsNode.get("ai.operation.id").asText()) - .isEqualTo("0cb22c0f071802f7f314569b007c9a1e"); - assertThat(tagsNode.get("ai.operation.name").asText()).isEqualTo("GET /webjars/**"); - assertThat(tagsNode.get("ai.user.userAgent").asText()) - .isEqualTo( - "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36"); - } - - // verify data - JsonNode data = jsonNode.get("data"); - verifyDataBaseType(i, data.get("baseType").asText()); - - JsonNode baseData = data.get("baseData"); - assertThat(baseData.get("ver").asInt()).isEqualTo(2); - JsonNode metrics = baseData.get("metrics"); - - if (i < 7) { // metrics is only applicable to Metric Telemetry type - assertThat(metrics.get(0).get("name").asText()).isEqualTo(expectedMetricsName(i)); - assertThat(metrics.get(0).get("value").asInt()).isEqualTo(expectedMetricsValue(i)); - } - - if (i == 7) { // Message - assertThat(baseData.get("message").asText()) - .isEqualTo("Tomcat initialized with port(s): 8080 (http)"); - assertThat(baseData.get("severityLevel").asText()).isEqualTo("Information"); - } - - if (i == 8) { // RemoteDependency's baseData - verifyRemoteDependencyBaseData(baseData); - } - - if (i == 9) { // Request's baseData - verifyRequestBaseData(baseData); - } - - // verify properties - verifyProperties(i, baseData.get("properties")); - } - } - - @Test - public void testWriteAndReadRandomText() { - String text = "hello world"; - LocalFileCache cache = new LocalFileCache(tempFolder); - LocalFileWriter writer = new LocalFileWriter(50, cache, tempFolder, null, false); - writer.writeToDisk(INSTRUMENTATION_KEY, singletonList(ByteBuffer.wrap(text.getBytes(UTF_8)))); - - LocalFileLoader loader = new LocalFileLoader(cache, tempFolder, null, false); - LocalFileLoader.PersistedFile persistedFile = loader.loadTelemetriesFromDisk(); - assertThat(new String(persistedFile.rawBytes.array(), UTF_8)).isEqualTo(text); - assertThat(persistedFile.instrumentationKey).isEqualTo(INSTRUMENTATION_KEY); - } - - @Test - public void testWriteGzipRawByte() throws IOException { - String text = - "1. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore \n" - + "2. magna aliquyam erat, sed diam voluptua. \n" - + "3. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum \n" - + "4. dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore\n" - + "5. magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, \n" - + "6. no sea takimata sanctus est Lorem ipsum dolor sit amet."; - - // gzip - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - try (GZIPOutputStream out = new GZIPOutputStream(byteArrayOutputStream)) { - out.write(text.getBytes(UTF_8)); - } finally { - byteArrayOutputStream.close(); - } - - // write gzipped bytes[] to disk - byte[] result = byteArrayOutputStream.toByteArray(); - LocalFileCache cache = new LocalFileCache(tempFolder); - LocalFileWriter writer = new LocalFileWriter(50, cache, tempFolder, null, false); - writer.writeToDisk(INSTRUMENTATION_KEY, singletonList(ByteBuffer.wrap(result))); - - // read gzipped byte[] from disk - LocalFileLoader loader = new LocalFileLoader(cache, tempFolder, null, false); - LocalFileLoader.PersistedFile persistedFile = loader.loadTelemetriesFromDisk(); - byte[] bytes = persistedFile.rawBytes.array(); - - // ungzip - ByteArrayInputStream inputStream = new ByteArrayInputStream(result); - byte[] ungzip = new byte[bytes.length * 3]; - int read; - try (GZIPInputStream gzipInputStream = new GZIPInputStream(inputStream)) { - read = gzipInputStream.read(ungzip, 0, ungzip.length); - } finally { - inputStream.close(); - } - - assertThat(new String(Arrays.copyOf(ungzip, read), UTF_8)).isEqualTo(text); - assertThat(persistedFile.instrumentationKey).isEqualTo(INSTRUMENTATION_KEY); + assertThat(loadedPersistedFile).isNull(); + assertThat(persistedFile.exists()) + .isFalse(); // verify the old formatted trn is deleted successfully. } @Test @@ -246,13 +112,14 @@ public void testDeleteFilePermanentlyOnSuccess() throws Exception { new LocalFileWriter(50, localFileCache, tempFolder, null, false); LocalFileLoader localFileLoader = new LocalFileLoader(localFileCache, tempFolder, null, false); - URL url = new URL("http://foo.bar"); TelemetryPipeline telemetryPipeline = new TelemetryPipeline(pipelineBuilder.build()); // persist 10 files to disk for (int i = 0; i < 10; i++) { localFileWriter.writeToDisk( - INSTRUMENTATION_KEY, singletonList(ByteBuffer.wrap("hello world".getBytes(UTF_8)))); + INSTRUMENTATION_KEY, + INGESTION_ENDPOINT, + singletonList(ByteBuffer.wrap("hello world".getBytes(UTF_8)))); } assertThat(localFileCache.getPersistedFilesCache().size()).isEqualTo(10); @@ -304,7 +171,9 @@ public void testDeleteFilePermanentlyOnFailure() throws Exception { // persist 10 files to disk for (int i = 0; i < 10; i++) { localFileWriter.writeToDisk( - INSTRUMENTATION_KEY, singletonList(ByteBuffer.wrap("hello world".getBytes(UTF_8)))); + INSTRUMENTATION_KEY, + INGESTION_ENDPOINT, + singletonList(ByteBuffer.wrap("hello world".getBytes(UTF_8)))); } assertThat(localFileCache.getPersistedFilesCache().size()).isEqualTo(10); @@ -332,177 +201,6 @@ public void testDeleteFilePermanentlyOnFailure() throws Exception { assertThat(localFileCache.getPersistedFilesCache().size()).isEqualTo(10); } - private static void verifyTelemetryName(int index, String actualName) { - String expectedName = null; - if (index < 6) { - expectedName = "Metric"; - } else if (index == 6) { - expectedName = "Statsbeat"; - } else if (index == 7) { - expectedName = "Message"; - } else if (index == 8) { - expectedName = "RemoteDependency"; - } else if (index == 9) { - expectedName = "Request"; - } - - assertThat(actualName).isEqualTo(expectedName); - } - - private static void verifyTelemetryTime(int index, String actualTime) { - String expectedTime = null; - if (index < 6) { - expectedTime = "2021-06-14T17:24:28.983-0700"; - } else if (index == 6) { - expectedTime = "2021-06-15T12:01:02.852-0700"; - } else if (index == 7) { - expectedTime = "2021-06-15T08:36:09.569-0700"; - } else if (index == 8) { - expectedTime = "2021-06-15T08:36:15.229-0700"; - } else if (index == 9) { - expectedTime = "2021-06-16T12:15:50.433-0700"; - } - - assertThat(actualTime).isEqualTo(expectedTime); - } - - private static void verifyTagsNodeSize(int index, int actualSize) { - int expectedSize = 0; - if (index < 8) { - expectedSize = 3; - } else if (index == 8) { - expectedSize = 4; - } else if (index == 9) { - expectedSize = 6; - } - - assertThat(actualSize).isEqualTo(expectedSize); - } - - private static void verifyDataBaseType(int index, String actualBaseType) { - String expectedBaseType = null; - if (index < 7) { - expectedBaseType = "MetricData"; - } else if (index == 7) { - expectedBaseType = "MessageData"; - } else if (index == 8) { - expectedBaseType = "RemoteDependencyData"; - } else if (index == 9) { - expectedBaseType = "RequestData"; - } - - assertThat(actualBaseType).isEqualTo(expectedBaseType); - } - - private static void verifyRemoteDependencyBaseData(JsonNode baseData) { - assertThat(baseData.get("name").asText()).isEqualTo("DROP TABLE vet_specialties IF EXISTS"); - assertThat(baseData.get("id").asText()).isEqualTo("d54e451407c13ad2"); - assertThat(baseData.get("duration").asText()).isEqualTo("00:00:00.0130000"); - assertThat(baseData.get("success").asText()).isEqualTo("true"); - assertThat(baseData.get("data").asText()).isEqualTo("DROP TABLE vet_specialties IF EXISTS"); - assertThat(baseData.get("type").asText()).isEqualTo("SQL"); - assertThat(baseData.get("target").asText()).isEqualTo("b8f14b49-a2ad-4fa9-967e-c00b1d6addc4"); - } - - private static void verifyRequestBaseData(JsonNode baseData) { - assertThat(baseData.get("id").asText()).isEqualTo("c0bfdc8f7963802c"); - assertThat(baseData.get("duration").asText()).isEqualTo("00:00:00.0210000"); - assertThat(baseData.get("responseCode").asText()).isEqualTo("304"); - assertThat(baseData.get("success").asText()).isEqualTo("true"); - assertThat(baseData.get("name").asText()).isEqualTo("GET /webjars/**"); - assertThat(baseData.get("url").asText()) - .isEqualTo("http://localhost:8080/webjars/jquery/2.2.4/jquery.min.js"); - } - - private static String expectedMetricsName(int index) { - switch (index) { - case 0: - return "jvm_threads_states"; - case 1: - return "hikaricp_connections_max"; - case 2: - return "process_uptime"; - case 3: - return "jvm_memory_used"; - case 4: - return "jvm_threads_live"; - case 5: - return "jdbc_connections_min"; - case 6: - return "Request Success Count"; - default: - throw new AssertionError("Unexpected index: " + index); - } - } - - private static int expectedMetricsValue(int index) { - switch (index) { - case 0: - return 3; - case 1: - return 10; - case 2: - return 3131610; - case 3: - return 12958128; - case 4: - return 150; - case 5: - return 110; - case 6: - return 2; - default: - throw new AssertionError("Unexpected index: " + index); - } - } - - private static void verifyProperties(int index, JsonNode properties) { - switch (index) { - case 0: - assertThat(properties.get("state").asText()).isEqualTo("blocked"); - return; - case 1: - assertThat(properties.get("pool").asText()).isEqualTo("HikariPool-1"); - return; - case 3: - assertThat(properties.get("area").asText()).isEqualTo("nonheap"); - assertThat(properties.get("id").asText()).isEqualTo("Compressed Class Space"); - return; - case 4: - assertThat(properties.get("state").asText()).isEqualTo("runnable"); - return; - case 5: - assertThat(properties.get("name").asText()).isEqualTo("dataSource"); - return; - case 6: // Statsbeat - verifyStatsbeatCustomDimensions(properties); - return; - case 7: // Message - assertThat(properties.get("LoggerName").asText()) - .isEqualTo("org.springframework.boot.web.embedded.tomcat.TomcatWebServer"); - assertThat(properties.get("SourceType").asText()).isEqualTo("Logger"); - return; - case 2: - case 8: - case 9: - assertThat(properties).isNull(); - return; - default: - throw new AssertionError("Unexpected index " + index); - } - } - - private static void verifyStatsbeatCustomDimensions(JsonNode properties) { - assertThat(properties.get("runtimeVersion").asText()).isEqualTo("11.0.7"); - assertThat(properties.get("os").asText()).isEqualTo("Windows"); - assertThat(properties.get("language").asText()).isEqualTo("java"); - assertThat(properties.get("attach").asText()).isEqualTo("codeless"); - assertThat(properties.get("instrumentation").asText()).isEqualTo("0"); - assertThat(properties.get("cikey").asText()).isEqualTo(INSTRUMENTATION_KEY); - assertThat(properties.get("version").asText()).isEqualTo("3.1.1"); - assertThat(properties.get("rp").asText()).isEqualTo("unknown"); - } - private static HttpClient getMockHttpClientSuccess() { return new MockHttpClient( request -> { diff --git a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFilePurgerTests.java b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFilePurgerTests.java index 910e3474462..521ca144ed4 100644 --- a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFilePurgerTests.java +++ b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFilePurgerTests.java @@ -36,7 +36,7 @@ public class LocalFilePurgerTests { @TempDir File tempFolder; @Test - public void testPurgedExpiredFiles() throws InterruptedException { + public void testPurgedExpiredFiles() throws Exception { String text = "hello world"; LocalFileCache cache = new LocalFileCache(tempFolder); LocalFileWriter writer = new LocalFileWriter(50, cache, tempFolder, null, false); @@ -48,6 +48,7 @@ public void testPurgedExpiredFiles() throws InterruptedException { for (int i = 0; i < 100; i++) { writer.writeToDisk( "00000000-0000-0000-0000-0FEEDDADBEE", + "http://foo.bar/", singletonList(ByteBuffer.wrap(text.getBytes(UTF_8)))); } diff --git a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileWriterTests.java b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileWriterTests.java index ef257efaf7a..26a85dd6572 100644 --- a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileWriterTests.java +++ b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileWriterTests.java @@ -28,10 +28,7 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.nio.ByteBuffer; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; @@ -43,62 +40,46 @@ public class LocalFileWriterTests { - private LocalFileCache localFileCache; + private static final String INSTRUMENTATION_KEY = "00000000-0000-0000-0000-0FEEDDADBEEF"; + private static final String INGESTION_ENDPOINT = "http://foo.bar/"; - private ByteBuffer buffer; + private LocalFileCache localFileCache; @TempDir File tempFolder; @BeforeEach public void setup() { localFileCache = new LocalFileCache(tempFolder); - - Path path = - new File(getClass().getClassLoader().getResource("write-transmission.txt").getPath()) - .toPath(); - try (InputStream in = Files.newInputStream(path)) { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - byte[] data = new byte[1024]; - int read; - while ((read = in.read(data, 0, data.length)) != -1) { - baos.write(data, 0, read); - } - buffer = ByteBuffer.wrap(baos.toByteArray()); - } catch (IOException ignored) { - } } @Test public void testWriteByteBuffersList() throws IOException { - byte[] bytes = new byte[buffer.remaining()]; - buffer.get(bytes); - String bytesToString = new String(bytes, UTF_8); + String content = Resources.readString("write-transmission.txt"); List byteBuffers = new ArrayList<>(); - String[] telemetries = bytesToString.split("\n"); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); + String[] telemetries = content.split("\n"); for (int i = 0; i < telemetries.length; i++) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); baos.write(telemetries[i].getBytes(UTF_8)); if (i < telemetries.length - 1) { baos.write('\r'); } - byteBuffers.add(ByteBuffer.wrap(baos.toByteArray())); - baos.reset(); } - baos.close(); assertThat(byteBuffers.size()).isEqualTo(10); LocalFileWriter writer = new LocalFileWriter(50, localFileCache, tempFolder, null, false); - writer.writeToDisk("00000000-0000-0000-0000-0FEEDDADBEEF", byteBuffers); + writer.writeToDisk(INSTRUMENTATION_KEY, INGESTION_ENDPOINT, byteBuffers); assertThat(localFileCache.getPersistedFilesCache().size()).isEqualTo(1); } @Test - public void testWriteRawByteArray() { + public void testWriteRawByteArray() throws IOException { LocalFileWriter writer = new LocalFileWriter(50, localFileCache, tempFolder, null, false); - writer.writeToDisk("00000000-0000-0000-0000-0FEEDDADBEEF", singletonList(buffer)); + byte[] content = Resources.readBytes("write-transmission.txt"); + writer.writeToDisk( + INSTRUMENTATION_KEY, INGESTION_ENDPOINT, singletonList(ByteBuffer.wrap(content))); assertThat(localFileCache.getPersistedFilesCache().size()).isEqualTo(1); } @@ -115,7 +96,8 @@ public void testWriteUnderMultipleThreadsEnvironment() throws InterruptedExcepti LocalFileWriter writer = new LocalFileWriter(50, localFileCache, tempFolder, null, false); writer.writeToDisk( - "00000000-0000-0000-0000-0FEEDDADBEEF", + INSTRUMENTATION_KEY, + INGESTION_ENDPOINT, singletonList(ByteBuffer.wrap(telemetry.getBytes(UTF_8)))); } }); diff --git a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/Resources.java b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/Resources.java new file mode 100644 index 00000000000..2b41cfb7a71 --- /dev/null +++ b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/Resources.java @@ -0,0 +1,49 @@ +/* + * ApplicationInsights-Java + * Copyright (c) Microsoft Corporation + * All rights reserved. + * + * MIT License + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the ""Software""), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package com.azure.monitor.opentelemetry.exporter.implementation.localstorage; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +class Resources { + + static String readString(String resourceName) throws IOException { + return new String(readBytes(resourceName), StandardCharsets.UTF_8); + } + + static byte[] readBytes(String resourceName) throws IOException { + try (InputStream in = + IntegrationTests.class.getClassLoader().getResourceAsStream(resourceName)) { + ByteArrayOutputStream result = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int length; + while ((length = in.read(buffer)) != -1) { + result.write(buffer, 0, length); + } + return result.toByteArray(); + } + } + + private Resources() {} +} diff --git a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporterTest.java b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporterTest.java index 7efd21c4672..daddd90ca44 100644 --- a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporterTest.java +++ b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporterTest.java @@ -30,6 +30,7 @@ import com.azure.core.http.HttpResponse; import com.azure.core.util.FluxUtil; import com.azure.monitor.opentelemetry.exporter.implementation.MockHttpResponse; +import com.azure.monitor.opentelemetry.exporter.implementation.configuration.ConnectionString; import com.azure.monitor.opentelemetry.exporter.implementation.localstorage.LocalStorageTelemetryPipelineListener; import com.azure.monitor.opentelemetry.exporter.implementation.models.TelemetryItem; import com.azure.monitor.opentelemetry.exporter.implementation.utils.TestUtils; @@ -38,8 +39,6 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.ArrayList; @@ -56,17 +55,23 @@ import reactor.core.publisher.Mono; public class TelemetryItemExporterTest { - RecordingHttpClient recordingHttpClient; + + private static final ConnectionString CONNECTION_STRING = + ConnectionString.parse( + "InstrumentationKey=00000000-0000-0000-0000-0FEEDDADBEEF;IngestionEndpoint=http://foo.bar"); + private static final ConnectionString REDIRECT_CONNECTION_STRING = + ConnectionString.parse( + "InstrumentationKey=11111111-0000-0000-0000-0FEEDDADBEEF;IngestionEndpoint=http://foo.bar"); + private static final String INSTRUMENTATION_KEY = "00000000-0000-0000-0000-0FEEDDADBEEF"; - private static final String REDIRECT_INSTRUMENTATION_KEY = "00000000-0000-0000-0000-0FEEDDADBEEE"; - private static final String END_POINT_URL = "http://foo.bar"; private static final String REDIRECT_URL = "http://foo.bar.redirect"; + RecordingHttpClient recordingHttpClient; + @TempDir File tempFolder; - private TelemetryItemExporter getExporter() throws MalformedURLException { + private TelemetryItemExporter getExporter() { HttpPipelineBuilder pipelineBuilder = new HttpPipelineBuilder().httpClient(recordingHttpClient); - URL url = new URL(END_POINT_URL); TelemetryPipeline telemetryPipeline = new TelemetryPipeline(pipelineBuilder.build()); return new TelemetryItemExporter( @@ -120,10 +125,10 @@ public void setup() { } @Test - public void singleIkeyTest() throws MalformedURLException { + public void singleIkeyTest() { // given List telemetryItems = new ArrayList<>(); - telemetryItems.add(TestUtils.createMetricTelemetry("metric" + 1, 1, INSTRUMENTATION_KEY)); + telemetryItems.add(TestUtils.createMetricTelemetry("metric" + 1, 1, CONNECTION_STRING)); TelemetryItemExporter exporter = getExporter(); // when @@ -135,12 +140,12 @@ public void singleIkeyTest() throws MalformedURLException { } @Test - public void dualIkeyTest() throws MalformedURLException { + public void dualIkeyTest() { // given List telemetryItems = new ArrayList<>(); - telemetryItems.add(TestUtils.createMetricTelemetry("metric" + 1, 1, INSTRUMENTATION_KEY)); + telemetryItems.add(TestUtils.createMetricTelemetry("metric" + 1, 1, CONNECTION_STRING)); telemetryItems.add( - TestUtils.createMetricTelemetry("metric" + 2, 2, REDIRECT_INSTRUMENTATION_KEY)); + TestUtils.createMetricTelemetry("metric" + 2, 2, REDIRECT_CONNECTION_STRING)); TelemetryItemExporter exporter = getExporter(); // when @@ -152,11 +157,11 @@ public void dualIkeyTest() throws MalformedURLException { } @Test - public void singleIkeyBatchTest() throws MalformedURLException { + public void singleIkeyBatchTest() { // given List telemetryItems = new ArrayList<>(); - telemetryItems.add(TestUtils.createMetricTelemetry("metric" + 1, 1, INSTRUMENTATION_KEY)); - telemetryItems.add(TestUtils.createMetricTelemetry("metric" + 2, 2, INSTRUMENTATION_KEY)); + telemetryItems.add(TestUtils.createMetricTelemetry("metric" + 1, 1, CONNECTION_STRING)); + telemetryItems.add(TestUtils.createMetricTelemetry("metric" + 2, 2, CONNECTION_STRING)); TelemetryItemExporter exporter = getExporter(); // when @@ -168,15 +173,15 @@ public void singleIkeyBatchTest() throws MalformedURLException { } @Test - public void dualIkeyBatchTest() throws MalformedURLException { + public void dualIkeyBatchTest() { // given List telemetryItems = new ArrayList<>(); - telemetryItems.add(TestUtils.createMetricTelemetry("metric" + 1, 1, INSTRUMENTATION_KEY)); - telemetryItems.add(TestUtils.createMetricTelemetry("metric" + 2, 2, INSTRUMENTATION_KEY)); + telemetryItems.add(TestUtils.createMetricTelemetry("metric" + 1, 1, CONNECTION_STRING)); + telemetryItems.add(TestUtils.createMetricTelemetry("metric" + 2, 2, CONNECTION_STRING)); telemetryItems.add( - TestUtils.createMetricTelemetry("metric" + 3, 3, REDIRECT_INSTRUMENTATION_KEY)); + TestUtils.createMetricTelemetry("metric" + 3, 3, REDIRECT_CONNECTION_STRING)); telemetryItems.add( - TestUtils.createMetricTelemetry("metric" + 4, 4, REDIRECT_INSTRUMENTATION_KEY)); + TestUtils.createMetricTelemetry("metric" + 4, 4, REDIRECT_CONNECTION_STRING)); TelemetryItemExporter exporter = getExporter(); // when @@ -188,15 +193,15 @@ public void dualIkeyBatchTest() throws MalformedURLException { } @Test - public void dualIkeyBatchWithDelayTest() throws MalformedURLException { + public void dualIkeyBatchWithDelayTest() { // given List telemetryItems = new ArrayList<>(); - telemetryItems.add(TestUtils.createMetricTelemetry("metric" + 1, 1, INSTRUMENTATION_KEY)); - telemetryItems.add(TestUtils.createMetricTelemetry("metric" + 2, 2, INSTRUMENTATION_KEY)); + telemetryItems.add(TestUtils.createMetricTelemetry("metric" + 1, 1, CONNECTION_STRING)); + telemetryItems.add(TestUtils.createMetricTelemetry("metric" + 2, 2, CONNECTION_STRING)); telemetryItems.add( - TestUtils.createMetricTelemetry("metric" + 3, 3, REDIRECT_INSTRUMENTATION_KEY)); + TestUtils.createMetricTelemetry("metric" + 3, 3, REDIRECT_CONNECTION_STRING)); telemetryItems.add( - TestUtils.createMetricTelemetry("metric" + 4, 4, REDIRECT_INSTRUMENTATION_KEY)); + TestUtils.createMetricTelemetry("metric" + 4, 4, REDIRECT_CONNECTION_STRING)); TelemetryItemExporter exporter = getExporter(); // when @@ -215,15 +220,15 @@ public void dualIkeyBatchWithDelayTest() throws MalformedURLException { } @Test - public void dualIkeyBatchWithDelayAndRedirectFlagFalseTest() throws MalformedURLException { + public void dualIkeyBatchWithDelayAndRedirectFlagFalseTest() { // given List telemetryItems = new ArrayList<>(); - telemetryItems.add(TestUtils.createMetricTelemetry("metric" + 1, 1, INSTRUMENTATION_KEY)); - telemetryItems.add(TestUtils.createMetricTelemetry("metric" + 2, 2, INSTRUMENTATION_KEY)); + telemetryItems.add(TestUtils.createMetricTelemetry("metric" + 1, 1, CONNECTION_STRING)); + telemetryItems.add(TestUtils.createMetricTelemetry("metric" + 2, 2, CONNECTION_STRING)); telemetryItems.add( - TestUtils.createMetricTelemetry("metric" + 3, 3, REDIRECT_INSTRUMENTATION_KEY)); + TestUtils.createMetricTelemetry("metric" + 3, 3, REDIRECT_CONNECTION_STRING)); telemetryItems.add( - TestUtils.createMetricTelemetry("metric" + 4, 4, REDIRECT_INSTRUMENTATION_KEY)); + TestUtils.createMetricTelemetry("metric" + 4, 4, REDIRECT_CONNECTION_STRING)); TelemetryItemExporter exporter = getExporter(); // when diff --git a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/quickpulse/QuickPulseCoordinatorTest.java b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/quickpulse/QuickPulseCoordinatorTest.java index ff3d76a3f83..4f07e335fd1 100644 --- a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/quickpulse/QuickPulseCoordinatorTest.java +++ b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/quickpulse/QuickPulseCoordinatorTest.java @@ -119,8 +119,7 @@ void testOnePingAndThenOnePost() throws InterruptedException { assertThat(collector.getQuickPulseStatus()).isEqualTo(QuickPulseStatus.QP_IS_OFF); } - // FIXME (trask) sporadically failing on CI - @Disabled + @Disabled("sporadically failing on CI") @Test void testOnePingAndThenOnePostWithRedirectedLink() throws InterruptedException { QuickPulseDataFetcher mockFetcher = Mockito.mock(QuickPulseDataFetcher.class); diff --git a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/quickpulse/QuickPulseDataCollectorTests.java b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/quickpulse/QuickPulseDataCollectorTests.java index 4a52016745a..7df8dc2d503 100644 --- a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/quickpulse/QuickPulseDataCollectorTests.java +++ b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/quickpulse/QuickPulseDataCollectorTests.java @@ -72,7 +72,7 @@ void requestTelemetryIsCounted_DurationIsSum() { long duration = 112233L; TelemetryItem telemetry = createRequestTelemetry("request-test", new Date(), duration, "200", true); - telemetry.setInstrumentationKey(FAKE_INSTRUMENTATION_KEY); + telemetry.setConnectionString(FAKE_CONNECTION_STRING); collector.add(telemetry); QuickPulseDataCollector.FinalCounters counters = collector.peek(); assertThat(counters.requests).isEqualTo(1); @@ -82,7 +82,7 @@ void requestTelemetryIsCounted_DurationIsSum() { // add another success and peek long duration2 = 65421L; telemetry = createRequestTelemetry("request-test-2", new Date(), duration2, "200", true); - telemetry.setInstrumentationKey(FAKE_INSTRUMENTATION_KEY); + telemetry.setConnectionString(FAKE_CONNECTION_STRING); collector.add(telemetry); counters = collector.peek(); double total = duration + duration2; @@ -93,7 +93,7 @@ void requestTelemetryIsCounted_DurationIsSum() { // add a failure and get/reset long duration3 = 9988L; telemetry = createRequestTelemetry("request-test-3", new Date(), duration3, "400", false); - telemetry.setInstrumentationKey(FAKE_INSTRUMENTATION_KEY); + telemetry.setConnectionString(FAKE_CONNECTION_STRING); collector.add(telemetry); counters = collector.getAndRestart(); total += duration3; @@ -115,7 +115,7 @@ void dependencyTelemetryIsCounted_DurationIsSum() { long duration = 112233L; TelemetryItem telemetry = createRemoteDependencyTelemetry("dep-test", "dep-test-cmd", duration, true); - telemetry.setInstrumentationKey(FAKE_INSTRUMENTATION_KEY); + telemetry.setConnectionString(FAKE_CONNECTION_STRING); collector.add(telemetry); QuickPulseDataCollector.FinalCounters counters = collector.peek(); assertThat(counters.rdds).isEqualTo(1); @@ -125,7 +125,7 @@ void dependencyTelemetryIsCounted_DurationIsSum() { // add another success and peek. long duration2 = 334455L; telemetry = createRemoteDependencyTelemetry("dep-test-2", "dep-test-cmd-2", duration2, true); - telemetry.setInstrumentationKey(FAKE_INSTRUMENTATION_KEY); + telemetry.setConnectionString(FAKE_CONNECTION_STRING); collector.add(telemetry); counters = collector.peek(); assertThat(counters.rdds).isEqualTo(2); @@ -136,7 +136,7 @@ void dependencyTelemetryIsCounted_DurationIsSum() { // add a failure and get/reset. long duration3 = 123456L; telemetry = createRemoteDependencyTelemetry("dep-test-3", "dep-test-cmd-3", duration3, false); - telemetry.setInstrumentationKey(FAKE_INSTRUMENTATION_KEY); + telemetry.setConnectionString(FAKE_CONNECTION_STRING); collector.add(telemetry); counters = collector.getAndRestart(); assertThat(counters.rdds).isEqualTo(3); @@ -155,13 +155,13 @@ void exceptionTelemetryIsCounted() { collector.enable(FAKE_CONNECTION_STRING::getInstrumentationKey); TelemetryItem telemetry = ExceptionTelemetryBuilder.create().build(); - telemetry.setInstrumentationKey(FAKE_INSTRUMENTATION_KEY); + telemetry.setConnectionString(FAKE_CONNECTION_STRING); collector.add(telemetry); QuickPulseDataCollector.FinalCounters counters = collector.peek(); assertThat(counters.exceptions).isEqualTo(1); telemetry = ExceptionTelemetryBuilder.create().build(); - telemetry.setInstrumentationKey(FAKE_INSTRUMENTATION_KEY); + telemetry.setConnectionString(FAKE_CONNECTION_STRING); collector.add(telemetry); counters = collector.getAndRestart(); assertThat(counters.exceptions).isEqualTo(2); @@ -255,7 +255,7 @@ void checkDocumentsListSize() { long duration = 112233L; TelemetryItem telemetry = createRequestTelemetry("request-test", new Date(), duration, "200", true); - telemetry.setInstrumentationKey(FAKE_INSTRUMENTATION_KEY); + telemetry.setConnectionString(FAKE_CONNECTION_STRING); for (int i = 0; i < 1005; i++) { collector.add(telemetry); } diff --git a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/quickpulse/QuickPulseIntegrationTests.java b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/quickpulse/QuickPulseIntegrationTests.java index 2010089cb12..ebc9d021ccb 100644 --- a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/quickpulse/QuickPulseIntegrationTests.java +++ b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/quickpulse/QuickPulseIntegrationTests.java @@ -143,12 +143,12 @@ public void testPostRequest() throws InterruptedException { // Request Telemetry TelemetryItem requestTelemetry = createRequestTelemetry("request-test", currDate, duration, "200", true); - requestTelemetry.setInstrumentationKey(instrumentationKey); + requestTelemetry.setConnectionString(connectionString); collector.add(requestTelemetry); // Dependency Telemetry TelemetryItem dependencyTelemetry = createRemoteDependencyTelemetry("dep-test", "dep-test-cmd", duration, true); - dependencyTelemetry.setInstrumentationKey(instrumentationKey); + dependencyTelemetry.setConnectionString(connectionString); collector.add(dependencyTelemetry); // Exception Telemetry ExceptionTelemetryBuilder builder = ExceptionTelemetryBuilder.create(); @@ -157,7 +157,7 @@ public void testPostRequest() throws InterruptedException { detailBuilder.setTypeName(Exception.class.getName()); builder.setExceptions(singletonList(detailBuilder)); TelemetryItem exceptionTelemetry = builder.build(); - exceptionTelemetry.setInstrumentationKey(instrumentationKey); + exceptionTelemetry.setConnectionString(connectionString); collector.add(exceptionTelemetry); QuickPulseCoordinatorInitData initData = diff --git a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/TestUtils.java b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/TestUtils.java index a75277a613b..a62c2dfd246 100644 --- a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/TestUtils.java +++ b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/TestUtils.java @@ -25,6 +25,7 @@ import com.azure.monitor.opentelemetry.exporter.AzureMonitorExporterBuilder; import com.azure.monitor.opentelemetry.exporter.AzureMonitorMetricExporter; import com.azure.monitor.opentelemetry.exporter.AzureMonitorTraceExporter; +import com.azure.monitor.opentelemetry.exporter.implementation.configuration.ConnectionString; import com.azure.monitor.opentelemetry.exporter.implementation.models.MetricDataPoint; import com.azure.monitor.opentelemetry.exporter.implementation.models.MetricsData; import com.azure.monitor.opentelemetry.exporter.implementation.models.MonitorBase; @@ -46,11 +47,11 @@ public final class TestUtils { public static TelemetryItem createMetricTelemetry( - String name, int value, String instrumentationKey) { + String name, int value, ConnectionString connectionString) { TelemetryItem telemetry = new TelemetryItem(); telemetry.setVersion(1); telemetry.setName("Metric"); - telemetry.setInstrumentationKey(instrumentationKey); + telemetry.setConnectionString(connectionString); Map tags = new HashMap<>(); tags.put("ai.internal.sdkVersion", "test_version"); tags.put("ai.internal.nodeName", "test_role_name"); diff --git a/agent/azure-monitor-exporter/src/test/resources/gzipped-raw-bytes.trn b/agent/azure-monitor-exporter/src/test/resources/gzipped-raw-bytes-without-ingestion-endpoint.trn similarity index 100% rename from agent/azure-monitor-exporter/src/test/resources/gzipped-raw-bytes.trn rename to agent/azure-monitor-exporter/src/test/resources/gzipped-raw-bytes-without-ingestion-endpoint.trn diff --git a/agent/azure-monitor-exporter/src/test/resources/read-transmission.txt b/agent/azure-monitor-exporter/src/test/resources/read-transmission.txt deleted file mode 100644 index 6c10671b8f6..00000000000 --- a/agent/azure-monitor-exporter/src/test/resources/read-transmission.txt +++ /dev/null @@ -1,10 +0,0 @@ -00000000-0000-0000-0000-0FEEDDADBEEF{"ver":1,"name":"Metric","time":"2021-06-14T17:24:28.983-0700","sampleRate":100,"iKey":"00000000-0000-0000-0000-0FEEDDADBEEF","tags":{"ai.internal.sdkVersion":"java:3.1.1","ai.internal.nodeName":"test-role-name","ai.cloud.roleInstance":"test-role-instance"},"data":{"baseType":"MetricData","baseData":{"ver":2,"metrics":[{"name":"jvm_threads_states","value":3}],"properties":{"state":"blocked"}}}} -{"ver":1,"name":"Metric","time":"2021-06-14T17:24:28.983-0700","sampleRate":100,"iKey":"00000000-0000-0000-0000-0FEEDDADBEEF","tags":{"ai.internal.sdkVersion":"java:3.1.1","ai.internal.nodeName":"test-role-name","ai.cloud.roleInstance":"test-role-instance"},"data":{"baseType":"MetricData","baseData":{"ver":2,"metrics":[{"name":"hikaricp_connections_max","value":10}],"properties":{"pool":"HikariPool-1"}}}} -{"ver":1,"name":"Metric","time":"2021-06-14T17:24:28.983-0700","sampleRate":100,"iKey":"00000000-0000-0000-0000-0FEEDDADBEEF","tags":{"ai.internal.sdkVersion":"java:3.1.1","ai.internal.nodeName":"test-role-name","ai.cloud.roleInstance":"test-role-instance"},"data":{"baseType":"MetricData","baseData":{"ver":2,"metrics":[{"name":"process_uptime","value":3131610}]}}} -{"ver":1,"name":"Metric","time":"2021-06-14T17:24:28.983-0700","sampleRate":100,"iKey":"00000000-0000-0000-0000-0FEEDDADBEEF","tags":{"ai.internal.sdkVersion":"java:3.1.1","ai.internal.nodeName":"test-role-name","ai.cloud.roleInstance":"test-role-instance"},"data":{"baseType":"MetricData","baseData":{"ver":2,"metrics":[{"name":"jvm_memory_used","value":12958128}],"properties":{"area":"nonheap","id":"Compressed Class Space"}}}} -{"ver":1,"name":"Metric","time":"2021-06-14T17:24:28.983-0700","sampleRate":100,"iKey":"00000000-0000-0000-0000-0FEEDDADBEEF","tags":{"ai.internal.sdkVersion":"java:3.1.1","ai.internal.nodeName":"test-role-name","ai.cloud.roleInstance":"test-role-instance"},"data":{"baseType":"MetricData","baseData":{"ver":2,"metrics":[{"name":"jvm_threads_live","value":150}],"properties":{"state":"runnable"}}}} -{"ver":1,"name":"Metric","time":"2021-06-14T17:24:28.983-0700","sampleRate":100,"iKey":"00000000-0000-0000-0000-0FEEDDADBEEF","tags":{"ai.internal.sdkVersion":"java:3.1.1","ai.internal.nodeName":"test-role-name","ai.cloud.roleInstance":"test-role-instance"},"data":{"baseType":"MetricData","baseData":{"ver":2,"metrics":[{"name":"jdbc_connections_min","value":110}],"properties":{"name":"dataSource"}}}} -{"ver":1,"name":"Statsbeat","time":"2021-06-15T12:01:02.852-0700","sampleRate":100.0,"iKey":"00000000-0000-0000-0000-0FEEDDADBEEF","tags":{"ai.internal.sdkVersion":"java:3.1.1","ai.internal.nodeName":"test-role-name","ai.cloud.roleInstance":"test-role-instance"},"data":{"baseType":"MetricData","baseData":{"ver":2,"metrics":[{"name":"Request Success Count","value":2.0}],"properties":{"runtimeVersion":"11.0.7","os":"Windows","language":"java","attach":"codeless","instrumentation":"0","cikey":"00000000-0000-0000-0000-0FEEDDADBEEF","version":"3.1.1","rp":"unknown"}}}} -{"ver":1,"name":"Message","time":"2021-06-15T08:36:09.569-0700","sampleRate":100.0,"iKey":"00000000-0000-0000-0000-0FEEDDADBEEF","tags":{"ai.internal.sdkVersion":"java:3.1.1","ai.internal.nodeName":"test-role-name","ai.cloud.roleInstance":"test-role-instance"},"data":{"baseType":"MessageData","baseData":{"ver":2,"message":"Tomcat initialized with port(s): 8080 (http)","severityLevel":"Information","properties":{"LoggerName":"org.springframework.boot.web.embedded.tomcat.TomcatWebServer","SourceType":"Logger"}}}} -{"ver":1,"name":"RemoteDependency","time":"2021-06-15T08:36:15.229-0700","sampleRate":100.0,"iKey":"00000000-0000-0000-0000-0FEEDDADBEEF","tags":{"ai.internal.sdkVersion":"java:3.1.1","ai.internal.nodeName":"test-role-name","ai.operation.id":"891b332db33c65cc6497c014f02db26d","ai.cloud.roleInstance":"test-role-instance"},"data":{"baseType":"RemoteDependencyData","baseData":{"ver":2,"name":"DROP TABLE vet_specialties IF EXISTS","id":"d54e451407c13ad2","duration":"00:00:00.0130000","success":true,"data":"DROP TABLE vet_specialties IF EXISTS","type":"SQL","target":"b8f14b49-a2ad-4fa9-967e-c00b1d6addc4"}}} -{"ver":1,"name":"Request","time":"2021-06-16T12:15:50.433-0700","sampleRate":100.0,"iKey":"00000000-0000-0000-0000-0FEEDDADBEEF","tags":{"ai.internal.sdkVersion":"java:3.1.1","ai.internal.nodeName":"test-role-name","ai.operation.id":"0cb22c0f071802f7f314569b007c9a1e","ai.operation.name":"GET /webjars/**","ai.cloud.roleInstance":"test-role-instance","ai.user.userAgent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36"},"data":{"baseType":"RequestData","baseData":{"ver":2,"id":"c0bfdc8f7963802c","duration":"00:00:00.0210000","responseCode":"304","success":true,"name":"GET /webjars/**","url":"http://localhost:8080/webjars/jquery/2.2.4/jquery.min.js"}}} \ No newline at end of file diff --git a/classic-sdk/core/src/main/java/com/microsoft/applicationinsights/telemetry/TelemetryContext.java b/classic-sdk/core/src/main/java/com/microsoft/applicationinsights/telemetry/TelemetryContext.java index 363dfc848c8..72d3d6e338c 100644 --- a/classic-sdk/core/src/main/java/com/microsoft/applicationinsights/telemetry/TelemetryContext.java +++ b/classic-sdk/core/src/main/java/com/microsoft/applicationinsights/telemetry/TelemetryContext.java @@ -44,6 +44,7 @@ public final class TelemetryContext { private final ContextTagsMap tags; private String instrumentationKey; + private String connectionString; private ComponentContext component; private DeviceContext device; private SessionContext session; @@ -136,11 +137,18 @@ public CloudContext getCloud() { * com.microsoft.applicationinsights.telemetry.Telemetry} * * @return The instrumentation key + * @deprecated Use {@link #setConnectionString(String)} and {@link #getConnectionString()} + * instead. */ + @Deprecated public String getInstrumentationKey() { return instrumentationKey; } + public String getConnectionString() { + return connectionString; + } + /** * Sets the default instrumentation key for all {@link * com.microsoft.applicationinsights.telemetry.Telemetry} objects logged in this {@link @@ -151,11 +159,17 @@ public String getInstrumentationKey() { * com.microsoft.applicationinsights.telemetry.Telemetry} * * @param instrumentationKey The instrumentation key + * @deprecated Use {@link #setConnectionString(String)} instead. */ + @Deprecated public void setInstrumentationKey(String instrumentationKey) { this.instrumentationKey = instrumentationKey; } + public void setConnectionString(String connectionString) { + this.connectionString = connectionString; + } + /** Gets a dictionary of application-defined property values. */ public ConcurrentMap getProperties() { return properties; diff --git a/smoke-tests/apps/CoreAndFilter2x/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/CoreAndFilter2xTest.java b/smoke-tests/apps/CoreAndFilter2x/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/CoreAndFilter2xTest.java index 88820a16f45..eb31e1f18c6 100644 --- a/smoke-tests/apps/CoreAndFilter2x/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/CoreAndFilter2xTest.java +++ b/smoke-tests/apps/CoreAndFilter2x/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/CoreAndFilter2xTest.java @@ -49,7 +49,10 @@ @UseAgent abstract class CoreAndFilter2xTest { - @RegisterExtension static final SmokeTestExtension testing = SmokeTestExtension.create(); + @RegisterExtension + static final SmokeTestExtension testing = + // standalone instrumentation keys are sent to the global ingestion endpoint + SmokeTestExtension.builder().usesGlobalIngestionEndpoint().build(); @Test @TargetUri("/trackDependency") diff --git a/smoke-tests/apps/CoreAndFilter3x/src/main/java/com/microsoft/applicationinsights/smoketestapp/SimpleTrackPageViewServlet.java b/smoke-tests/apps/CoreAndFilter3x/src/main/java/com/microsoft/applicationinsights/smoketestapp/SimpleTrackPageViewServlet.java index 377615c86af..d037522dd48 100644 --- a/smoke-tests/apps/CoreAndFilter3x/src/main/java/com/microsoft/applicationinsights/smoketestapp/SimpleTrackPageViewServlet.java +++ b/smoke-tests/apps/CoreAndFilter3x/src/main/java/com/microsoft/applicationinsights/smoketestapp/SimpleTrackPageViewServlet.java @@ -44,7 +44,9 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) { PageViewTelemetry pvt2 = new PageViewTelemetry("test-page-2"); // instrumentation key set on the Telemetry is used by interop - pvt2.getContext().setInstrumentationKey("12341234-1234-1234-1234-123412341234"); + pvt2.getContext() + .setConnectionString( + "InstrumentationKey=12341234-1234-1234-1234-123412341234;IngestionEndpoint=http://host.testcontainers.internal:6060/"); // role name and instance set on the Telemetry is used by interop pvt2.getContext().getCloud().setRole("role-goes-here"); pvt2.getContext().getCloud().setRoleInstance("role-instance-goes-here"); @@ -71,8 +73,11 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) { client.trackPageView(pvt2); TelemetryClient otherClient = new TelemetryClient(); - // instrumentation key set on the TelemetryClient is intentionally ignored by interop - otherClient.getContext().setInstrumentationKey("12341234-1234-1234-1234-123412341234"); + // connection string set on the TelemetryClient is intentionally ignored by interop + otherClient + .getContext() + .setConnectionString( + "InstrumentationKey=12341234-1234-1234-1234-123412341234;IngestionEndpoint=http://host.testcontainers.internal:6060/"); // role name and instance set on the TelemetryClient are intentionally ignored by interop otherClient.getContext().getCloud().setRole("role-goes-here"); otherClient.getContext().getCloud().setRoleInstance("role-instance-goes-here"); diff --git a/smoke-tests/apps/InstrumentationKeyOverrides/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/InstrumentationKeyOverridesTest.java b/smoke-tests/apps/InstrumentationKeyOverrides/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/InstrumentationKeyOverridesTest.java index 829ad0853cb..b38f7f6a897 100644 --- a/smoke-tests/apps/InstrumentationKeyOverrides/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/InstrumentationKeyOverridesTest.java +++ b/smoke-tests/apps/InstrumentationKeyOverrides/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/InstrumentationKeyOverridesTest.java @@ -31,7 +31,6 @@ import com.microsoft.applicationinsights.smoketest.schemav2.RequestData; import com.microsoft.applicationinsights.smoketest.schemav2.SeverityLevel; import java.util.List; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -39,20 +38,17 @@ @Environment(TOMCAT_8_JAVA_8) class InstrumentationKeyOverridesTest { - @RegisterExtension static final SmokeTestExtension testing = SmokeTestExtension.create(); + @RegisterExtension + static final SmokeTestExtension testing = + // standalone instrumentation keys are sent to the global ingestion endpoint + SmokeTestExtension.builder().usesGlobalIngestionEndpoint().build(); - // unfortunately, these tests don't pass, because instrumentation keys without ingestion endpoints - // (correctly) send to the default ingestion endpoint (https://dc.services.visualstudio.com/) - @Disabled @Test @TargetUri("/app2") void testApp2() throws Exception { testApp("12345678-0000-0000-0000-0FEEDDADBEEF"); } - // unfortunately, these tests don't pass, because instrumentation keys without ingestion endpoints - // (correctly) send to the default ingestion endpoint (https://dc.services.visualstudio.com/) - @Disabled @Test @TargetUri("/app3") void testApp3() throws Exception { @@ -100,8 +96,8 @@ private static void testApp(String iKey) throws Exception { assertThat(md.getProperties()).hasSize(3); SmokeTestExtension.assertParentChild( - rd, rdEnvelope, rddEnvelope, "GET /ConnectionStringOverrides/*"); + rd, rdEnvelope, rddEnvelope, "GET /InstrumentationKeyOverrides/*"); SmokeTestExtension.assertParentChild( - rd, rdEnvelope, mdEnvelope, "GET /ConnectionStringOverrides/*"); + rd, rdEnvelope, mdEnvelope, "GET /InstrumentationKeyOverrides/*"); } } diff --git a/smoke-tests/apps/Jdbc/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/JdbcTest.java b/smoke-tests/apps/Jdbc/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/JdbcTest.java index 4050246124a..9a38bcd83b6 100644 --- a/smoke-tests/apps/Jdbc/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/JdbcTest.java +++ b/smoke-tests/apps/Jdbc/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/JdbcTest.java @@ -33,6 +33,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.data.MapEntry.entry; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -300,8 +301,8 @@ void sqlServerStatement() throws Exception { telemetry.rd, telemetry.rdEnvelope, telemetry.rddEnvelope1, "GET /Jdbc/*"); } - // FIXME: need custom container with oracle db - // @Test + @Disabled("need custom container with oracle db") + @Test @TargetUri("/oraclePreparedStatement") void oraclePreparedStatement() throws Exception { Telemetry telemetry = testing.getTelemetry(1); @@ -321,8 +322,8 @@ void oraclePreparedStatement() throws Exception { telemetry.rd, telemetry.rdEnvelope, telemetry.rddEnvelope1, "GET /Jdbc/*"); } - // FIXME: need custom container with oracle db - // @Test + @Disabled("need custom container with oracle db") + @Test @TargetUri("/oracleStatement") void oracleStatement() throws Exception { Telemetry telemetry = testing.getTelemetry(1); diff --git a/smoke-tests/apps/Kafka/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/KafkaControllerSpansEnabledTest.java b/smoke-tests/apps/Kafka/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/KafkaControllerSpansEnabledTest.java index d01b1a2a288..73fa750c40b 100644 --- a/smoke-tests/apps/Kafka/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/KafkaControllerSpansEnabledTest.java +++ b/smoke-tests/apps/Kafka/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/KafkaControllerSpansEnabledTest.java @@ -41,8 +41,10 @@ class KafkaControllerSpansEnabledTest { @RegisterExtension static final SmokeTestExtension testing = - SmokeTestExtension.create( - new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:6.2.1")), "KAFKA"); + SmokeTestExtension.builder() + .setDependencyContainer( + "KAFKA", new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:6.2.1"))) + .build(); @Test @TargetUri("/sendMessage") diff --git a/smoke-tests/apps/Kafka/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/KafkaDisabledTest.java b/smoke-tests/apps/Kafka/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/KafkaDisabledTest.java index fb6a8c69903..69624f43286 100644 --- a/smoke-tests/apps/Kafka/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/KafkaDisabledTest.java +++ b/smoke-tests/apps/Kafka/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/KafkaDisabledTest.java @@ -41,8 +41,10 @@ class KafkaDisabledTest { @RegisterExtension static final SmokeTestExtension testing = - SmokeTestExtension.create( - new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:6.2.1")), "KAFKA"); + SmokeTestExtension.builder() + .setDependencyContainer( + "KAFKA", new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:6.2.1"))) + .build(); @Test @TargetUri("/sendMessage") diff --git a/smoke-tests/apps/Kafka/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/KafkaTest.java b/smoke-tests/apps/Kafka/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/KafkaTest.java index 518b60aed8b..6c468751812 100644 --- a/smoke-tests/apps/Kafka/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/KafkaTest.java +++ b/smoke-tests/apps/Kafka/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/KafkaTest.java @@ -48,8 +48,10 @@ abstract class KafkaTest { @RegisterExtension static final SmokeTestExtension testing = - SmokeTestExtension.create( - new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:6.2.1")), "KAFKA"); + SmokeTestExtension.builder() + .setDependencyContainer( + "KAFKA", new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:6.2.1"))) + .build(); @Test @TargetUri("/sendMessage") diff --git a/smoke-tests/apps/OpenTelemetryApiSupport/src/main/java/com/microsoft/applicationinsights/smoketestapp/TestController.java b/smoke-tests/apps/OpenTelemetryApiSupport/src/main/java/com/microsoft/applicationinsights/smoketestapp/TestController.java index 6902dbca627..9a800d1b58e 100644 --- a/smoke-tests/apps/OpenTelemetryApiSupport/src/main/java/com/microsoft/applicationinsights/smoketestapp/TestController.java +++ b/smoke-tests/apps/OpenTelemetryApiSupport/src/main/java/com/microsoft/applicationinsights/smoketestapp/TestController.java @@ -47,15 +47,15 @@ public String testOverridingConnectionStringEtc() { Span.current() .setAttribute( "ai.preview.connection_string", - "InstrumentationKey=12341234-1234-1234-1234-123412341234"); + "InstrumentationKey=12341234-1234-1234-1234-123412341234;IngestionEndpoint=http://host.testcontainers.internal:6060/"); Span.current().setAttribute("ai.preview.service_name", "role-name-here"); Span.current().setAttribute("ai.preview.service_instance_id", "role-instance-here"); Span.current().setAttribute("ai.preview.service_version", "application-version-here"); return "OK!"; } - @GetMapping("/test-overriding-ikey-etc") - public String testOverridingIkeyEtc() { + @GetMapping("/test-overriding-ikey") + public String testOverridingIkey() { Span.current() .setAttribute("ai.preview.instrumentation_key", "12341234-1234-1234-1234-123412341234"); return "OK!"; diff --git a/smoke-tests/apps/OpenTelemetryApiSupport/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/OpenTelemetryApiSupportControllerSpansEnabledTest.java b/smoke-tests/apps/OpenTelemetryApiSupport/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/OpenTelemetryApiSupportControllerSpansEnabledTest.java index 1eb87adce70..62406c2d65b 100644 --- a/smoke-tests/apps/OpenTelemetryApiSupport/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/OpenTelemetryApiSupportControllerSpansEnabledTest.java +++ b/smoke-tests/apps/OpenTelemetryApiSupport/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/OpenTelemetryApiSupportControllerSpansEnabledTest.java @@ -81,50 +81,6 @@ void testApi() throws Exception { "GET /OpenTelemetryApiSupport/test-api"); } - @Test - @TargetUri("/test-overriding-ikey-etc") - void testOverridingIkeyEtc() throws Exception { - Telemetry telemetry = testing.getTelemetry(1); - - assertThat(telemetry.rd.getName()) - .isEqualTo("GET /OpenTelemetryApiSupport/test-overriding-ikey-etc"); - assertThat(telemetry.rd.getUrl()) - .matches("http://localhost:[0-9]+/OpenTelemetryApiSupport/test-overriding-ikey-etc"); - assertThat(telemetry.rd.getResponseCode()).isEqualTo("200"); - assertThat(telemetry.rd.getSuccess()).isTrue(); - assertThat(telemetry.rd.getSource()).isNull(); - assertThat(telemetry.rd.getProperties()) - .containsExactly(entry("_MS.ProcessedByMetricExtractors", "True")); - assertThat(telemetry.rd.getMeasurements()).isEmpty(); - - assertThat(telemetry.rdd1.getName()).isEqualTo("TestController.testOverridingIkeyEtc"); - assertThat(telemetry.rdd1.getData()).isNull(); - assertThat(telemetry.rdd1.getType()).isEqualTo("InProc"); - assertThat(telemetry.rdd1.getTarget()).isNull(); - assertThat(telemetry.rdd1.getProperties()).isEmpty(); - assertThat(telemetry.rdd1.getSuccess()).isTrue(); - - // ideally want the properties below on rd, but can't get SERVER span yet, see - // https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/1726#issuecomment-731890267 - - // checking that instrumentation key, cloud role name, cloud role instance, and sdk version are - // from the agent - assertThat(telemetry.rddEnvelope1.getIKey()).isEqualTo("12341234-1234-1234-1234-123412341234"); - assertThat(telemetry.rddEnvelope1.getTags()).containsEntry("ai.cloud.role", "role-name-here"); - assertThat(telemetry.rddEnvelope1.getTags()) - .containsEntry("ai.cloud.roleInstance", "role-instance-here"); - assertThat(telemetry.rddEnvelope1.getTags()) - .containsEntry("ai.application.ver", "application-version-here"); - assertThat(telemetry.rddEnvelope1.getTags()) - .hasEntrySatisfying("ai.internal.sdkVersion", v -> assertThat(v).startsWith("java:3.")); - - SmokeTestExtension.assertParentChild( - telemetry.rd, - telemetry.rdEnvelope, - telemetry.rddEnvelope1, - "GET /OpenTelemetryApiSupport/test-overriding-ikey-etc"); - } - @Test @TargetUri("/test-extension-annotations") void testExtensionAnnotations() throws Exception { diff --git a/smoke-tests/apps/OpenTelemetryApiSupport/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/OpenTelemetryApiSupportInstrumentationKeyTest.java b/smoke-tests/apps/OpenTelemetryApiSupport/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/OpenTelemetryApiSupportInstrumentationKeyTest.java new file mode 100644 index 00000000000..09c5e3445e6 --- /dev/null +++ b/smoke-tests/apps/OpenTelemetryApiSupport/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/OpenTelemetryApiSupportInstrumentationKeyTest.java @@ -0,0 +1,91 @@ +/* + * ApplicationInsights-Java + * Copyright (c) Microsoft Corporation + * All rights reserved. + * + * MIT License + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the ""Software""), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package com.microsoft.applicationinsights.smoketest; + +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.TOMCAT_8_JAVA_11; +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.TOMCAT_8_JAVA_11_OPENJ9; +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.TOMCAT_8_JAVA_17; +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.TOMCAT_8_JAVA_18; +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.TOMCAT_8_JAVA_19; +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.TOMCAT_8_JAVA_8; +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.TOMCAT_8_JAVA_8_OPENJ9; +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.WILDFLY_13_JAVA_8; +import static com.microsoft.applicationinsights.smoketest.WarEnvironmentValue.WILDFLY_13_JAVA_8_OPENJ9; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.data.MapEntry.entry; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +@UseAgent +abstract class OpenTelemetryApiSupportInstrumentationKeyTest { + + @RegisterExtension + static final SmokeTestExtension testing = + SmokeTestExtension.builder().usesGlobalIngestionEndpoint().build(); + + @Test + @TargetUri("/test-overriding-ikey") + void testOverridingIkey() throws Exception { + Telemetry telemetry = testing.getTelemetry(0); + + assertThat(telemetry.rd.getName()) + .isEqualTo("GET /OpenTelemetryApiSupport/test-overriding-ikey"); + assertThat(telemetry.rd.getUrl()) + .matches("http://localhost:[0-9]+/OpenTelemetryApiSupport/test-overriding-ikey"); + assertThat(telemetry.rd.getResponseCode()).isEqualTo("200"); + assertThat(telemetry.rd.getSuccess()).isTrue(); + assertThat(telemetry.rd.getSource()).isNull(); + assertThat(telemetry.rd.getProperties()) + .containsExactly(entry("_MS.ProcessedByMetricExtractors", "True")); + assertThat(telemetry.rd.getMeasurements()).isEmpty(); + + assertThat(telemetry.rdEnvelope.getIKey()).isEqualTo("12341234-1234-1234-1234-123412341234"); + } + + @Environment(TOMCAT_8_JAVA_8) + static class Tomcat8Java8Test extends OpenTelemetryApiSupportInstrumentationKeyTest {} + + @Environment(TOMCAT_8_JAVA_8_OPENJ9) + static class Tomcat8Java8OpenJ9Test extends OpenTelemetryApiSupportInstrumentationKeyTest {} + + @Environment(TOMCAT_8_JAVA_11) + static class Tomcat8Java11Test extends OpenTelemetryApiSupportInstrumentationKeyTest {} + + @Environment(TOMCAT_8_JAVA_11_OPENJ9) + static class Tomcat8Java11OpenJ9Test extends OpenTelemetryApiSupportInstrumentationKeyTest {} + + @Environment(TOMCAT_8_JAVA_17) + static class Tomcat8Java17Test extends OpenTelemetryApiSupportInstrumentationKeyTest {} + + @Environment(TOMCAT_8_JAVA_18) + static class Tomcat8Java18Test extends OpenTelemetryApiSupportInstrumentationKeyTest {} + + @Environment(TOMCAT_8_JAVA_19) + static class Tomcat8Java19Test extends OpenTelemetryApiSupportInstrumentationKeyTest {} + + @Environment(WILDFLY_13_JAVA_8) + static class Wildfly13Java8Test extends OpenTelemetryApiSupportInstrumentationKeyTest {} + + @Environment(WILDFLY_13_JAVA_8_OPENJ9) + static class Wildfly13Java8OpenJ9Test extends OpenTelemetryApiSupportInstrumentationKeyTest {} +} diff --git a/smoke-tests/apps/OpenTelemetryApiSupport/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/OpenTelemetryApiSupportTest.java b/smoke-tests/apps/OpenTelemetryApiSupport/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/OpenTelemetryApiSupportTest.java index 9ba93133b89..d40eafbd929 100644 --- a/smoke-tests/apps/OpenTelemetryApiSupport/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/OpenTelemetryApiSupportTest.java +++ b/smoke-tests/apps/OpenTelemetryApiSupport/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/OpenTelemetryApiSupportTest.java @@ -102,34 +102,6 @@ void testOverridingConnectionStringEtc() throws Exception { .hasEntrySatisfying("ai.internal.sdkVersion", v -> assertThat(v).startsWith("java:3.")); } - @Test - @TargetUri("/test-overriding-ikey") - void testOverridingIkey() throws Exception { - Telemetry telemetry = testing.getTelemetry(0); - - assertThat(telemetry.rd.getName()) - .isEqualTo("GET /OpenTelemetryApiSupport/test-overriding-ikey"); - assertThat(telemetry.rd.getUrl()) - .matches("http://localhost:[0-9]+/OpenTelemetryApiSupport/test-overriding-ikey-etc"); - assertThat(telemetry.rd.getResponseCode()).isEqualTo("200"); - assertThat(telemetry.rd.getSuccess()).isTrue(); - assertThat(telemetry.rd.getSource()).isNull(); - assertThat(telemetry.rd.getProperties()) - .containsExactly(entry("_MS.ProcessedByMetricExtractors", "True")); - assertThat(telemetry.rd.getMeasurements()).isEmpty(); - - // checking that instrumentation key, cloud role name, cloud role instance, and sdk version are - // from the agent - assertThat(telemetry.rdEnvelope.getIKey()).isEqualTo("12341234-1234-1234-1234-123412341234"); - assertThat(telemetry.rdEnvelope.getTags()).containsEntry("ai.cloud.role", "role-name-here"); - assertThat(telemetry.rdEnvelope.getTags().get("ai.cloud.roleInstance")) - .isEqualTo("role-instance-here"); - assertThat(telemetry.rdEnvelope.getTags()) - .containsEntry("ai.application.ver", "application-version-here"); - assertThat(telemetry.rdEnvelope.getTags()) - .hasEntrySatisfying("ai.internal.sdkVersion", v -> assertThat(v).startsWith("java:3.")); - } - @Test @TargetUri("/test-extension-annotations") void testExtensionAnnotations() throws Exception { diff --git a/smoke-tests/apps/ReadOnly/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/ReadOnlyTest.java b/smoke-tests/apps/ReadOnly/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/ReadOnlyTest.java index 3ca07b601e0..cfea0d23727 100644 --- a/smoke-tests/apps/ReadOnly/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/ReadOnlyTest.java +++ b/smoke-tests/apps/ReadOnly/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/ReadOnlyTest.java @@ -44,7 +44,8 @@ abstract class ReadOnlyTest { @RegisterExtension - static final SmokeTestExtension testing = SmokeTestExtension.create(true, true); + static final SmokeTestExtension testing = + SmokeTestExtension.builder().setReadOnly(true).setSkipHealthCheck(true).build(); @Test void test() throws Exception { diff --git a/smoke-tests/apps/SamplingOverridesBackCompat/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/SamplingOverridesBackCompatTest.java b/smoke-tests/apps/SamplingOverridesBackCompat/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/SamplingOverridesBackCompatTest.java index 7864d550a74..435b72c05cd 100644 --- a/smoke-tests/apps/SamplingOverridesBackCompat/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/SamplingOverridesBackCompatTest.java +++ b/smoke-tests/apps/SamplingOverridesBackCompat/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/SamplingOverridesBackCompatTest.java @@ -79,8 +79,6 @@ void testNoisyJdbc() throws Exception { RequestData rd = (RequestData) ((Data) rdEnvelope.getData()).getBaseData(); - assertThat(rdEnvelope.getIKey()).isEqualTo("00000000-0000-0000-0000-0FEEDDADBEEF"); - assertThat(rdEnvelope.getTags()).containsEntry("ai.cloud.role", "testrolename"); assertThat(rd.getSuccess()).isTrue(); } @@ -105,16 +103,12 @@ void testRegularJdbc() throws Exception { RemoteDependencyData rdd = (RemoteDependencyData) ((Data) rddEnvelope.getData()).getBaseData(); - assertThat(rdEnvelope.getIKey()).isEqualTo("87654321-0000-0000-0000-0FEEDDADBEEF"); - assertThat(rdEnvelope.getTags()).containsEntry("ai.cloud.role", "app3"); assertThat(rd.getSuccess()).isTrue(); assertThat(rdd.getType()).isEqualTo("SQL"); assertThat(rdd.getTarget()).isEqualTo("hsqldb | testdb"); assertThat(rdd.getName()).isEqualTo("SELECT testdb.abc"); assertThat(rdd.getData()).isEqualTo("select * from abc"); - assertThat(rddEnvelope.getIKey()).isEqualTo("87654321-0000-0000-0000-0FEEDDADBEEF"); - assertThat(rddEnvelope.getTags()).containsEntry("ai.cloud.role", "app3"); assertThat(rdd.getSuccess()).isTrue(); SmokeTestExtension.assertParentChild( diff --git a/smoke-tests/apps/SamplingOverridesBackCompat/src/smokeTest/resources/applicationinsights.json b/smoke-tests/apps/SamplingOverridesBackCompat/src/smokeTest/resources/applicationinsights.json index c86d7663dca..692c15ef344 100644 --- a/smoke-tests/apps/SamplingOverridesBackCompat/src/smokeTest/resources/applicationinsights.json +++ b/smoke-tests/apps/SamplingOverridesBackCompat/src/smokeTest/resources/applicationinsights.json @@ -34,26 +34,6 @@ "id": "filter out noisy jdbc" } ] - }, - "instrumentationKeyOverrides": [ - { - "httpPathPrefix": "/SamplingOverridesBackCompat/login", - "instrumentationKey": "12345678-0000-0000-0000-0FEEDDADBEEF" - }, - { - "httpPathPrefix": "/SamplingOverridesBackCompat/regular-jdbc", - "instrumentationKey": "87654321-0000-0000-0000-0FEEDDADBEEF" - } - ], - "roleNameOverrides": [ - { - "httpPathPrefix": "/SamplingOverridesBackCompat/login", - "roleName": "app2" - }, - { - "httpPathPrefix": "/SamplingOverridesBackCompat/regular-jdbc", - "roleName": "app3" - } - ] + } } } diff --git a/smoke-tests/apps/SpringCloudStream/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/SpringCloudStreamControllerSpansEnabledTest.java b/smoke-tests/apps/SpringCloudStream/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/SpringCloudStreamControllerSpansEnabledTest.java index 5887685d567..42f5b92ed7f 100644 --- a/smoke-tests/apps/SpringCloudStream/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/SpringCloudStreamControllerSpansEnabledTest.java +++ b/smoke-tests/apps/SpringCloudStream/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/SpringCloudStreamControllerSpansEnabledTest.java @@ -41,8 +41,10 @@ class SpringCloudStreamControllerSpansEnabledTest { @RegisterExtension static final SmokeTestExtension testing = - SmokeTestExtension.create( - new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:6.2.1")), "KAFKA"); + SmokeTestExtension.builder() + .setDependencyContainer( + "KAFKA", new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:6.2.1"))) + .build(); @Test @TargetUri("/sendMessage") diff --git a/smoke-tests/apps/SpringCloudStream/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/SpringCloudStreamTest.java b/smoke-tests/apps/SpringCloudStream/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/SpringCloudStreamTest.java index 787a7dcd5ab..278f4d7ffe0 100644 --- a/smoke-tests/apps/SpringCloudStream/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/SpringCloudStreamTest.java +++ b/smoke-tests/apps/SpringCloudStream/src/smokeTest/java/com/microsoft/applicationinsights/smoketest/SpringCloudStreamTest.java @@ -48,8 +48,10 @@ abstract class SpringCloudStreamTest { @RegisterExtension static final SmokeTestExtension testing = - SmokeTestExtension.create( - new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:6.2.1")), "KAFKA"); + SmokeTestExtension.builder() + .setDependencyContainer( + "KAFKA", new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:6.2.1"))) + .build(); @Test @TargetUri("/sendMessage") diff --git a/smoke-tests/framework/src/main/java/com/microsoft/applicationinsights/smoketest/SmokeTestExtension.java b/smoke-tests/framework/src/main/java/com/microsoft/applicationinsights/smoketest/SmokeTestExtension.java index f32ecd6331a..de1a16557ec 100644 --- a/smoke-tests/framework/src/main/java/com/microsoft/applicationinsights/smoketest/SmokeTestExtension.java +++ b/smoke-tests/framework/src/main/java/com/microsoft/applicationinsights/smoketest/SmokeTestExtension.java @@ -80,6 +80,8 @@ public class SmokeTestExtension private static final int TELEMETRY_RECEIVE_TIMEOUT_SECONDS = 60; + private static final String FAKE_INGESTION_ENDPOINT = "http://host.testcontainers.internal:6060/"; + private static final File appFile = new File(System.getProperty("ai.smoke-test.test-app-file")); private static final File javaagentFile = new File(System.getProperty("ai.smoke-test.javaagent-file")); @@ -106,29 +108,27 @@ public class SmokeTestExtension private final String dependencyContainerEnvVarName; private final boolean skipHealthCheck; private final boolean readOnly; + private final boolean usesGlobalIngestionEndpoint; public static SmokeTestExtension create() { - return new SmokeTestExtension(false, false, null, null); - } - - public static SmokeTestExtension create(boolean skipHealthCheck, boolean readOnly) { - return new SmokeTestExtension(skipHealthCheck, readOnly, null, null); + return new SmokeTestExtension(null, null, false, false, false); } - public static SmokeTestExtension create( - GenericContainer dependencyContainer, String dependencyContainerEnvVarName) { - return new SmokeTestExtension(false, false, dependencyContainer, dependencyContainerEnvVarName); + public static SmokeTestExtensionBuilder builder() { + return new SmokeTestExtensionBuilder(); } - private SmokeTestExtension( - boolean skipHealthCheck, - boolean readOnly, + SmokeTestExtension( @Nullable GenericContainer dependencyContainer, - @Nullable String dependencyContainerEnvVarName) { + @Nullable String dependencyContainerEnvVarName, + boolean usesGlobalIngestionEndpoint, + boolean skipHealthCheck, + boolean readOnly) { this.skipHealthCheck = skipHealthCheck; this.readOnly = readOnly; this.dependencyContainer = dependencyContainer; this.dependencyContainerEnvVarName = dependencyContainerEnvVarName; + this.usesGlobalIngestionEndpoint = usesGlobalIngestionEndpoint; } @Override @@ -363,7 +363,8 @@ protected Set getLivenessCheckPorts() { .withEnv( "APPLICATIONINSIGHTS_CONNECTION_STRING", "InstrumentationKey=00000000-0000-0000-0000-0FEEDDADBEEF;" - + "IngestionEndpoint=http://host.testcontainers.internal:6060/") + + "IngestionEndpoint=" + + FAKE_INGESTION_ENDPOINT) .withNetwork(network) .withExposedPorts(8080) .withFileSystemBind( @@ -373,6 +374,10 @@ protected Set getLivenessCheckPorts() { List javaToolOptions = new ArrayList<>(); javaToolOptions.add("-Dapplicationinsights.testing.batch-schedule-delay-millis=500"); + if (usesGlobalIngestionEndpoint) { + javaToolOptions.add( + "-Dapplicationinsights.testing.global-ingestion-endpoint=" + FAKE_INGESTION_ENDPOINT); + } if (REMOTE_DEBUG) { javaToolOptions.add("-agentlib:jdwp=transport=dt_socket,address=5005,server=y,suspend=y"); } diff --git a/smoke-tests/framework/src/main/java/com/microsoft/applicationinsights/smoketest/SmokeTestExtensionBuilder.java b/smoke-tests/framework/src/main/java/com/microsoft/applicationinsights/smoketest/SmokeTestExtensionBuilder.java new file mode 100644 index 00000000000..789351ea588 --- /dev/null +++ b/smoke-tests/framework/src/main/java/com/microsoft/applicationinsights/smoketest/SmokeTestExtensionBuilder.java @@ -0,0 +1,64 @@ +/* + * ApplicationInsights-Java + * Copyright (c) Microsoft Corporation + * All rights reserved. + * + * MIT License + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the ""Software""), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package com.microsoft.applicationinsights.smoketest; + +import org.testcontainers.containers.GenericContainer; + +public class SmokeTestExtensionBuilder { + + private GenericContainer dependencyContainer; + private String dependencyContainerEnvVarName; + private boolean usesGlobalIngestionEndpoint; + private boolean skipHealthCheck; + private boolean readOnly; + + public SmokeTestExtensionBuilder setDependencyContainer( + String envVarName, GenericContainer container) { + this.dependencyContainer = container; + this.dependencyContainerEnvVarName = envVarName; + return this; + } + + public SmokeTestExtensionBuilder usesGlobalIngestionEndpoint() { + this.usesGlobalIngestionEndpoint = true; + return this; + } + + public SmokeTestExtensionBuilder setSkipHealthCheck(boolean skipHealthCheck) { + this.skipHealthCheck = skipHealthCheck; + return this; + } + + public SmokeTestExtensionBuilder setReadOnly(boolean readOnly) { + this.readOnly = readOnly; + return this; + } + + public SmokeTestExtension build() { + return new SmokeTestExtension( + dependencyContainer, + dependencyContainerEnvVarName, + usesGlobalIngestionEndpoint, + skipHealthCheck, + readOnly); + } +} From 993c411908552977ae153046b6f8048135000af7 Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Sun, 28 Aug 2022 17:53:43 -0700 Subject: [PATCH 06/17] Fix --- .../logging/DiagnosticTelemetryPipelineListener.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/logging/DiagnosticTelemetryPipelineListener.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/logging/DiagnosticTelemetryPipelineListener.java index f1812626afc..7902099565a 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/logging/DiagnosticTelemetryPipelineListener.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/logging/DiagnosticTelemetryPipelineListener.java @@ -67,7 +67,9 @@ public void onResponse(TelemetryPipelineRequest request, TelemetryPipelineRespon case 206: // PARTIAL CONTENT, Breeze-specific: PARTIAL SUCCESS case 400: // breeze returns if json content is bad (e.g. missing required field) operationLogger.recordFailure( - "Received response code 400 (" + "Received response code " + + responseCode + + " (" + getErrorMessageFromPartialSuccessResponse(response.getBody()) + ")", INGESTION_ERROR); From d4b07c3606ae24d4aa6038c97d9f5bb9c01ad0a7 Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Mon, 29 Aug 2022 10:48:43 -0700 Subject: [PATCH 07/17] More ikey -> connection string --- .../internal/classicsdk/BytecodeUtilImpl.java | 7 +-- .../builders/AbstractTelemetryBuilder.java | 4 ++ .../configuration/ConnectionString.java | 36 +++++++++++++++- .../ConnectionStringBuilder.java | 5 ++- .../localstorage/LocalFileLoader.java | 43 +++++++++---------- .../localstorage/LocalFileSender.java | 3 +- .../localstorage/LocalFileWriter.java | 10 ++--- ...LocalStorageTelemetryPipelineListener.java | 6 +-- .../implementation/models/TelemetryItem.java | 24 ++++++++--- .../pipeline/TelemetryItemExporter.java | 23 +++------- .../pipeline/TelemetryPipeline.java | 18 ++++---- .../pipeline/TelemetryPipelineRequest.java | 15 ++++--- .../localstorage/IntegrationTests.java | 11 ++--- .../localstorage/LocalFileLoaderTests.java | 31 +++---------- .../localstorage/LocalFilePurgerTests.java | 3 +- .../localstorage/LocalFileWriterTests.java | 13 +++--- .../pipeline/TelemetryItemExporterTest.java | 11 ++--- .../implementation/utils/TestUtils.java | 3 +- 18 files changed, 135 insertions(+), 131 deletions(-) diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/classicsdk/BytecodeUtilImpl.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/classicsdk/BytecodeUtilImpl.java index 9625c96a439..eb1d7dcaf89 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/classicsdk/BytecodeUtilImpl.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/classicsdk/BytecodeUtilImpl.java @@ -37,7 +37,6 @@ import com.azure.monitor.opentelemetry.exporter.implementation.builders.PageViewTelemetryBuilder; import com.azure.monitor.opentelemetry.exporter.implementation.builders.RemoteDependencyTelemetryBuilder; import com.azure.monitor.opentelemetry.exporter.implementation.builders.RequestTelemetryBuilder; -import com.azure.monitor.opentelemetry.exporter.implementation.configuration.ConnectionString; import com.azure.monitor.opentelemetry.exporter.implementation.models.ContextTagKeys; import com.azure.monitor.opentelemetry.exporter.implementation.models.SeverityLevel; import com.azure.monitor.opentelemetry.exporter.implementation.utils.FormattedDuration; @@ -49,7 +48,6 @@ import com.microsoft.applicationinsights.agent.internal.telemetry.TelemetryClient; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanContext; -import io.opentelemetry.instrumentation.api.internal.cache.Cache; import io.opentelemetry.sdk.trace.ReadableSpan; import java.net.URI; import java.net.URL; @@ -71,8 +69,6 @@ public class BytecodeUtilImpl implements BytecodeUtilDelegate { public static volatile FeatureStatsbeat featureStatsbeat; - private static final Cache connectionStringCache = Cache.bounded(100); - @Override public void trackEvent( @Nullable Date timestamp, @@ -548,8 +544,7 @@ private static void setConnectionString( connectionString = "InstrumentationKey=" + instrumentationKey; } if (connectionString != null) { - telemetryBuilder.setConnectionString( - connectionStringCache.computeIfAbsent(connectionString, ConnectionString::parse)); + telemetryBuilder.setConnectionString(connectionString); } } diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/AbstractTelemetryBuilder.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/AbstractTelemetryBuilder.java index bcec2fdb26b..b1351d8d823 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/AbstractTelemetryBuilder.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/AbstractTelemetryBuilder.java @@ -65,6 +65,10 @@ public void setSampleRate(float sampleRate) { telemetryItem.setSampleRate(sampleRate); } + public void setConnectionString(String connectionString) { + telemetryItem.setConnectionString(connectionString); + } + public void setConnectionString(ConnectionString connectionString) { telemetryItem.setConnectionString(connectionString); } diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/ConnectionString.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/ConnectionString.java index 1b1fbb1b53f..f7c4dfd3918 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/ConnectionString.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/ConnectionString.java @@ -21,25 +21,36 @@ package com.azure.monitor.opentelemetry.exporter.implementation.configuration; +import io.opentelemetry.instrumentation.api.internal.cache.Cache; import java.net.URL; public final class ConnectionString { + private static final Cache cache = Cache.bounded(100); + private final String instrumentationKey; private final String ingestionEndpoint; private final URL liveEndpoint; private final URL profilerEndpoint; + private final String parsedFrom; + ConnectionString( - String instrumentationKey, URL ingestionEndpoint, URL liveEndpoint, URL profilerEndpoint) { + String instrumentationKey, + URL ingestionEndpoint, + URL liveEndpoint, + URL profilerEndpoint, + String parsedFrom) { this.instrumentationKey = instrumentationKey; this.ingestionEndpoint = ingestionEndpoint.toExternalForm(); this.liveEndpoint = liveEndpoint; this.profilerEndpoint = profilerEndpoint; + this.parsedFrom = parsedFrom; } public static ConnectionString parse(String connectionString) { - return new ConnectionStringBuilder().setConnectionString(connectionString).build(); + return cache.computeIfAbsent( + connectionString, key -> new ConnectionStringBuilder().setConnectionString(key).build()); } public String getInstrumentationKey() { @@ -57,4 +68,25 @@ public URL getLiveEndpoint() { public URL getProfilerEndpoint() { return profilerEndpoint; } + + public String getParsedFrom() { + return parsedFrom; + } + + @Override + public int hashCode() { + return parsedFrom.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + ConnectionString that = (ConnectionString) obj; + return parsedFrom.equals(that.parsedFrom); + } } diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/ConnectionStringBuilder.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/ConnectionStringBuilder.java index 078a05928e9..69e166fd414 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/ConnectionStringBuilder.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/ConnectionStringBuilder.java @@ -34,6 +34,8 @@ class ConnectionStringBuilder { // visible for testing static final int CONNECTION_STRING_MAX_LENGTH = 4096; + private String parsedFrom; + private String instrumentationKey; private URL ingestionEndpoint; @@ -51,13 +53,14 @@ class ConnectionStringBuilder { } ConnectionStringBuilder setConnectionString(String connectionString) { + parsedFrom = connectionString; mapToConnectionConfiguration(getKeyValuePairs(connectionString)); return this; } ConnectionString build() { return new ConnectionString( - instrumentationKey, ingestionEndpoint, liveEndpoint, profilerEndpoint); + instrumentationKey, ingestionEndpoint, liveEndpoint, profilerEndpoint, parsedFrom); } private static Map getKeyValuePairs(String connectionString) { diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoader.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoader.java index 557c45ffbaa..3b7b19c4db1 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoader.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoader.java @@ -23,6 +23,7 @@ import static com.azure.monitor.opentelemetry.exporter.implementation.utils.AzureMonitorMsgId.DISK_PERSISTENCE_LOADER_ERROR; +import com.azure.monitor.opentelemetry.exporter.implementation.configuration.ConnectionString; import com.azure.monitor.opentelemetry.exporter.implementation.logging.OperationLogger; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.DataInputStream; @@ -30,16 +31,15 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.file.Files; -import java.util.regex.Pattern; import javax.annotation.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** This class manages loading a list of {@link ByteBuffer} from the disk. */ class LocalFileLoader { - // A regex to validate that an instrumentation key is well-formed. It's copied straight from the - // Breeze repo. - private static final String INSTRUMENTATION_KEY_REGEX = - "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"; + private static final Logger logger = LoggerFactory.getLogger(LocalFileLoader.class); + private static final String TEMPORARY_FILE_EXTENSION = ".tmp"; private final LocalFileCache localFileCache; @@ -110,8 +110,7 @@ PersistedFile loadTelemetriesFromDisk() { return null; } - String instrumentationKey; - String ingestionEndpoint; + String connectionString; byte[] telemetryBytes; try (DataInputStream dataInputStream = @@ -128,8 +127,8 @@ PersistedFile loadTelemetriesFromDisk() { return null; } - instrumentationKey = dataInputStream.readUTF(); - if (!isInstrumentationKeyValid(instrumentationKey)) { + connectionString = dataInputStream.readUTF(); + if (!isConnectionStringKeyValid(connectionString)) { // probably really old format where content was written directly with no ikey // need to close FileInputStream before delete @@ -138,8 +137,6 @@ PersistedFile loadTelemetriesFromDisk() { return null; } - ingestionEndpoint = dataInputStream.readUTF(); - int numBytes = dataInputStream.readInt(); telemetryBytes = new byte[numBytes]; dataInputStream.readFully(telemetryBytes); @@ -152,8 +149,7 @@ PersistedFile loadTelemetriesFromDisk() { } operationLogger.recordSuccess(); - return new PersistedFile( - tempFile, instrumentationKey, ingestionEndpoint, ByteBuffer.wrap(telemetryBytes)); + return new PersistedFile(tempFile, connectionString, ByteBuffer.wrap(telemetryBytes)); } private void deleteFile(File tempFile) { @@ -163,8 +159,14 @@ private void deleteFile(File tempFile) { } } - static boolean isInstrumentationKeyValid(String instrumentationKey) { - return Pattern.matches(INSTRUMENTATION_KEY_REGEX, instrumentationKey.toLowerCase()); + static boolean isConnectionStringKeyValid(String connectionString) { + try { + ConnectionString.parse(connectionString); + return true; + } catch (RuntimeException e) { + logger.debug(e.getMessage(), e); + return false; + } } // either delete it permanently on success or add it back to cache to be processed again later on @@ -207,19 +209,16 @@ void updateProcessedFileStatus(boolean successOrNonRetryableError, File file) { static class PersistedFile { final File file; - final String instrumentationKey; - final String ingestionEndpoint; + final String connectionString; final ByteBuffer rawBytes; - PersistedFile( - File file, String instrumentationKey, String ingestionEndpoint, ByteBuffer byteBuffer) { - if (instrumentationKey == null) { + PersistedFile(File file, String connectionString, ByteBuffer byteBuffer) { + if (connectionString == null) { throw new IllegalArgumentException("instrumentation key can not be null."); } this.file = file; - this.instrumentationKey = instrumentationKey; - this.ingestionEndpoint = ingestionEndpoint; + this.connectionString = connectionString; this.rawBytes = byteBuffer; } } diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileSender.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileSender.java index 706f52f3590..ad264343e5a 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileSender.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileSender.java @@ -83,8 +83,7 @@ public void run() { CompletableResultCode resultCode = telemetryPipeline.send( singletonList(persistedFile.rawBytes), - persistedFile.instrumentationKey, - persistedFile.ingestionEndpoint, + persistedFile.connectionString, TelemetryPipelineListener.composite( diagnosticListener, new LocalFileSenderTelemetryPipelineListener( diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileWriter.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileWriter.java index 67616a89c57..d83d01417d2 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileWriter.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileWriter.java @@ -68,7 +68,7 @@ final class LocalFileWriter { value = "SECPTI", // Potential Path Traversal justification = "The constructed file path cannot be controlled by an end user of the instrumented application") - void writeToDisk(String instrumentationKey, String ingestionEndpoint, List buffers) { + void writeToDisk(String connectionString, List buffers) { long size = getTotalSizeOfPersistedFiles(telemetryFolder); if (size >= diskPersistenceMaxSizeBytes) { operationLogger.recordFailure( @@ -93,7 +93,7 @@ void writeToDisk(String instrumentationKey, String ingestionEndpoint, List buffers) + private static void write(File file, String connectionString, List buffers) throws IOException { try (FileOutputStream fileOut = new FileOutputStream(file); DataOutputStream dataOut = new DataOutputStream(fileOut)) { dataOut.writeInt(1); // version - dataOut.writeUTF(instrumentationKey); - dataOut.writeUTF(ingestionEndpoint); + dataOut.writeUTF(connectionString); int numBytes = buffers.stream().mapToInt(ByteBuffer::remaining).sum(); dataOut.writeInt(numBytes); diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalStorageTelemetryPipelineListener.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalStorageTelemetryPipelineListener.java index fdaf2239bea..a25be219cd0 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalStorageTelemetryPipelineListener.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalStorageTelemetryPipelineListener.java @@ -63,16 +63,14 @@ public LocalStorageTelemetryPipelineListener( @Override public void onResponse(TelemetryPipelineRequest request, TelemetryPipelineResponse response) { if (StatusCode.isRetryable(response.getStatusCode())) { - localFileWriter.writeToDisk( - request.getInstrumentationKey(), request.getIngestionEndpoint(), request.getTelemetry()); + localFileWriter.writeToDisk(request.getConnectionString(), request.getTelemetry()); } } @Override public void onException( TelemetryPipelineRequest request, String errorMessage, Throwable throwable) { - localFileWriter.writeToDisk( - request.getInstrumentationKey(), request.getIngestionEndpoint(), request.getTelemetry()); + localFileWriter.writeToDisk(request.getConnectionString(), request.getTelemetry()); } @Override diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java index 9f794b41893..1fa002649ce 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java @@ -79,7 +79,7 @@ public final class TelemetryItem { @JsonProperty(value = "iKey") private String instrumentationKey; - @JsonIgnore private String ingestionEndpoint; + @JsonIgnore private String connectionString; /* * Key/value collection of context properties. See ContextTagKeys for @@ -221,21 +221,33 @@ public String getInstrumentationKey() { } @JsonIgnore - public String getIngestionEndpoint() { - return ingestionEndpoint; + public String getConnectionString() { + return connectionString; + } + + @JsonIgnore + public TelemetryItem setConnectionString(String connectionString) { + this.connectionString = connectionString; + this.instrumentationKey = ConnectionString.parse(connectionString).getInstrumentationKey(); + return this; } @JsonIgnore public TelemetryItem setConnectionString(ConnectionString connectionString) { - instrumentationKey = connectionString.getInstrumentationKey(); - ingestionEndpoint = connectionString.getIngestionEndpoint(); + this.connectionString = connectionString.getParsedFrom(); + this.instrumentationKey = connectionString.getInstrumentationKey(); return this; } @JsonIgnore public TelemetryItem setConnectionString(StatsbeatConnectionString connectionString) { instrumentationKey = connectionString.getInstrumentationKey(); - ingestionEndpoint = connectionString.getIngestionEndpoint(); + // TODO (trask) turn StatsbeatConnectionString into a real connection string? + this.connectionString = + "InstrumentationKey=" + + connectionString.getInstrumentationKey() + + ";IngestionEndpoint=" + + connectionString.getIngestionEndpoint(); return this; } diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporter.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporter.java index 32da04e2163..8183597ebeb 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporter.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporter.java @@ -90,24 +90,15 @@ public TelemetryItemExporter( } public CompletableResultCode send(List telemetryItems) { - // second level (ingestion endpoint) is just to protect against scenario where some telemetry - // is stamped with same ikey but bad ingestion endpoint, so only the bad telemetry will fail - Map>> groupings = new HashMap<>(); + Map> groupings = new HashMap<>(); for (TelemetryItem telemetryItem : telemetryItems) { groupings - .computeIfAbsent(telemetryItem.getInstrumentationKey(), k -> new HashMap<>()) - .computeIfAbsent(telemetryItem.getIngestionEndpoint(), k -> new ArrayList<>()) + .computeIfAbsent(telemetryItem.getConnectionString(), k -> new ArrayList<>()) .add(telemetryItem); } List resultCodeList = new ArrayList<>(); - for (Map.Entry>> outerEntry : groupings.entrySet()) { - for (Map.Entry> innerEntry : outerEntry.getValue().entrySet()) { - String instrumentationKey = outerEntry.getKey(); - String ingestionEndpoint = innerEntry.getKey(); - resultCodeList.add( - internalSendByInstrumentationKey( - innerEntry.getValue(), instrumentationKey, ingestionEndpoint)); - } + for (Map.Entry> entry : groupings.entrySet()) { + resultCodeList.add(internalSendByConnectionString(entry.getValue(), entry.getKey())); } return maybeAddToActiveExportResults(resultCodeList); } @@ -140,8 +131,8 @@ public CompletableResultCode shutdown() { return listener.shutdown(); } - CompletableResultCode internalSendByInstrumentationKey( - List telemetryItems, String instrumentationKey, String ingestionEndpoint) { + CompletableResultCode internalSendByConnectionString( + List telemetryItems, String connectionString) { List byteBuffers; try { byteBuffers = encode(telemetryItems); @@ -150,7 +141,7 @@ CompletableResultCode internalSendByInstrumentationKey( encodeBatchOperationLogger.recordFailure(t.getMessage(), t); return CompletableResultCode.ofFailure(); } - return telemetryPipeline.send(byteBuffers, instrumentationKey, ingestionEndpoint, listener); + return telemetryPipeline.send(byteBuffers, connectionString, listener); } List encode(List telemetryItems) throws IOException { diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryPipeline.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryPipeline.java index 40496798871..583e0b702e7 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryPipeline.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryPipeline.java @@ -25,6 +25,7 @@ import com.azure.core.http.HttpResponse; import com.azure.core.util.Context; import com.azure.core.util.tracing.Tracer; +import com.azure.monitor.opentelemetry.exporter.implementation.configuration.ConnectionString; import com.azure.monitor.opentelemetry.exporter.implementation.utils.StatusCode; import io.opentelemetry.sdk.common.CompletableResultCode; import java.net.MalformedURLException; @@ -44,7 +45,7 @@ public class TelemetryPipeline { private final HttpPipeline pipeline; - // key is instrumentationKey, value is redirectUrl + // key is connectionString, value is redirectUrl private final Map redirectCache = Collections.synchronizedMap( new LinkedHashMap() { @@ -59,16 +60,17 @@ public TelemetryPipeline(HttpPipeline pipeline) { } public CompletableResultCode send( - List telemetry, - String instrumentationKey, - String ingestionEndpoint, - TelemetryPipelineListener listener) { + List telemetry, String connectionString, TelemetryPipelineListener listener) { + + ConnectionString connectionStringObj = ConnectionString.parse(connectionString); URL url = redirectCache.computeIfAbsent( - instrumentationKey, ikey -> getFullIngestionUrl(ingestionEndpoint)); + connectionString, k -> getFullIngestionUrl(connectionStringObj.getIngestionEndpoint())); + TelemetryPipelineRequest request = - new TelemetryPipelineRequest(url, instrumentationKey, ingestionEndpoint, telemetry); + new TelemetryPipelineRequest( + url, connectionString, connectionStringObj.getInstrumentationKey(), telemetry); try { CompletableResultCode result = new CompletableResultCode(); @@ -148,7 +150,7 @@ private void onResponseBody( listener.onException(request, "Invalid redirect: " + location, e); return; } - redirectCache.put(request.getInstrumentationKey(), locationUrl); + redirectCache.put(request.getConnectionString(), locationUrl); request.setUrl(locationUrl); sendInternal(request, listener, result, remainingRedirects - 1); return; diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryPipelineRequest.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryPipelineRequest.java index 7283df2b431..6802d8976a7 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryPipelineRequest.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryPipelineRequest.java @@ -31,16 +31,16 @@ public class TelemetryPipelineRequest { private volatile URL url; + private final String connectionString; private final String instrumentationKey; - private final String ingestionEndpoint; private final List telemetry; private final int contentLength; TelemetryPipelineRequest( - URL url, String instrumentationKey, String ingestionEndpoint, List telemetry) { + URL url, String connectionString, String instrumentationKey, List telemetry) { this.url = url; + this.connectionString = connectionString; this.instrumentationKey = instrumentationKey; - this.ingestionEndpoint = ingestionEndpoint; this.telemetry = telemetry; contentLength = telemetry.stream().mapToInt(ByteBuffer::limit).sum(); } @@ -57,12 +57,13 @@ public List getTelemetry() { return telemetry; } - public String getInstrumentationKey() { - return instrumentationKey; + public String getConnectionString() { + return connectionString; } - public String getIngestionEndpoint() { - return ingestionEndpoint; + // used by statsbeat + public String getInstrumentationKey() { + return instrumentationKey; } HttpRequest createHttpRequest() { diff --git a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/IntegrationTests.java b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/IntegrationTests.java index cca32d76f55..6e7e1cff5da 100644 --- a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/IntegrationTests.java +++ b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/IntegrationTests.java @@ -31,7 +31,6 @@ import com.azure.core.http.HttpRequest; import com.azure.core.test.http.MockHttpResponse; import com.azure.core.util.Context; -import com.azure.monitor.opentelemetry.exporter.implementation.configuration.ConnectionString; import com.azure.monitor.opentelemetry.exporter.implementation.models.TelemetryItem; import com.azure.monitor.opentelemetry.exporter.implementation.pipeline.TelemetryItemExporter; import com.azure.monitor.opentelemetry.exporter.implementation.pipeline.TelemetryPipeline; @@ -54,11 +53,8 @@ public class IntegrationTests { - private static final ConnectionString CONNECTION_STRING = - ConnectionString.parse( - "InstrumentationKey=00000000-0000-0000-0000-0FEEDDADBEEF;IngestionEndpoint=http://foo.bar/"); - private static final String INSTRUMENTATION_KEY = "00000000-0000-0000-0000-0FEEDDADBEEF"; - private static final String INGESTION_ENDPOINT = "http://foo.bar/"; + private static final String CONNECTION_STRING = + "InstrumentationKey=00000000-0000-0000-0000-0FEEDDADBEEF;IngestionEndpoint=http://foo.bar/"; private TelemetryItemExporter telemetryItemExporter; @@ -131,8 +127,7 @@ public void integrationTest() throws Exception { for (int i = 100; i > 0; i--) { LocalFileLoader.PersistedFile file = localFileLoader.loadTelemetriesFromDisk(); - assertThat(file.instrumentationKey).isEqualTo(INSTRUMENTATION_KEY); - assertThat(file.ingestionEndpoint).isEqualTo(INGESTION_ENDPOINT); + assertThat(file.connectionString).isEqualTo(CONNECTION_STRING); assertThat(ungzip(file.rawBytes.array())).isEqualTo(expected); assertThat(localFileCache.getPersistedFilesCache().size()).isEqualTo(i - 1); } diff --git a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoaderTests.java b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoaderTests.java index ddb1392e57c..5ec51316eb3 100644 --- a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoaderTests.java +++ b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoaderTests.java @@ -52,22 +52,11 @@ public class LocalFileLoaderTests { private static final String GZIPPED_RAW_BYTES_WITHOUT_IKEY = "gzipped-raw-bytes-without-ikey.trn"; private static final String GZIPPED_RAW_BYTES_WITHOUT_INGESTION_ENDPOINT = "gzipped-raw-bytes-without-ingestion-endpoint.trn"; - private static final String INSTRUMENTATION_KEY = "00000000-0000-0000-0000-0FEEDDADBEEF"; - private static final String INGESTION_ENDPOINT = "http://foo.bar/"; + private static final String CONNECTION_STRING = + "InstrumentationKey=00000000-0000-0000-0000-0FEEDDADBEEF;IngestionEndpoint=http://foo.bar/"; @TempDir File tempFolder; - @Test - public void testInstrumentationKeyRegex() { - assertThat(LocalFileLoader.isInstrumentationKeyValid(INSTRUMENTATION_KEY)).isTrue(); - assertThat(LocalFileLoader.isInstrumentationKeyValid("fake-instrumentation-key")).isFalse(); - assertThat(LocalFileLoader.isInstrumentationKeyValid("5ED1AE38-41AF-11EC-81D3")).isFalse(); - assertThat(LocalFileLoader.isInstrumentationKeyValid("5ED1AE38-41AF-11EC-81D3-0242AC130003")) - .isTrue(); - assertThat(LocalFileLoader.isInstrumentationKeyValid("C6864988-6BF8-45EF-8590-1FD3D84E5A4D")) - .isTrue(); - } - @Test public void testPersistedFileWithoutInstrumentationKey() throws IOException { File persistedFile = new File(tempFolder, GZIPPED_RAW_BYTES_WITHOUT_IKEY); @@ -117,9 +106,7 @@ public void testDeleteFilePermanentlyOnSuccess() throws Exception { // persist 10 files to disk for (int i = 0; i < 10; i++) { localFileWriter.writeToDisk( - INSTRUMENTATION_KEY, - INGESTION_ENDPOINT, - singletonList(ByteBuffer.wrap("hello world".getBytes(UTF_8)))); + CONNECTION_STRING, singletonList(ByteBuffer.wrap("hello world".getBytes(UTF_8)))); } assertThat(localFileCache.getPersistedFilesCache().size()).isEqualTo(10); @@ -135,8 +122,7 @@ public void testDeleteFilePermanentlyOnSuccess() throws Exception { CompletableResultCode completableResultCode = telemetryPipeline.send( singletonList(persistedFile.rawBytes), - persistedFile.instrumentationKey, - persistedFile.ingestionEndpoint, + persistedFile.connectionString, new LocalFileSenderTelemetryPipelineListener(localFileLoader, persistedFile.file)); completableResultCode.join(10, SECONDS); assertThat(completableResultCode.isSuccess()).isEqualTo(true); @@ -171,9 +157,7 @@ public void testDeleteFilePermanentlyOnFailure() throws Exception { // persist 10 files to disk for (int i = 0; i < 10; i++) { localFileWriter.writeToDisk( - INSTRUMENTATION_KEY, - INGESTION_ENDPOINT, - singletonList(ByteBuffer.wrap("hello world".getBytes(UTF_8)))); + CONNECTION_STRING, singletonList(ByteBuffer.wrap("hello world".getBytes(UTF_8)))); } assertThat(localFileCache.getPersistedFilesCache().size()).isEqualTo(10); @@ -184,13 +168,12 @@ public void testDeleteFilePermanentlyOnFailure() throws Exception { // fail to send persisted files and expect them to be kept on disk for (int i = 0; i < 10; i++) { LocalFileLoader.PersistedFile persistedFile = localFileLoader.loadTelemetriesFromDisk(); - assertThat(persistedFile.instrumentationKey).isEqualTo(INSTRUMENTATION_KEY); + assertThat(persistedFile.connectionString).isEqualTo(CONNECTION_STRING); CompletableResultCode completableResultCode = telemetryPipeline.send( singletonList(persistedFile.rawBytes), - persistedFile.instrumentationKey, - persistedFile.ingestionEndpoint, + persistedFile.connectionString, new LocalFileSenderTelemetryPipelineListener(localFileLoader, persistedFile.file)); completableResultCode.join(10, SECONDS); assertThat(completableResultCode.isSuccess()).isEqualTo(false); diff --git a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFilePurgerTests.java b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFilePurgerTests.java index 521ca144ed4..5f9cef2ffe7 100644 --- a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFilePurgerTests.java +++ b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFilePurgerTests.java @@ -47,8 +47,7 @@ public void testPurgedExpiredFiles() throws Exception { // persist 100 files to disk for (int i = 0; i < 100; i++) { writer.writeToDisk( - "00000000-0000-0000-0000-0FEEDDADBEE", - "http://foo.bar/", + "InstrumentationKey=00000000-0000-0000-0000-0FEEDDADBEE;IngestionEndpoint=http://foo.bar/", singletonList(ByteBuffer.wrap(text.getBytes(UTF_8)))); } diff --git a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileWriterTests.java b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileWriterTests.java index 26a85dd6572..601b17900c4 100644 --- a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileWriterTests.java +++ b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileWriterTests.java @@ -40,8 +40,8 @@ public class LocalFileWriterTests { - private static final String INSTRUMENTATION_KEY = "00000000-0000-0000-0000-0FEEDDADBEEF"; - private static final String INGESTION_ENDPOINT = "http://foo.bar/"; + private static final String CONNECTION_STRING = + "InstrumentationKey=00000000-0000-0000-0000-0FEEDDADBEEF;IngestionEndpoint=http://foo.bar/"; private LocalFileCache localFileCache; @@ -70,7 +70,7 @@ public void testWriteByteBuffersList() throws IOException { assertThat(byteBuffers.size()).isEqualTo(10); LocalFileWriter writer = new LocalFileWriter(50, localFileCache, tempFolder, null, false); - writer.writeToDisk(INSTRUMENTATION_KEY, INGESTION_ENDPOINT, byteBuffers); + writer.writeToDisk(CONNECTION_STRING, byteBuffers); assertThat(localFileCache.getPersistedFilesCache().size()).isEqualTo(1); } @@ -78,8 +78,7 @@ public void testWriteByteBuffersList() throws IOException { public void testWriteRawByteArray() throws IOException { LocalFileWriter writer = new LocalFileWriter(50, localFileCache, tempFolder, null, false); byte[] content = Resources.readBytes("write-transmission.txt"); - writer.writeToDisk( - INSTRUMENTATION_KEY, INGESTION_ENDPOINT, singletonList(ByteBuffer.wrap(content))); + writer.writeToDisk(CONNECTION_STRING, singletonList(ByteBuffer.wrap(content))); assertThat(localFileCache.getPersistedFilesCache().size()).isEqualTo(1); } @@ -96,9 +95,7 @@ public void testWriteUnderMultipleThreadsEnvironment() throws InterruptedExcepti LocalFileWriter writer = new LocalFileWriter(50, localFileCache, tempFolder, null, false); writer.writeToDisk( - INSTRUMENTATION_KEY, - INGESTION_ENDPOINT, - singletonList(ByteBuffer.wrap(telemetry.getBytes(UTF_8)))); + CONNECTION_STRING, singletonList(ByteBuffer.wrap(telemetry.getBytes(UTF_8)))); } }); } diff --git a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporterTest.java b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporterTest.java index daddd90ca44..7a128088c3a 100644 --- a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporterTest.java +++ b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/pipeline/TelemetryItemExporterTest.java @@ -30,7 +30,6 @@ import com.azure.core.http.HttpResponse; import com.azure.core.util.FluxUtil; import com.azure.monitor.opentelemetry.exporter.implementation.MockHttpResponse; -import com.azure.monitor.opentelemetry.exporter.implementation.configuration.ConnectionString; import com.azure.monitor.opentelemetry.exporter.implementation.localstorage.LocalStorageTelemetryPipelineListener; import com.azure.monitor.opentelemetry.exporter.implementation.models.TelemetryItem; import com.azure.monitor.opentelemetry.exporter.implementation.utils.TestUtils; @@ -56,12 +55,10 @@ public class TelemetryItemExporterTest { - private static final ConnectionString CONNECTION_STRING = - ConnectionString.parse( - "InstrumentationKey=00000000-0000-0000-0000-0FEEDDADBEEF;IngestionEndpoint=http://foo.bar"); - private static final ConnectionString REDIRECT_CONNECTION_STRING = - ConnectionString.parse( - "InstrumentationKey=11111111-0000-0000-0000-0FEEDDADBEEF;IngestionEndpoint=http://foo.bar"); + private static final String CONNECTION_STRING = + "InstrumentationKey=00000000-0000-0000-0000-0FEEDDADBEEF;IngestionEndpoint=http://foo.bar"; + private static final String REDIRECT_CONNECTION_STRING = + "InstrumentationKey=11111111-0000-0000-0000-0FEEDDADBEEF;IngestionEndpoint=http://foo.bar"; private static final String INSTRUMENTATION_KEY = "00000000-0000-0000-0000-0FEEDDADBEEF"; private static final String REDIRECT_URL = "http://foo.bar.redirect"; diff --git a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/TestUtils.java b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/TestUtils.java index a62c2dfd246..f0ebae2a325 100644 --- a/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/TestUtils.java +++ b/agent/azure-monitor-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/TestUtils.java @@ -25,7 +25,6 @@ import com.azure.monitor.opentelemetry.exporter.AzureMonitorExporterBuilder; import com.azure.monitor.opentelemetry.exporter.AzureMonitorMetricExporter; import com.azure.monitor.opentelemetry.exporter.AzureMonitorTraceExporter; -import com.azure.monitor.opentelemetry.exporter.implementation.configuration.ConnectionString; import com.azure.monitor.opentelemetry.exporter.implementation.models.MetricDataPoint; import com.azure.monitor.opentelemetry.exporter.implementation.models.MetricsData; import com.azure.monitor.opentelemetry.exporter.implementation.models.MonitorBase; @@ -47,7 +46,7 @@ public final class TestUtils { public static TelemetryItem createMetricTelemetry( - String name, int value, ConnectionString connectionString) { + String name, int value, String connectionString) { TelemetryItem telemetry = new TelemetryItem(); telemetry.setVersion(1); telemetry.setName("Metric"); From 020e475b92f45cfd362371694d0144ef8f4b9d34 Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Mon, 29 Aug 2022 11:28:15 -0700 Subject: [PATCH 08/17] Remove setInstrumentationKey from classic sdk --- .../TelemetryContextClassFileTransformer.java | 17 +++++++++ .../telemetry/TelemetryContext.java | 36 ------------------- 2 files changed, 17 insertions(+), 36 deletions(-) diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/classicsdk/TelemetryContextClassFileTransformer.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/classicsdk/TelemetryContextClassFileTransformer.java index 0c7fa15c859..3ae8be2911d 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/classicsdk/TelemetryContextClassFileTransformer.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/classicsdk/TelemetryContextClassFileTransformer.java @@ -75,6 +75,7 @@ private static class TelemetryContextClassVisitor extends ClassVisitor { private final ClassWriter cw; private boolean foundGetConnectionStringMethod; + private boolean foundGetInstrumentationKeyMethod; private TelemetryContextClassVisitor(ClassWriter cw) { super(ASM9, cw); @@ -91,6 +92,9 @@ public MethodVisitor visitMethod( if (name.equals("getConnectionString") && descriptor.equals("()Ljava/lang/String;")) { foundGetConnectionStringMethod = true; } + if (name.equals("getInstrumentationKey") && descriptor.equals("()Ljava/lang/String;")) { + foundGetInstrumentationKeyMethod = true; + } return super.visitMethod(access, name, descriptor, signature, exceptions); } @@ -99,6 +103,9 @@ public void visitEnd() { if (!foundGetConnectionStringMethod) { writeGetConnectionStringMethod(); } + if (!foundGetInstrumentationKeyMethod) { + writeGetInstrumentationKeyMethod(); + } } private void writeGetConnectionStringMethod() { @@ -110,5 +117,15 @@ private void writeGetConnectionStringMethod() { mv.visitMaxs(1, 1); mv.visitEnd(); } + + private void writeGetInstrumentationKeyMethod() { + MethodVisitor mv = + cw.visitMethod(ACC_PUBLIC, "getInstrumentationKey", "()Ljava/lang/String;", null, null); + mv.visitCode(); + mv.visitInsn(ACONST_NULL); + mv.visitInsn(ARETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } } } diff --git a/classic-sdk/core/src/main/java/com/microsoft/applicationinsights/telemetry/TelemetryContext.java b/classic-sdk/core/src/main/java/com/microsoft/applicationinsights/telemetry/TelemetryContext.java index 72d3d6e338c..c97ee1d9450 100644 --- a/classic-sdk/core/src/main/java/com/microsoft/applicationinsights/telemetry/TelemetryContext.java +++ b/classic-sdk/core/src/main/java/com/microsoft/applicationinsights/telemetry/TelemetryContext.java @@ -43,7 +43,6 @@ public final class TelemetryContext { private final ConcurrentMap properties; private final ContextTagsMap tags; - private String instrumentationKey; private String connectionString; private ComponentContext component; private DeviceContext device; @@ -127,45 +126,10 @@ public CloudContext getCloud() { return cloud; } - /** - * Gets the default instrumentation key for all {@link - * com.microsoft.applicationinsights.telemetry.Telemetry} objects logged in this {@link - * com.microsoft.applicationinsights.telemetry.TelemetryContext}. - * - *

You can specify it for all telemetry tracked via a particular {@link - * com.microsoft.applicationinsights.TelemetryClient} or for a specific {@link - * com.microsoft.applicationinsights.telemetry.Telemetry} - * - * @return The instrumentation key - * @deprecated Use {@link #setConnectionString(String)} and {@link #getConnectionString()} - * instead. - */ - @Deprecated - public String getInstrumentationKey() { - return instrumentationKey; - } - public String getConnectionString() { return connectionString; } - /** - * Sets the default instrumentation key for all {@link - * com.microsoft.applicationinsights.telemetry.Telemetry} objects logged in this {@link - * com.microsoft.applicationinsights.telemetry.TelemetryContext}. - * - *

You can specify it for all telemetry tracked via a particular {@link - * com.microsoft.applicationinsights.TelemetryClient} or for a specific {@link - * com.microsoft.applicationinsights.telemetry.Telemetry} - * - * @param instrumentationKey The instrumentation key - * @deprecated Use {@link #setConnectionString(String)} instead. - */ - @Deprecated - public void setInstrumentationKey(String instrumentationKey) { - this.instrumentationKey = instrumentationKey; - } - public void setConnectionString(String connectionString) { this.connectionString = connectionString; } From dee467f581d5ebaaa2516b9f17d03d6e7ef8149c Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Mon, 29 Aug 2022 11:32:11 -0700 Subject: [PATCH 09/17] TODO heya --- .../exporter/implementation/models/TelemetryItem.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java index 1fa002649ce..4161314c19b 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java @@ -242,7 +242,7 @@ public TelemetryItem setConnectionString(ConnectionString connectionString) { @JsonIgnore public TelemetryItem setConnectionString(StatsbeatConnectionString connectionString) { instrumentationKey = connectionString.getInstrumentationKey(); - // TODO (trask) turn StatsbeatConnectionString into a real connection string? + // TODO (heya) turn StatsbeatConnectionString into a real connection string? this.connectionString = "InstrumentationKey=" + connectionString.getInstrumentationKey() From a1767c325cf29e75307575934bc8891b5d13b22f Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Mon, 29 Aug 2022 11:41:51 -0700 Subject: [PATCH 10/17] is --- .../agent/internal/exporter/AgentLogExporter.java | 6 +++--- .../agent/internal/sampling/AiOverrideSampler.java | 4 ++-- .../agent/internal/sampling/SamplingOverrides.java | 12 ++++++------ 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/exporter/AgentLogExporter.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/exporter/AgentLogExporter.java index 3c5670249e6..f5dc25fb202 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/exporter/AgentLogExporter.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/exporter/AgentLogExporter.java @@ -113,16 +113,16 @@ public CompletableResultCode export(Collection logs) { SpanContext spanContext = log.getSpanContext(); - boolean standaloneLog = !spanContext.isValid(); + boolean isStandaloneLog = !spanContext.isValid(); Double samplingPercentage = - samplingOverrides.getOverridePercentage(standaloneLog, log.getAttributes()); + samplingOverrides.getOverridePercentage(isStandaloneLog, log.getAttributes()); if (samplingPercentage != null && !shouldSample(spanContext, samplingPercentage)) { continue; } if (samplingPercentage == null - && !standaloneLog + && !isStandaloneLog && !spanContext.getTraceFlags().isSampled()) { // if there is no sampling override, and the log is part of an unsampled trace, then don't // capture it diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/sampling/AiOverrideSampler.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/sampling/AiOverrideSampler.java index bc07b6e1891..d93a9791328 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/sampling/AiOverrideSampler.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/sampling/AiOverrideSampler.java @@ -67,8 +67,8 @@ public SamplingResult shouldSample( SamplingOverrides samplingOverrides = isRequest ? requestSamplingOverrides : dependencySamplingOverrides; - boolean standaloneTelemetry = !isRequest && !parentSpanContext.isValid(); - Sampler override = samplingOverrides.getOverride(standaloneTelemetry, attributes); + boolean isStandaloneTelemetry = !isRequest && !parentSpanContext.isValid(); + Sampler override = samplingOverrides.getOverride(isStandaloneTelemetry, attributes); if (override != null) { return override.shouldSample(parentContext, traceId, name, spanKind, attributes, parentLinks); } diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/sampling/SamplingOverrides.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/sampling/SamplingOverrides.java index 274ab0a5c61..2ce155d3965 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/sampling/SamplingOverrides.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/sampling/SamplingOverrides.java @@ -47,10 +47,10 @@ public SamplingOverrides(List overrides) { } @Nullable - public Sampler getOverride(boolean standaloneTelemetry, Attributes attributes) { + public Sampler getOverride(boolean isStandaloneTelemetry, Attributes attributes) { LazyHttpUrl lazyHttpUrl = new LazyHttpUrl(attributes); for (MatcherGroup matcherGroups : matcherGroups) { - if (matcherGroups.matches(standaloneTelemetry, attributes, lazyHttpUrl)) { + if (matcherGroups.matches(isStandaloneTelemetry, attributes, lazyHttpUrl)) { return matcherGroups.getSampler(); } } @@ -59,9 +59,9 @@ public Sampler getOverride(boolean standaloneTelemetry, Attributes attributes) { // used to do sampling inside the log exporter @Nullable - public Double getOverridePercentage(boolean standaloneTelemetry, Attributes attributes) { + public Double getOverridePercentage(boolean isStandaloneTelemetry, Attributes attributes) { for (MatcherGroup matcherGroups : matcherGroups) { - if (matcherGroups.matches(standaloneTelemetry, attributes, null)) { + if (matcherGroups.matches(isStandaloneTelemetry, attributes, null)) { return matcherGroups.getPercentage(); } } @@ -93,8 +93,8 @@ Sampler getSampler() { } private boolean matches( - boolean standaloneTelemetry, Attributes attributes, @Nullable LazyHttpUrl lazyHttpUrl) { - if (standaloneTelemetry && !this.includeStandaloneTelemetry) { + boolean isStandaloneTelemetry, Attributes attributes, @Nullable LazyHttpUrl lazyHttpUrl) { + if (isStandaloneTelemetry && !this.includeStandaloneTelemetry) { return false; } for (TempPredicate predicate : predicates) { From a7b07a49c279e36157f74f1780f667d30eb8331f Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Mon, 29 Aug 2022 13:33:18 -0700 Subject: [PATCH 11/17] Rename --- ...acyInstrumentation.java => ClassicSdkInstrumentation.java} | 4 ++-- .../agent/internal/init/FirstEntryPoint.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/{LegacyInstrumentation.java => ClassicSdkInstrumentation.java} (98%) diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/LegacyInstrumentation.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/ClassicSdkInstrumentation.java similarity index 98% rename from agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/LegacyInstrumentation.java rename to agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/ClassicSdkInstrumentation.java index f8ae576de8e..5940942eb17 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/LegacyInstrumentation.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/ClassicSdkInstrumentation.java @@ -38,7 +38,7 @@ import io.opentelemetry.javaagent.bootstrap.InstrumentationHolder; import java.lang.instrument.Instrumentation; -class LegacyInstrumentation { +class ClassicSdkInstrumentation { static void registerTransformers() { Instrumentation instrumentation = InstrumentationHolder.getInstrumentation(); @@ -62,5 +62,5 @@ static void registerTransformers() { BytecodeUtil.setDelegate(new BytecodeUtilImpl()); } - private LegacyInstrumentation() {} + private ClassicSdkInstrumentation() {} } diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/FirstEntryPoint.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/FirstEntryPoint.java index 989e0a740ce..4bb3bf38aab 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/FirstEntryPoint.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/FirstEntryPoint.java @@ -107,7 +107,7 @@ public void init() { startupLogger = configureLogging(configuration.selfDiagnostics, agentPath); ConfigurationBuilder.logConfigurationWarnMessages(); - LegacyInstrumentation.registerTransformers(); + ClassicSdkInstrumentation.registerTransformers(); } catch (Exception e) { throw new IllegalStateException(e); } From c68ee8e01801297cd5ad0dce1bb7ee2672490622 Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Mon, 29 Aug 2022 13:35:54 -0700 Subject: [PATCH 12/17] Rename --- .../implementation/LogDataMapper.java | 32 ++++++------ .../implementation/SpanDataMapper.java | 51 +++++++++---------- 2 files changed, 39 insertions(+), 44 deletions(-) diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/LogDataMapper.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/LogDataMapper.java index d1420ac1584..6083d808a35 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/LogDataMapper.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/LogDataMapper.java @@ -158,43 +158,43 @@ private static void setItemCount( static void setExtraAttributes(AbstractTelemetryBuilder telemetryBuilder, Attributes attributes) { attributes.forEach( - (key, value) -> { - String stringKey = key.getKey(); - if (stringKey.startsWith("applicationinsights.internal.")) { + (attributeKey, value) -> { + String key = attributeKey.getKey(); + if (key.startsWith("applicationinsights.internal.")) { return; } - if (stringKey.startsWith(LOG4J2_CONTEXT_DATA_PREFIX)) { + if (key.startsWith(LOG4J2_CONTEXT_DATA_PREFIX)) { telemetryBuilder.addProperty( - stringKey.substring(LOG4J2_CONTEXT_DATA_PREFIX.length()), String.valueOf(value)); + key.substring(LOG4J2_CONTEXT_DATA_PREFIX.length()), String.valueOf(value)); return; } - if (stringKey.startsWith(LOGBACK_MDC_PREFIX)) { + if (key.startsWith(LOGBACK_MDC_PREFIX)) { telemetryBuilder.addProperty( - stringKey.substring(LOGBACK_MDC_PREFIX.length()), String.valueOf(value)); + key.substring(LOGBACK_MDC_PREFIX.length()), String.valueOf(value)); return; } - if (stringKey.startsWith(JBOSS_LOGGING_MDC_PREFIX)) { + if (key.startsWith(JBOSS_LOGGING_MDC_PREFIX)) { telemetryBuilder.addProperty( - stringKey.substring(JBOSS_LOGGING_MDC_PREFIX.length()), String.valueOf(value)); + key.substring(JBOSS_LOGGING_MDC_PREFIX.length()), String.valueOf(value)); return; } - if (stringKey.startsWith(LOG4J1_2_MDC_PREFIX)) { + if (key.startsWith(LOG4J1_2_MDC_PREFIX)) { telemetryBuilder.addProperty( - stringKey.substring(LOG4J1_2_MDC_PREFIX.length()), String.valueOf(value)); + key.substring(LOG4J1_2_MDC_PREFIX.length()), String.valueOf(value)); return; } - if (SpanDataMapper.applyCommonTags(telemetryBuilder, value, stringKey)) { + if (SpanDataMapper.applyCommonTags(telemetryBuilder, key, value)) { return; } - if (stringKey.startsWith("thread.")) { + if (key.startsWith("thread.")) { return; } - if (stringKey.startsWith("exception.")) { + if (key.startsWith("exception.")) { return; } - String val = SpanDataMapper.convertToString(value, key.getType()); + String val = SpanDataMapper.convertToString(value, attributeKey.getType()); if (val != null) { - telemetryBuilder.addProperty(key.getKey(), val); + telemetryBuilder.addProperty(attributeKey.getKey(), val); } }); } diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/SpanDataMapper.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/SpanDataMapper.java index f209db805f7..d1ea682c985 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/SpanDataMapper.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/SpanDataMapper.java @@ -853,78 +853,73 @@ private static void addLinks(AbstractTelemetryBuilder telemetryBuilder, List { - String stringKey = key.getKey(); - if (stringKey.startsWith("applicationinsights.internal.")) { + (attributeKey, value) -> { + String key = attributeKey.getKey(); + if (key.startsWith("applicationinsights.internal.")) { return; } - if (stringKey.equals(AiSemanticAttributes.AZURE_SDK_NAMESPACE.getKey()) - || stringKey.equals(AiSemanticAttributes.AZURE_SDK_MESSAGE_BUS_DESTINATION.getKey()) - || stringKey.equals(AiSemanticAttributes.AZURE_SDK_ENQUEUED_TIME.getKey())) { + if (key.equals(AiSemanticAttributes.AZURE_SDK_NAMESPACE.getKey()) + || key.equals(AiSemanticAttributes.AZURE_SDK_MESSAGE_BUS_DESTINATION.getKey()) + || key.equals(AiSemanticAttributes.AZURE_SDK_ENQUEUED_TIME.getKey())) { // these are from azure SDK (AZURE_SDK_PEER_ADDRESS gets filtered out automatically // since it uses the otel "peer." prefix) return; } - if (stringKey.equals(AiSemanticAttributes.KAFKA_RECORD_QUEUE_TIME_MS.getKey()) - || stringKey.equals(AiSemanticAttributes.KAFKA_OFFSET.getKey())) { + if (key.equals(AiSemanticAttributes.KAFKA_RECORD_QUEUE_TIME_MS.getKey()) + || key.equals(AiSemanticAttributes.KAFKA_OFFSET.getKey())) { return; } - if (stringKey.equals(AiSemanticAttributes.REQUEST_CONTEXT.getKey())) { + if (key.equals(AiSemanticAttributes.REQUEST_CONTEXT.getKey())) { return; } - if (stringKey.equals(SemanticAttributes.HTTP_USER_AGENT.getKey()) - && value instanceof String) { + if (key.equals(SemanticAttributes.HTTP_USER_AGENT.getKey()) && value instanceof String) { telemetryBuilder.addTag("ai.user.userAgent", (String) value); return; } - if (applyCommonTags(telemetryBuilder, value, stringKey)) { + if (applyCommonTags(telemetryBuilder, key, value)) { return; } - if (STANDARD_ATTRIBUTE_PREFIX_TRIE.getOrDefault(stringKey, false) - && !stringKey.startsWith("http.request.header.") - && !stringKey.startsWith("http.response.header.")) { + if (STANDARD_ATTRIBUTE_PREFIX_TRIE.getOrDefault(key, false) + && !key.startsWith("http.request.header.") + && !key.startsWith("http.response.header.")) { return; } - String val = convertToString(value, key.getType()); + String val = convertToString(value, attributeKey.getType()); if (value != null) { - telemetryBuilder.addProperty(key.getKey(), val); + telemetryBuilder.addProperty(attributeKey.getKey(), val); } }); } static boolean applyCommonTags( - AbstractTelemetryBuilder telemetryBuilder, Object value, String stringKey) { + AbstractTelemetryBuilder telemetryBuilder, String key, Object value) { - if (stringKey.equals(SemanticAttributes.ENDUSER_ID.getKey()) && value instanceof String) { + if (key.equals(SemanticAttributes.ENDUSER_ID.getKey()) && value instanceof String) { telemetryBuilder.addTag(ContextTagKeys.AI_USER_ID.toString(), (String) value); return true; } - if (stringKey.equals(AiSemanticAttributes.CONNECTION_STRING.getKey()) - && value instanceof String) { + if (key.equals(AiSemanticAttributes.CONNECTION_STRING.getKey()) && value instanceof String) { // intentionally letting exceptions from parse bubble up telemetryBuilder.setConnectionString( connectionStringCache.computeIfAbsent((String) value, ConnectionString::parse)); return true; } - if (stringKey.equals(AiSemanticAttributes.INSTRUMENTATION_KEY.getKey()) - && value instanceof String) { + if (key.equals(AiSemanticAttributes.INSTRUMENTATION_KEY.getKey()) && value instanceof String) { // intentionally letting exceptions from parse bubble up telemetryBuilder.setConnectionString( connectionStringCache.computeIfAbsent( "InstrumentationKey=" + value, ConnectionString::parse)); return true; } - if (stringKey.equals(AiSemanticAttributes.ROLE_NAME.getKey()) && value instanceof String) { + if (key.equals(AiSemanticAttributes.ROLE_NAME.getKey()) && value instanceof String) { telemetryBuilder.addTag(ContextTagKeys.AI_CLOUD_ROLE.toString(), (String) value); return true; } - if (stringKey.equals(AiSemanticAttributes.ROLE_INSTANCE_ID.getKey()) - && value instanceof String) { + if (key.equals(AiSemanticAttributes.ROLE_INSTANCE_ID.getKey()) && value instanceof String) { telemetryBuilder.addTag(ContextTagKeys.AI_CLOUD_ROLE_INSTANCE.toString(), (String) value); return true; } - if (stringKey.equals(AiSemanticAttributes.APPLICATION_VERSION.getKey()) - && value instanceof String) { + if (key.equals(AiSemanticAttributes.APPLICATION_VERSION.getKey()) && value instanceof String) { telemetryBuilder.addTag(ContextTagKeys.AI_APPLICATION_VER.toString(), (String) value); return true; } From 1f090a84628cf292260a8b6b8d8154ee84a46ebe Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Mon, 29 Aug 2022 13:41:19 -0700 Subject: [PATCH 13/17] Reuse --- .../exporter/implementation/models/TelemetryItem.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java index 4161314c19b..bbe29337895 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java @@ -245,7 +245,7 @@ public TelemetryItem setConnectionString(StatsbeatConnectionString connectionStr // TODO (heya) turn StatsbeatConnectionString into a real connection string? this.connectionString = "InstrumentationKey=" - + connectionString.getInstrumentationKey() + + instrumentationKey + ";IngestionEndpoint=" + connectionString.getIngestionEndpoint(); return this; From 2a1cd1d0775167f4315b50f0fa4dcbb5636e2440 Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Mon, 29 Aug 2022 15:06:53 -0700 Subject: [PATCH 14/17] Review --- .../configuration/ConnectionString.java | 27 ++++--------------- .../localstorage/LocalFileLoader.java | 19 ------------- .../implementation/models/TelemetryItem.java | 2 +- 3 files changed, 6 insertions(+), 42 deletions(-) diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/ConnectionString.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/ConnectionString.java index f7c4dfd3918..6d86edb3622 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/ConnectionString.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/ConnectionString.java @@ -33,19 +33,19 @@ public final class ConnectionString { private final URL liveEndpoint; private final URL profilerEndpoint; - private final String parsedFrom; + private final String originalString; ConnectionString( String instrumentationKey, URL ingestionEndpoint, URL liveEndpoint, URL profilerEndpoint, - String parsedFrom) { + String originalString) { this.instrumentationKey = instrumentationKey; this.ingestionEndpoint = ingestionEndpoint.toExternalForm(); this.liveEndpoint = liveEndpoint; this.profilerEndpoint = profilerEndpoint; - this.parsedFrom = parsedFrom; + this.originalString = originalString; } public static ConnectionString parse(String connectionString) { @@ -69,24 +69,7 @@ public URL getProfilerEndpoint() { return profilerEndpoint; } - public String getParsedFrom() { - return parsedFrom; - } - - @Override - public int hashCode() { - return parsedFrom.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - ConnectionString that = (ConnectionString) obj; - return parsedFrom.equals(that.parsedFrom); + public String getOriginalString() { + return originalString; } } diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoader.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoader.java index 3b7b19c4db1..8b926e46293 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoader.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoader.java @@ -23,7 +23,6 @@ import static com.azure.monitor.opentelemetry.exporter.implementation.utils.AzureMonitorMsgId.DISK_PERSISTENCE_LOADER_ERROR; -import com.azure.monitor.opentelemetry.exporter.implementation.configuration.ConnectionString; import com.azure.monitor.opentelemetry.exporter.implementation.logging.OperationLogger; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.DataInputStream; @@ -128,14 +127,6 @@ PersistedFile loadTelemetriesFromDisk() { } connectionString = dataInputStream.readUTF(); - if (!isConnectionStringKeyValid(connectionString)) { - // probably really old format where content was written directly with no ikey - - // need to close FileInputStream before delete - dataInputStream.close(); - deleteFile(tempFile); - return null; - } int numBytes = dataInputStream.readInt(); telemetryBytes = new byte[numBytes]; @@ -159,16 +150,6 @@ private void deleteFile(File tempFile) { } } - static boolean isConnectionStringKeyValid(String connectionString) { - try { - ConnectionString.parse(connectionString); - return true; - } catch (RuntimeException e) { - logger.debug(e.getMessage(), e); - return false; - } - } - // either delete it permanently on success or add it back to cache to be processed again later on // failure @SuppressFBWarnings( diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java index bbe29337895..081904eb7c1 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/models/TelemetryItem.java @@ -234,7 +234,7 @@ public TelemetryItem setConnectionString(String connectionString) { @JsonIgnore public TelemetryItem setConnectionString(ConnectionString connectionString) { - this.connectionString = connectionString.getParsedFrom(); + this.connectionString = connectionString.getOriginalString(); this.instrumentationKey = connectionString.getInstrumentationKey(); return this; } From e06d0f23b6dd2125c51639728370a06f49d8cde2 Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Mon, 29 Aug 2022 15:14:00 -0700 Subject: [PATCH 15/17] Unused --- .../exporter/implementation/localstorage/LocalFileLoader.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoader.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoader.java index 8b926e46293..e5012d5cee1 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoader.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoader.java @@ -37,8 +37,6 @@ /** This class manages loading a list of {@link ByteBuffer} from the disk. */ class LocalFileLoader { - private static final Logger logger = LoggerFactory.getLogger(LocalFileLoader.class); - private static final String TEMPORARY_FILE_EXTENSION = ".tmp"; private final LocalFileCache localFileCache; From 344d7c79204d5ef655748ccc55a4ef3238b5e027 Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Mon, 29 Aug 2022 15:28:25 -0700 Subject: [PATCH 16/17] Unused --- .../exporter/implementation/localstorage/LocalFileLoader.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoader.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoader.java index e5012d5cee1..16594bf7172 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoader.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/localstorage/LocalFileLoader.java @@ -31,8 +31,6 @@ import java.nio.ByteBuffer; import java.nio.file.Files; import javax.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** This class manages loading a list of {@link ByteBuffer} from the disk. */ class LocalFileLoader { From 56ed47cc52dc5e0180e9d44094a2aa83fd23eafb Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Mon, 29 Aug 2022 21:26:53 -0700 Subject: [PATCH 17/17] Rename --- .../configuration/ConnectionStringBuilder.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/ConnectionStringBuilder.java b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/ConnectionStringBuilder.java index 69e166fd414..aeafa03cbf1 100644 --- a/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/ConnectionStringBuilder.java +++ b/agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/configuration/ConnectionStringBuilder.java @@ -34,7 +34,7 @@ class ConnectionStringBuilder { // visible for testing static final int CONNECTION_STRING_MAX_LENGTH = 4096; - private String parsedFrom; + private String originalString; private String instrumentationKey; @@ -53,14 +53,14 @@ class ConnectionStringBuilder { } ConnectionStringBuilder setConnectionString(String connectionString) { - parsedFrom = connectionString; + originalString = connectionString; mapToConnectionConfiguration(getKeyValuePairs(connectionString)); return this; } ConnectionString build() { return new ConnectionString( - instrumentationKey, ingestionEndpoint, liveEndpoint, profilerEndpoint, parsedFrom); + instrumentationKey, ingestionEndpoint, liveEndpoint, profilerEndpoint, originalString); } private static Map getKeyValuePairs(String connectionString) {