From 1fe7ae633cd35b518da5b39e36743cff404b0e7e Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Fri, 4 Feb 2022 16:19:04 -0800 Subject: [PATCH] Add telemetry field truncation (#26880) --- .../exporter/AzureMonitorTraceExporter.java | 276 ++++++++---------- .../exporter/implementation/Exceptions.java | 114 -------- .../exporter/implementation/UrlParser.java | 126 -------- .../builders/AbstractTelemetryBuilder.java | 75 +++++ .../builders/EventTelemetryBuilder.java | 53 ++++ .../builders/ExceptionDetailBuilder.java | 61 ++++ .../builders/ExceptionTelemetryBuilder.java | 69 +++++ .../implementation/builders/Exceptions.java | 60 ++++ .../builders/MessageTelemetryBuilder.java | 59 ++++ .../builders/MetricPointBuilder.java | 53 ++++ .../builders/MetricTelemetryBuilder.java | 65 +++++ .../builders/PageViewTelemetryBuilder.java | 70 +++++ .../RemoteDependencyTelemetryBuilder.java | 86 ++++++ .../builders/RequestTelemetryBuilder.java | 80 +++++ .../builders/StackFrameBuilder.java | 40 +++ .../builders/StatsbeatTelemetryBuilder.java | 61 ++++ .../builders/TelemetryTruncation.java | 65 +++++ .../{ => utils}/FormattedDuration.java | 8 +- .../{ => utils}/FormattedTime.java | 11 +- .../implementation/utils/UrlParser.java | 127 ++++++++ .../{ => utils}/VersionGenerator.java | 2 +- .../MonitorExporterClientTestBase.java | 2 +- .../implementation/ExceptionsTest.java | 184 ------------ .../implementation/UrlParserPathTest.java | 158 ---------- .../implementation/UrlParserTargetTest.java | 175 ----------- .../implementation/utils/ExceptionsTest.java | 98 +++++++ .../{ => utils}/FormattedDurationTest.java | 2 +- .../utils/UrlParserPathTest.java | 158 ++++++++++ .../utils/UrlParserTargetTest.java | 175 +++++++++++ .../{ => utils}/VersionTest.java | 2 +- 30 files changed, 1596 insertions(+), 919 deletions(-) delete mode 100644 sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/Exceptions.java delete mode 100644 sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/UrlParser.java create mode 100644 sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/AbstractTelemetryBuilder.java create mode 100644 sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/EventTelemetryBuilder.java create mode 100644 sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/ExceptionDetailBuilder.java create mode 100644 sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/ExceptionTelemetryBuilder.java create mode 100644 sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/Exceptions.java create mode 100644 sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/MessageTelemetryBuilder.java create mode 100644 sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/MetricPointBuilder.java create mode 100644 sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/MetricTelemetryBuilder.java create mode 100644 sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/PageViewTelemetryBuilder.java create mode 100644 sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/RemoteDependencyTelemetryBuilder.java create mode 100644 sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/RequestTelemetryBuilder.java create mode 100644 sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/StackFrameBuilder.java create mode 100644 sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/StatsbeatTelemetryBuilder.java create mode 100644 sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/TelemetryTruncation.java rename sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/{ => utils}/FormattedDuration.java (91%) rename sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/{ => utils}/FormattedTime.java (80%) create mode 100644 sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/UrlParser.java rename sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/{ => utils}/VersionGenerator.java (96%) delete mode 100644 sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/ExceptionsTest.java delete mode 100644 sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/UrlParserPathTest.java delete mode 100644 sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/UrlParserTargetTest.java create mode 100644 sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/ExceptionsTest.java rename sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/{ => utils}/FormattedDurationTest.java (94%) create mode 100644 sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/UrlParserPathTest.java create mode 100644 sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/UrlParserTargetTest.java rename sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/{ => utils}/VersionTest.java (91%) diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/AzureMonitorTraceExporter.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/AzureMonitorTraceExporter.java index 23d5f064e69f8..4d3441bbda434 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/AzureMonitorTraceExporter.java +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/AzureMonitorTraceExporter.java @@ -5,19 +5,18 @@ import com.azure.core.util.logging.ClientLogger; import com.azure.core.util.tracing.Tracer; -import com.azure.monitor.opentelemetry.exporter.implementation.Exceptions; -import com.azure.monitor.opentelemetry.exporter.implementation.FormattedDuration; -import com.azure.monitor.opentelemetry.exporter.implementation.FormattedTime; -import com.azure.monitor.opentelemetry.exporter.implementation.UrlParser; -import com.azure.monitor.opentelemetry.exporter.implementation.VersionGenerator; +import com.azure.monitor.opentelemetry.exporter.implementation.builders.AbstractTelemetryBuilder; +import com.azure.monitor.opentelemetry.exporter.implementation.builders.ExceptionTelemetryBuilder; +import com.azure.monitor.opentelemetry.exporter.implementation.builders.Exceptions; +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.models.ContextTagKeys; -import com.azure.monitor.opentelemetry.exporter.implementation.models.MessageData; -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.RemoteDependencyData; -import com.azure.monitor.opentelemetry.exporter.implementation.models.RequestData; -import com.azure.monitor.opentelemetry.exporter.implementation.models.TelemetryExceptionData; import com.azure.monitor.opentelemetry.exporter.implementation.models.TelemetryItem; +import com.azure.monitor.opentelemetry.exporter.implementation.utils.FormattedDuration; +import com.azure.monitor.opentelemetry.exporter.implementation.utils.FormattedTime; +import com.azure.monitor.opentelemetry.exporter.implementation.utils.UrlParser; +import com.azure.monitor.opentelemetry.exporter.implementation.utils.VersionGenerator; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.AttributeType; import io.opentelemetry.api.common.Attributes; @@ -35,10 +34,8 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; import static io.opentelemetry.api.common.AttributeKey.longKey; @@ -134,7 +131,8 @@ public CompletableResultCode export(Collection spans) { } client.export(telemetryItems) .subscriberContext(Context.of(Tracer.DISABLE_TRACING_KEY, true)) - .subscribe(ignored -> { }, error -> completableResultCode.fail(), completableResultCode::succeed); + .subscribe(ignored -> { + }, error -> completableResultCode.fail(), completableResultCode::succeed); return completableResultCode; } catch (Throwable t) { LOGGER.error(t.getMessage(), t); @@ -185,34 +183,32 @@ private void export(SpanData span, List telemetryItems) { private void exportRemoteDependency(SpanData span, boolean inProc, List telemetryItems) { - TelemetryItem telemetry = new TelemetryItem(); - RemoteDependencyData data = new RemoteDependencyData(); - initTelemetry(telemetry, data, "RemoteDependency", "RemoteDependencyData"); - // TODO (trask): can properties be moved up to MonitorDomain and then this can be lazy init in setExtraAttributes - data.setProperties(new HashMap<>()); + RemoteDependencyTelemetryBuilder telemetryBuilder = RemoteDependencyTelemetryBuilder.create(); + initTelemetry(telemetryBuilder); + // sampling is not supported in this exporter yet float samplingPercentage = 100; // set standard properties - setOperationTags(telemetry, span); - setTime(telemetry, span.getStartEpochNanos()); - setExtraAttributes(telemetry, data.getProperties(), span.getAttributes()); - addLinks(data.getProperties(), span.getLinks()); + setOperationTags(telemetryBuilder, span); + setTime(telemetryBuilder, span.getStartEpochNanos()); + setExtraAttributes(telemetryBuilder, span.getAttributes()); + addLinks(telemetryBuilder, span.getLinks()); // set dependency-specific properties - data.setId(span.getSpanId()); - data.setName(getDependencyName(span)); - data.setDuration( + telemetryBuilder.setId(span.getSpanId()); + telemetryBuilder.setName(getDependencyName(span)); + telemetryBuilder.setDuration( FormattedDuration.fromNanos(span.getEndEpochNanos() - span.getStartEpochNanos())); - data.setSuccess(getSuccess(span)); + telemetryBuilder.setSuccess(getSuccess(span)); if (inProc) { - data.setType("InProc"); + telemetryBuilder.setType("InProc"); } else { - applySemanticConventions(span, data); + applySemanticConventions(telemetryBuilder, span); } - telemetryItems.add(telemetry); + telemetryItems.add(telemetryBuilder.build()); exportEvents(span, null, telemetryItems); } @@ -255,35 +251,35 @@ private static String getDependencyName(SpanData span) { return path.isEmpty() ? method + " /" : method + " " + path; } - private static void applySemanticConventions(SpanData span, RemoteDependencyData remoteDependencyData) { + private static void applySemanticConventions(RemoteDependencyTelemetryBuilder telemetryBuilder, SpanData span) { Attributes attributes = span.getAttributes(); String httpMethod = attributes.get(SemanticAttributes.HTTP_METHOD); if (httpMethod != null) { - applyHttpClientSpan(attributes, remoteDependencyData); + applyHttpClientSpan(telemetryBuilder, attributes); return; } String rpcSystem = attributes.get(SemanticAttributes.RPC_SYSTEM); if (rpcSystem != null) { - applyRpcClientSpan(attributes, remoteDependencyData, rpcSystem); + applyRpcClientSpan(telemetryBuilder, rpcSystem, attributes); return; } String dbSystem = attributes.get(SemanticAttributes.DB_SYSTEM); if (dbSystem != null) { - applyDatabaseClientSpan(attributes, remoteDependencyData, dbSystem); + applyDatabaseClientSpan(telemetryBuilder, dbSystem, attributes); return; } String azureNamespace = attributes.get(AZURE_NAMESPACE); if ("Microsoft.EventHub".equals(azureNamespace)) { - applyEventHubsSpan(attributes, remoteDependencyData); + applyEventHubsSpan(telemetryBuilder, attributes); return; } if ("Microsoft.ServiceBus".equals(azureNamespace)) { - applyServiceBusSpan(attributes, remoteDependencyData); + applyServiceBusSpan(telemetryBuilder, attributes); return; } String messagingSystem = attributes.get(SemanticAttributes.MESSAGING_SYSTEM); if (messagingSystem != null) { - applyMessagingClientSpan(attributes, remoteDependencyData, messagingSystem, span.getKind()); + applyMessagingClientSpan(telemetryBuilder, span.getKind(), messagingSystem, attributes); return; } @@ -291,7 +287,7 @@ private static void applySemanticConventions(SpanData span, RemoteDependencyData // so we always want the port included String target = getTargetFromPeerAttributes(attributes, Integer.MAX_VALUE); if (target != null) { - remoteDependencyData.setTarget(target); + telemetryBuilder.setTarget(target); return; } @@ -301,50 +297,50 @@ private static void applySemanticConventions(SpanData span, RemoteDependencyData // // so we mark these as InProc, even though they aren't INTERNAL spans, // in order to prevent App Map from considering them - remoteDependencyData.setType("InProc"); + telemetryBuilder.setType("InProc"); } - private static void setOperationTags(TelemetryItem telemetry, SpanData span) { - setOperationId(telemetry, span.getTraceId()); - setOperationParentId(telemetry, span.getParentSpanContext().getSpanId()); - setOperationName(telemetry, span.getAttributes()); + private static void setOperationTags(AbstractTelemetryBuilder telemetryBuilder, SpanData span) { + setOperationId(telemetryBuilder, span.getTraceId()); + setOperationParentId(telemetryBuilder, span.getParentSpanContext().getSpanId()); + setOperationName(telemetryBuilder, span.getAttributes()); } - private static void setOperationId(TelemetryItem telemetry, String traceId) { - telemetry.getTags().put(ContextTagKeys.AI_OPERATION_ID.toString(), traceId); + private static void setOperationId(AbstractTelemetryBuilder telemetryBuilder, String traceId) { + telemetryBuilder.addTag(ContextTagKeys.AI_OPERATION_ID.toString(), traceId); } - private static void setOperationParentId(TelemetryItem telemetry, String parentSpanId) { + private static void setOperationParentId(AbstractTelemetryBuilder telemetryBuilder, String parentSpanId) { if (SpanId.isValid(parentSpanId)) { - telemetry.getTags().put(ContextTagKeys.AI_OPERATION_PARENT_ID.toString(), parentSpanId); + telemetryBuilder.addTag(ContextTagKeys.AI_OPERATION_PARENT_ID.toString(), parentSpanId); } } - private static void setOperationName(TelemetryItem telemetry, Attributes attributes) { + private static void setOperationName(AbstractTelemetryBuilder telemetryBuilder, Attributes attributes) { String operationName = attributes.get(AI_OPERATION_NAME_KEY); if (operationName != null) { - setOperationName(telemetry, operationName); + setOperationName(telemetryBuilder, operationName); } } - private static void setOperationName(TelemetryItem telemetry, String operationName) { - telemetry.getTags().put(ContextTagKeys.AI_OPERATION_NAME.toString(), operationName); + private static void setOperationName(AbstractTelemetryBuilder telemetryBuilder, String operationName) { + telemetryBuilder.addTag(ContextTagKeys.AI_OPERATION_NAME.toString(), operationName); } - private static void applyHttpClientSpan(Attributes attributes, RemoteDependencyData telemetry) { + private static void applyHttpClientSpan(RemoteDependencyTelemetryBuilder telemetryBuilder, Attributes attributes) { String target = getTargetForHttpClientSpan(attributes); - telemetry.setType("Http"); - telemetry.setTarget(target); + telemetryBuilder.setType("Http"); + telemetryBuilder.setTarget(target); Long httpStatusCode = attributes.get(SemanticAttributes.HTTP_STATUS_CODE); if (httpStatusCode != null) { - telemetry.setResultCode(Long.toString(httpStatusCode)); + telemetryBuilder.setResultCode(Long.toString(httpStatusCode)); } String url = attributes.get(SemanticAttributes.HTTP_URL); - telemetry.setData(url); + telemetryBuilder.setData(url); } private static String getTargetForHttpClientSpan(Attributes attributes) { @@ -434,19 +430,17 @@ private static String getHostFromNetAttributes(Attributes attributes) { return attributes.get(SemanticAttributes.NET_PEER_IP); } - private static void applyRpcClientSpan(Attributes attributes, RemoteDependencyData telemetry, - String rpcSystem) { - telemetry.setType(rpcSystem); + private static void applyRpcClientSpan(RemoteDependencyTelemetryBuilder telemetryBuilder, String rpcSystem, Attributes attributes) { + telemetryBuilder.setType(rpcSystem); String target = getTargetFromPeerAttributes(attributes, 0); // not appending /rpc.service for now since that seems too fine-grained if (target == null) { target = rpcSystem; } - telemetry.setTarget(target); + telemetryBuilder.setTarget(target); } - private static void applyDatabaseClientSpan(Attributes attributes, RemoteDependencyData telemetry, - String dbSystem) { + private static void applyDatabaseClientSpan(RemoteDependencyTelemetryBuilder telemetryBuilder, String dbSystem, Attributes attributes) { String dbStatement = attributes.get(SemanticAttributes.DB_STATEMENT); String type; if (SQL_DB_SYSTEMS.contains(dbSystem)) { @@ -460,8 +454,8 @@ private static void applyDatabaseClientSpan(Attributes attributes, RemoteDepende } else { type = dbSystem; } - telemetry.setType(type); - telemetry.setData(dbStatement); + telemetryBuilder.setType(type); + telemetryBuilder.setData(dbStatement); String target = nullAwareConcat( getTargetFromPeerAttributes(attributes, getDefaultPortForDbSystem(dbSystem)), @@ -470,36 +464,36 @@ private static void applyDatabaseClientSpan(Attributes attributes, RemoteDepende if (target == null) { target = dbSystem; } - telemetry.setTarget(target); + telemetryBuilder.setTarget(target); } - private static void applyMessagingClientSpan(Attributes attributes, RemoteDependencyData telemetry, - String messagingSystem, SpanKind spanKind) { + private static void applyMessagingClientSpan(RemoteDependencyTelemetryBuilder telemetryBuilder, SpanKind spanKind, + String messagingSystem, Attributes attributes) { if (spanKind == SpanKind.PRODUCER) { - telemetry.setType("Queue Message | " + messagingSystem); + telemetryBuilder.setType("Queue Message | " + messagingSystem); } else { // e.g. CONSUMER kind (without remote parent) and CLIENT kind - telemetry.setType(messagingSystem); + telemetryBuilder.setType(messagingSystem); } String destination = attributes.get(SemanticAttributes.MESSAGING_DESTINATION); if (destination != null) { - telemetry.setTarget(destination); + telemetryBuilder.setTarget(destination); } else { - telemetry.setTarget(messagingSystem); + telemetryBuilder.setTarget(messagingSystem); } } // special case needed until Azure SDK moves to OTel semantic conventions - private static void applyEventHubsSpan(Attributes attributes, RemoteDependencyData telemetry) { - telemetry.setType("Microsoft.EventHub"); - telemetry.setTarget(getAzureSdkTargetSource(attributes)); + private static void applyEventHubsSpan(RemoteDependencyTelemetryBuilder telemetryBuilder, Attributes attributes) { + telemetryBuilder.setType("Microsoft.EventHub"); + telemetryBuilder.setTarget(getAzureSdkTargetSource(attributes)); } // special case needed until Azure SDK moves to OTel semantic conventions - private static void applyServiceBusSpan(Attributes attributes, RemoteDependencyData telemetry) { + private static void applyServiceBusSpan(RemoteDependencyTelemetryBuilder telemetryBuilder, Attributes attributes) { // TODO(trask) change this to Microsoft.ServiceBus once that is supported in U/X E2E view - telemetry.setType("AZURE SERVICE BUS"); - telemetry.setTarget(getAzureSdkTargetSource(attributes)); + telemetryBuilder.setType("AZURE SERVICE BUS"); + telemetryBuilder.setTarget(getAzureSdkTargetSource(attributes)); } private static String getAzureSdkTargetSource(Attributes attributes) { @@ -540,11 +534,8 @@ private static int getDefaultPortForDbSystem(String dbSystem) { } private void exportRequest(SpanData span, List telemetryItems) { - TelemetryItem telemetry = new TelemetryItem(); - RequestData data = new RequestData(); - initTelemetry(telemetry, data, "Request", "RequestData"); - // TODO (trask): can properties be moved up to MonitorDomain and then this can be lazy init in setExtraAttributes - data.setProperties(new HashMap<>()); + RequestTelemetryBuilder telemetryBuilder = RequestTelemetryBuilder.create(); + initTelemetry(telemetryBuilder); Attributes attributes = span.getAttributes(); long startEpochNanos = span.getStartEpochNanos(); @@ -552,29 +543,28 @@ private void exportRequest(SpanData span, List telemetryItems) { float samplingPercentage = 100; // set standard properties - data.setId(span.getSpanId()); - setTime(telemetry, startEpochNanos); - setExtraAttributes(telemetry, data.getProperties(), attributes); - addLinks(data.getProperties(), span.getLinks()); + telemetryBuilder.setId(span.getSpanId()); + setTime(telemetryBuilder, startEpochNanos); + setExtraAttributes(telemetryBuilder, attributes); + addLinks(telemetryBuilder, span.getLinks()); String operationName = getOperationName(span); - telemetry.getTags().put(ContextTagKeys.AI_OPERATION_NAME.toString(), operationName); - telemetry.getTags().put(ContextTagKeys.AI_OPERATION_ID.toString(), span.getTraceId()); + telemetryBuilder.addTag(ContextTagKeys.AI_OPERATION_NAME.toString(), operationName); + telemetryBuilder.addTag(ContextTagKeys.AI_OPERATION_ID.toString(), span.getTraceId()); - telemetry - .getTags() - .put( + telemetryBuilder + .addTag( ContextTagKeys.AI_OPERATION_PARENT_ID.toString(), span.getParentSpanContext().getSpanId()); // set request-specific properties - data.setName(operationName); - data.setDuration(FormattedDuration.fromNanos(span.getEndEpochNanos() - startEpochNanos)); - data.setSuccess(getSuccess(span)); + telemetryBuilder.setName(operationName); + telemetryBuilder.setDuration(FormattedDuration.fromNanos(span.getEndEpochNanos() - startEpochNanos)); + telemetryBuilder.setSuccess(getSuccess(span)); String httpUrl = getHttpUrlFromServerSpan(attributes); if (httpUrl != null) { - data.setUrl(httpUrl); + telemetryBuilder.setUrl(httpUrl); } Long httpStatusCode = attributes.get(SemanticAttributes.HTTP_STATUS_CODE); @@ -582,9 +572,9 @@ private void exportRequest(SpanData span, List telemetryItems) { httpStatusCode = attributes.get(SemanticAttributes.RPC_GRPC_STATUS_CODE); } if (httpStatusCode != null) { - data.setResponseCode(Long.toString(httpStatusCode)); + telemetryBuilder.setResponseCode(Long.toString(httpStatusCode)); } else { - data.setResponseCode("0"); + telemetryBuilder.setResponseCode("0"); } String locationIp = attributes.get(SemanticAttributes.HTTP_CLIENT_IP); @@ -593,10 +583,10 @@ private void exportRequest(SpanData span, List telemetryItems) { locationIp = attributes.get(SemanticAttributes.NET_PEER_IP); } if (locationIp != null) { - telemetry.getTags().put(ContextTagKeys.AI_LOCATION_IP.toString(), locationIp); + telemetryBuilder.addTag(ContextTagKeys.AI_LOCATION_IP.toString(), locationIp); } - data.setSource(getSource(attributes)); + telemetryBuilder.setSource(getSource(attributes)); // TODO (trask): for batch consumer, enqueuedTime should be the average of this attribute // across all links @@ -605,20 +595,14 @@ private void exportRequest(SpanData span, List telemetryItems) { long timeSinceEnqueuedMillis = Math.max( 0L, NANOSECONDS.toMillis(span.getStartEpochNanos()) - SECONDS.toMillis(enqueuedTime)); - if (data.getMeasurements() == null) { - data.setMeasurements(new HashMap<>()); - } - data.getMeasurements().put("timeSinceEnqueued", (double) timeSinceEnqueuedMillis); + telemetryBuilder.addMeasurement("timeSinceEnqueued", (double) timeSinceEnqueuedMillis); } Long timeSinceEnqueuedMillis = attributes.get(KAFKA_RECORD_QUEUE_TIME_MS); if (timeSinceEnqueuedMillis != null) { - if (data.getMeasurements() == null) { - data.setMeasurements(new HashMap<>()); - } - data.getMeasurements().put("timeSinceEnqueued", (double) timeSinceEnqueuedMillis); + telemetryBuilder.addMeasurement("timeSinceEnqueued", (double) timeSinceEnqueuedMillis); } - telemetryItems.add(telemetry); + telemetryItems.add(telemetryBuilder.build()); exportEvents(span, operationName, telemetryItems); } @@ -719,75 +703,59 @@ private void exportEvents(SpanData span, @Nullable String operationName, List()); + MessageTelemetryBuilder telemetryBuilder = MessageTelemetryBuilder.create(); + initTelemetry(telemetryBuilder); // set standard properties - setOperationId(telemetry, span.getTraceId()); - setOperationParentId(telemetry, span.getSpanId()); + setOperationId(telemetryBuilder, span.getTraceId()); + setOperationParentId(telemetryBuilder, span.getSpanId()); if (operationName != null) { - setOperationName(telemetry, operationName); + setOperationName(telemetryBuilder, operationName); } else { - setOperationName(telemetry, span.getAttributes()); + setOperationName(telemetryBuilder, span.getAttributes()); } - setTime(telemetry, event.getEpochNanos()); - setExtraAttributes(telemetry, data.getProperties(), event.getAttributes()); + setTime(telemetryBuilder, event.getEpochNanos()); + setExtraAttributes(telemetryBuilder, event.getAttributes()); // set message-specific properties - data.setMessage(event.getName()); + telemetryBuilder.setMessage(event.getName()); - telemetryItems.add(telemetry); + telemetryItems.add(telemetryBuilder.build()); } } private void trackException(String errorStack, SpanData span, @Nullable String operationName, List telemetryItems) { - TelemetryItem telemetry = new TelemetryItem(); - TelemetryExceptionData data = new TelemetryExceptionData(); - initTelemetry(telemetry, data, "Exception", "ExceptionData"); - // TODO (trask): can properties be moved up to MonitorDomain and then this can be lazy init in setExtraAttributes - data.setProperties(new HashMap<>()); + ExceptionTelemetryBuilder telemetryBuilder = ExceptionTelemetryBuilder.create(); + initTelemetry(telemetryBuilder); // set standard properties - setOperationId(telemetry, span.getTraceId()); - setOperationParentId(telemetry, span.getSpanId()); + setOperationId(telemetryBuilder, span.getTraceId()); + setOperationParentId(telemetryBuilder, span.getSpanId()); if (operationName != null) { - setOperationName(telemetry, operationName); + setOperationName(telemetryBuilder, operationName); } else { - setOperationName(telemetry, span.getAttributes()); + setOperationName(telemetryBuilder, span.getAttributes()); } - setTime(telemetry, span.getEndEpochNanos()); + setTime(telemetryBuilder, span.getEndEpochNanos()); // set exception-specific properties - data.setExceptions(Exceptions.minimalParse(errorStack)); + telemetryBuilder.setExceptions(Exceptions.minimalParse(errorStack)); - telemetryItems.add(telemetry); + telemetryItems.add(telemetryBuilder.build()); } - private void initTelemetry(TelemetryItem telemetry, MonitorDomain data, String telemetryName, - String baseType) { - telemetry.setVersion(1); - telemetry.setName(telemetryName); - telemetry.setInstrumentationKey(instrumentationKey); - telemetry.setTags(new HashMap<>()); + private void initTelemetry(AbstractTelemetryBuilder telemetryBuilder) { + telemetryBuilder.setInstrumentationKey(instrumentationKey); // Set AI Internal SDK Version - telemetry.getTags().put(ContextTagKeys.AI_INTERNAL_SDK_VERSION.toString(), VersionGenerator.getSdkVersion()); - data.setVersion(2); - - MonitorBase monitorBase = new MonitorBase(); - telemetry.setData(monitorBase); - monitorBase.setBaseType(baseType); - monitorBase.setBaseData(data); + telemetryBuilder.addTag(ContextTagKeys.AI_INTERNAL_SDK_VERSION.toString(), VersionGenerator.getSdkVersion()); } - private static void setTime(TelemetryItem telemetry, long epochNanos) { - telemetry.setTime(FormattedTime.offSetDateTimeFromEpochNanos(epochNanos)); + private static void setTime(AbstractTelemetryBuilder telemetryBuilder, long epochNanos) { + telemetryBuilder.setTime(FormattedTime.offSetDateTimeFromEpochNanos(epochNanos)); } - private static void addLinks(Map properties, List links) { + private static void addLinks(AbstractTelemetryBuilder telemetryBuilder, List links) { if (links.isEmpty()) { return; } @@ -806,10 +774,10 @@ private static void addLinks(Map properties, List link first = false; } sb.append("]"); - properties.put("_MS.links", sb.toString()); + telemetryBuilder.addProperty("_MS.links", sb.toString()); } - private static void setExtraAttributes(TelemetryItem telemetry, Map properties, + private static void setExtraAttributes(AbstractTelemetryBuilder telemetryBuilder, Attributes attributes) { attributes.forEach((key, value) -> { String stringKey = key.getKey(); @@ -826,12 +794,12 @@ private static void setExtraAttributes(TelemetryItem telemetry, Map minimalParse(String str) { - TelemetryExceptionDetails details = new TelemetryExceptionDetails(); - int separator = -1; - int length = str.length(); - int current; - for (current = 0; current < length; current++) { - char c = str.charAt(current); - if (c == ':') { - separator = current; - } else if (c == '\r' || c == '\n') { - break; - } - } - // at the end of the loop, current will be end of the first line - if (separator != -1) { - String typeName = str.substring(0, separator); - String message = str.substring(separator + 1, current).trim(); - if (message.isEmpty()) { - message = typeName; - } - details.setTypeName(typeName); - details.setMessage(message); - } else { - String typeName = str.substring(0, current); - details.setTypeName(typeName); - details.setMessage(typeName); - } - details.setStack(str); - return singletonList(details); - } - - // THIS IS UNFINISHED WORK - // NOT SURE IF IT'S NEEDED - // TESTING WITH minimalParse() first - public static List fullParse(String str) { - Parser parser = new Parser(); - for (String line : str.split("\r?\n")) { - parser.process(line); - } - return parser.getDetails(); - } - - private Exceptions() {} - - static class Parser { - - private TelemetryExceptionDetails current; - private final List list = new ArrayList<>(); - - void process(String line) { - if (line.charAt(0) != '\t') { - if (current != null) { - list.add(current); - } - if (line.startsWith("Caused by: ")) { - line = line.substring("Caused by: ".length()); - } - current = new TelemetryExceptionDetails(); - int index = line.indexOf(':'); - if (index != -1) { - String typeName = line.substring(0, index); - String message = line.substring(index + 1).trim(); - if (message.isEmpty()) { - message = typeName; - } - current.setTypeName(typeName); - current.setMessage(message); - } else { - current.setTypeName(line); - current.setMessage(line); - } - } - } - - public List getDetails() { - if (current != null) { - list.add(current); - } - return list; - } - } -} diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/UrlParser.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/UrlParser.java deleted file mode 100644 index c743c589d121b..0000000000000 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/UrlParser.java +++ /dev/null @@ -1,126 +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.azure.monitor.opentelemetry.exporter.implementation; - -import reactor.util.annotation.Nullable; - -public class UrlParser { - - /** - * Returns the "target" (host:port) portion of the url. - * - *

Returns {@code null} if the target cannot be extracted from url for any reason. - */ - @Nullable - public static String getTargetFromUrl(String url) { - - int schemeEndIndex = url.indexOf(':'); - if (schemeEndIndex == -1) { - // not a valid url - return null; - } - - int len = url.length(); - if (schemeEndIndex + 2 < len - && url.charAt(schemeEndIndex + 1) == '/' - && url.charAt(schemeEndIndex + 2) == '/') { - // has authority component - // look for - // '/' - start of path - // '?' or end of string - empty path - int index; - for (index = schemeEndIndex + 3; index < len; index++) { - char c = url.charAt(index); - if (c == '/' || c == '?' || c == '#') { - break; - } - } - String target = url.substring(schemeEndIndex + 3, index); - return target.isEmpty() ? null : target; - } else { - // has no authority - return null; - } - } - - /** - * Returns the path portion of the url. - * - *

Returns {@code null} if the path cannot be extracted from url for any reason. - */ - @Nullable - public static String getPathFromUrl(String url) { - - int schemeEndIndex = url.indexOf(':'); - if (schemeEndIndex == -1) { - // not a valid url - return null; - } - - int len = url.length(); - if (schemeEndIndex + 2 < len - && url.charAt(schemeEndIndex + 1) == '/' - && url.charAt(schemeEndIndex + 2) == '/') { - // has authority component - // look for - // '/' - start of path - // '?' or end of string - empty path - int pathStartIndex = -1; - for (int i = schemeEndIndex + 3; i < len; i++) { - char c = url.charAt(i); - if (c == '/') { - pathStartIndex = i; - break; - } else if (c == '?' || c == '#') { - // empty path - return ""; - } - } - if (pathStartIndex == -1) { - // end of the url was reached while scanning for the beginning of the path - // which means the path is empty - return ""; - } - int pathEndIndex = getPathEndIndex(url, pathStartIndex + 1); - return url.substring(pathStartIndex, pathEndIndex); - } else { - // has no authority, path starts right away - int pathStartIndex = schemeEndIndex + 1; - int pathEndIndex = getPathEndIndex(url, pathStartIndex); - return url.substring(pathStartIndex, pathEndIndex); - } - } - - // returns the ending index of the path component (exclusive) - private static int getPathEndIndex(String url, int startIndex) { - int len = url.length(); - for (int i = startIndex; i < len; i++) { - char c = url.charAt(i); - if (c == '?' || c == '#') { - return i; - } - } - return len; - } - - private UrlParser() {} -} diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/AbstractTelemetryBuilder.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/AbstractTelemetryBuilder.java new file mode 100644 index 0000000000000..6814e315d0c37 --- /dev/null +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/AbstractTelemetryBuilder.java @@ -0,0 +1,75 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.monitor.opentelemetry.exporter.implementation.builders; + +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; + +import java.time.OffsetDateTime; +import java.util.HashMap; +import java.util.Map; + +public abstract class AbstractTelemetryBuilder { + + private static final int MAX_PROPERTY_KEY_LENGTH = 150; + private static final int MAX_PROPERTY_VALUE_LENGTH = 8192; + + protected static final int MAX_MEASUREMENT_KEY_LENGTH = 150; + + protected static final int MAX_NAME_LENGTH = 1024; + protected static final int MAX_ID_LENGTH = 512; + + private final TelemetryItem telemetryItem; + + protected AbstractTelemetryBuilder(MonitorDomain data, String telemetryName, String baseType) { + + telemetryItem = new TelemetryItem(); + telemetryItem.setVersion(1); + telemetryItem.setName(telemetryName); + + data.setVersion(2); + + MonitorBase monitorBase = new MonitorBase(); + telemetryItem.setData(monitorBase); + monitorBase.setBaseType(baseType); + monitorBase.setBaseData(data); + } + + public void setTime(OffsetDateTime time) { + telemetryItem.setTime(time); + } + + public void setSampleRate(float sampleRate) { + telemetryItem.setSampleRate(sampleRate); + } + + public void setInstrumentationKey(String instrumentationKey) { + telemetryItem.setInstrumentationKey(instrumentationKey); + } + + public void addTag(String key, String value) { + Map tags = telemetryItem.getTags(); + if (tags == null) { + tags = new HashMap<>(); + telemetryItem.setTags(tags); + } + tags.put(key, value); + } + + public void addProperty(String key, String value) { + if (key == null || key.isEmpty() || key.length() > MAX_PROPERTY_KEY_LENGTH || value == null) { + // TODO (trask) log + return; + } + getProperties().put(key, TelemetryTruncation.truncatePropertyValue(value, MAX_PROPERTY_VALUE_LENGTH, key)); + } + + public TelemetryItem build() { + return telemetryItem; + } + + protected abstract Map getProperties(); +} diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/EventTelemetryBuilder.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/EventTelemetryBuilder.java new file mode 100644 index 0000000000000..91d3715b20489 --- /dev/null +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/EventTelemetryBuilder.java @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.monitor.opentelemetry.exporter.implementation.builders; + +import com.azure.monitor.opentelemetry.exporter.implementation.models.TelemetryEventData; + +import java.util.HashMap; +import java.util.Map; + +public final class EventTelemetryBuilder extends AbstractTelemetryBuilder { + + private static final int MAX_EVENT_NAME_LENGTH = 512; + + private final TelemetryEventData data; + + public static EventTelemetryBuilder create() { + return new EventTelemetryBuilder(new TelemetryEventData()); + } + + private EventTelemetryBuilder(TelemetryEventData data) { + super(data, "Event", "EventData"); + this.data = data; + } + + public void setName(String name) { + data.setName(TelemetryTruncation.truncateTelemetry(name, MAX_EVENT_NAME_LENGTH, "Event.name")); + } + + public void addMeasurement(String key, Double value) { + if (key == null || key.isEmpty() || key.length() > MAX_MEASUREMENT_KEY_LENGTH) { + // TODO (trask) log + return; + } + Map measurements = data.getMeasurements(); + if (measurements == null) { + measurements = new HashMap<>(); + data.setMeasurements(measurements); + } + measurements.put(key, value); + } + + @Override + protected Map getProperties() { + Map properties = data.getProperties(); + if (properties == null) { + properties = new HashMap<>(); + data.setProperties(properties); + } + return properties; + } +} diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/ExceptionDetailBuilder.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/ExceptionDetailBuilder.java new file mode 100644 index 0000000000000..d3db605d7ac1b --- /dev/null +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/ExceptionDetailBuilder.java @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.monitor.opentelemetry.exporter.implementation.builders; + +import com.azure.monitor.opentelemetry.exporter.implementation.models.StackFrame; +import com.azure.monitor.opentelemetry.exporter.implementation.models.TelemetryExceptionDetails; + +import java.util.ArrayList; +import java.util.List; + +public final class ExceptionDetailBuilder { + + private static final int MAX_NAME_LENGTH = 1024; + private static final int MAX_MESSAGE_LENGTH = 32768; + + private final TelemetryExceptionDetails data = new TelemetryExceptionDetails(); + + public void setId(Integer id) { + data.setId(id); + } + + public void setOuter(ExceptionDetailBuilder outer) { + data.setOuterId(outer.data.getId()); + } + + public void setTypeName(String typeName) { + data.setTypeName( + TelemetryTruncation.truncateTelemetry( + typeName, MAX_NAME_LENGTH, "ExceptionDetail.typeName")); + } + + public void setMessage(String message) { + data.setMessage( + TelemetryTruncation.truncateTelemetry( + message, MAX_MESSAGE_LENGTH, "ExceptionDetail.message")); + } + + public void setHasFullStack(Boolean hasFullStack) { + data.setHasFullStack(hasFullStack); + } + + public void setStack(String stack) { + data.setStack( + TelemetryTruncation.truncateTelemetry(stack, MAX_MESSAGE_LENGTH, "ExceptionDetail.stack")); + } + + public void setParsedStack(List builders) { + List stackFrames = new ArrayList<>(); + for (StackFrameBuilder builder : builders) { + stackFrames.add(builder.build()); + } + data.setParsedStack(stackFrames); + } + + // visible (beyond package protected) for testing + public TelemetryExceptionDetails build() { + return data; + } +} diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/ExceptionTelemetryBuilder.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/ExceptionTelemetryBuilder.java new file mode 100644 index 0000000000000..a768a3a6ef662 --- /dev/null +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/ExceptionTelemetryBuilder.java @@ -0,0 +1,69 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.monitor.opentelemetry.exporter.implementation.builders; + +import com.azure.monitor.opentelemetry.exporter.implementation.models.SeverityLevel; +import com.azure.monitor.opentelemetry.exporter.implementation.models.TelemetryExceptionData; +import com.azure.monitor.opentelemetry.exporter.implementation.models.TelemetryExceptionDetails; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public final class ExceptionTelemetryBuilder extends AbstractTelemetryBuilder { + + private static final int MAX_PROBLEM_ID_LENGTH = 1024; + + private final TelemetryExceptionData data; + + public static ExceptionTelemetryBuilder create() { + return new ExceptionTelemetryBuilder(new TelemetryExceptionData()); + } + + private ExceptionTelemetryBuilder(TelemetryExceptionData data) { + super(data, "Exception", "ExceptionData"); + this.data = data; + } + + public void setExceptions(List builders) { + List details = new ArrayList<>(); + for (ExceptionDetailBuilder builder : builders) { + details.add(builder.build()); + } + data.setExceptions(details); + } + + public void setSeverityLevel(SeverityLevel severityLevel) { + data.setSeverityLevel(severityLevel); + } + + public void setProblemId(String problemId) { + data.setProblemId(TelemetryTruncation.truncateTelemetry(problemId, MAX_PROBLEM_ID_LENGTH, "Exception.problemId")); + } + + public void addMeasurement(String key, Double value) { + if (key == null || key.isEmpty() || key.length() > MAX_MEASUREMENT_KEY_LENGTH) { + // TODO (trask) log + return; + } + Map measurements = data.getMeasurements(); + if (measurements == null) { + measurements = new HashMap<>(); + data.setMeasurements(measurements); + } + measurements.put(key, value); + } + + @Override + protected Map getProperties() { + Map properties = data.getProperties(); + if (properties == null) { + properties = new HashMap<>(); + data.setProperties(properties); + } + return properties; + } +} diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/Exceptions.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/Exceptions.java new file mode 100644 index 0000000000000..3a5293c5cb856 --- /dev/null +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/Exceptions.java @@ -0,0 +1,60 @@ +/* + * 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.builders; + +import java.util.List; + +import static java.util.Collections.singletonList; + +public class Exceptions { + + public static List minimalParse(String str) { + ExceptionDetailBuilder builder = new ExceptionDetailBuilder(); + int separator = -1; + int length = str.length(); + int current; + for (current = 0; current < length; current++) { + char c = str.charAt(current); + if (c == ':') { + separator = current; + } else if (c == '\r' || c == '\n') { + break; + } + } + // at the end of the loop, current will be end of the first line + if (separator != -1) { + String typeName = str.substring(0, separator); + String message = str.substring(separator + 1, current).trim(); + if (message.isEmpty()) { + message = typeName; + } + builder.setTypeName(typeName); + builder.setMessage(message); + } else { + String typeName = str.substring(0, current); + builder.setTypeName(typeName); + builder.setMessage(typeName); + } + builder.setStack(str); + return singletonList(builder); + } +} diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/MessageTelemetryBuilder.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/MessageTelemetryBuilder.java new file mode 100644 index 0000000000000..a4de508573787 --- /dev/null +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/MessageTelemetryBuilder.java @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.monitor.opentelemetry.exporter.implementation.builders; + +import com.azure.monitor.opentelemetry.exporter.implementation.models.MessageData; +import com.azure.monitor.opentelemetry.exporter.implementation.models.SeverityLevel; + +import java.util.HashMap; +import java.util.Map; + +public final class MessageTelemetryBuilder extends AbstractTelemetryBuilder { + + private static final int MAX_MESSAGE_LENGTH = 32768; + + private final MessageData data; + + public static MessageTelemetryBuilder create() { + return new MessageTelemetryBuilder(new MessageData()); + } + + private MessageTelemetryBuilder(MessageData data) { + super(data, "Message", "MessageData"); + this.data = data; + } + + public void setMessage(String message) { + data.setMessage( + TelemetryTruncation.truncateTelemetry(message, MAX_MESSAGE_LENGTH, "Message.message")); + } + + public void setSeverityLevel(SeverityLevel severityLevel) { + data.setSeverityLevel(severityLevel); + } + + public void addMeasurement(String key, Double value) { + if (key == null || key.isEmpty() || key.length() > MAX_MEASUREMENT_KEY_LENGTH) { + // TODO (trask) log + return; + } + Map measurements = data.getMeasurements(); + if (measurements == null) { + measurements = new HashMap<>(); + data.setMeasurements(measurements); + } + measurements.put(key, value); + } + + @Override + protected Map getProperties() { + Map properties = data.getProperties(); + if (properties == null) { + properties = new HashMap<>(); + data.setProperties(properties); + } + return properties; + } +} diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/MetricPointBuilder.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/MetricPointBuilder.java new file mode 100644 index 0000000000000..f3a3efb6ea105 --- /dev/null +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/MetricPointBuilder.java @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.monitor.opentelemetry.exporter.implementation.builders; + +import com.azure.monitor.opentelemetry.exporter.implementation.models.DataPointType; +import com.azure.monitor.opentelemetry.exporter.implementation.models.MetricDataPoint; + +public final class MetricPointBuilder { + + private static final int MAX_METRIC_NAME_SPACE_LENGTH = 256; + private static final int MAX_NAME_LENGTH = 1024; + + private final MetricDataPoint data = new MetricDataPoint(); + + public void setNamespace(String namespace) { + data.setNamespace( + TelemetryTruncation.truncateTelemetry(namespace, MAX_METRIC_NAME_SPACE_LENGTH, "MetricPoint.namespace")); + } + + public void setName(String name) { + data.setName(TelemetryTruncation.truncateTelemetry(name, MAX_NAME_LENGTH, "MetricPoint.name")); + } + + public void setDataPointType(DataPointType dataPointType) { + data.setDataPointType(dataPointType); + } + + public void setValue(double value) { + data.setValue(value); + } + + public void setCount(Integer count) { + data.setCount(count); + } + + public void setMin(Double min) { + data.setMin(min); + } + + public void setMax(Double max) { + data.setMax(max); + } + + public void setStdDev(Double stdDev) { + data.setStdDev(stdDev); + } + + MetricDataPoint build() { + return data; + } +} diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/MetricTelemetryBuilder.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/MetricTelemetryBuilder.java new file mode 100644 index 0000000000000..12ee3e95a51df --- /dev/null +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/MetricTelemetryBuilder.java @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.monitor.opentelemetry.exporter.implementation.builders; + +import com.azure.monitor.opentelemetry.exporter.implementation.models.DataPointType; +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.utils.FormattedTime; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public final class MetricTelemetryBuilder extends AbstractTelemetryBuilder { + + private final MetricsData data; + + public static MetricTelemetryBuilder create() { + return new MetricTelemetryBuilder(new MetricsData()); + } + + public static MetricTelemetryBuilder create(String name, double value) { + MetricTelemetryBuilder telemetryBuilder = new MetricTelemetryBuilder(new MetricsData()); + + MetricPointBuilder point = new MetricPointBuilder(); + + point.setName(name); + point.setValue(value); + point.setDataPointType(DataPointType.MEASUREMENT); + telemetryBuilder.setMetricPoint(point); + + telemetryBuilder.setTime(FormattedTime.offSetDateTimeFromNow()); + + return telemetryBuilder; + } + + private MetricTelemetryBuilder(MetricsData data) { + super(data, "Metric", "MetricData"); + this.data = data; + } + + public void setMetricPoint(MetricPointBuilder point) { + List metrics = data.getMetrics(); + if (metrics == null) { + metrics = new ArrayList<>(); + data.setMetrics(metrics); + } + if (metrics.isEmpty()) { + metrics.add(point.build()); + } + } + + @Override + protected Map getProperties() { + Map properties = data.getProperties(); + if (properties == null) { + properties = new HashMap<>(); + data.setProperties(properties); + } + return properties; + } +} diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/PageViewTelemetryBuilder.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/PageViewTelemetryBuilder.java new file mode 100644 index 0000000000000..79e18eeaeeb09 --- /dev/null +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/PageViewTelemetryBuilder.java @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.monitor.opentelemetry.exporter.implementation.builders; + +import com.azure.monitor.opentelemetry.exporter.implementation.models.PageViewData; + +import java.util.HashMap; +import java.util.Map; + +public final class PageViewTelemetryBuilder extends AbstractTelemetryBuilder { + + private static final int MAX_URL_LENGTH = 2048; + + private final PageViewData data; + + public static PageViewTelemetryBuilder create() { + return new PageViewTelemetryBuilder(new PageViewData()); + } + + private PageViewTelemetryBuilder(PageViewData data) { + super(data, "PageView", "PageViewData"); + this.data = data; + } + + public void setId(String id) { + data.setId(TelemetryTruncation.truncateTelemetry(id, MAX_ID_LENGTH, "PageView.id")); + } + + public void setName(String name) { + data.setName(TelemetryTruncation.truncateTelemetry(name, MAX_NAME_LENGTH, "PageView.name")); + } + + public void setUrl(String url) { + data.setUrl(TelemetryTruncation.truncateTelemetry(url, MAX_URL_LENGTH, "PageView.url")); + } + + public void setDuration(String duration) { + data.setDuration(duration); + } + + public void setReferredUri(String referredUri) { + data.setReferredUri( + TelemetryTruncation.truncateTelemetry(referredUri, MAX_URL_LENGTH, "PageView.referredUri")); + } + + public void addMeasurement(String key, Double value) { + if (key == null || key.isEmpty() || key.length() > MAX_MEASUREMENT_KEY_LENGTH) { + // TODO (trask) log + return; + } + Map measurements = data.getMeasurements(); + if (measurements == null) { + measurements = new HashMap<>(); + data.setMeasurements(measurements); + } + measurements.put(key, value); + } + + @Override + protected Map getProperties() { + Map properties = data.getProperties(); + if (properties == null) { + properties = new HashMap<>(); + data.setProperties(properties); + } + return properties; + } +} diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/RemoteDependencyTelemetryBuilder.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/RemoteDependencyTelemetryBuilder.java new file mode 100644 index 0000000000000..559731b2ba6b6 --- /dev/null +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/RemoteDependencyTelemetryBuilder.java @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.monitor.opentelemetry.exporter.implementation.builders; + +import com.azure.monitor.opentelemetry.exporter.implementation.models.RemoteDependencyData; + +import java.util.HashMap; +import java.util.Map; + +public final class RemoteDependencyTelemetryBuilder extends AbstractTelemetryBuilder { + + private static final int MAX_DATA_LENGTH = 8192; + private static final int MAX_RESULT_CODE_LENGTH = 1024; + private static final int MAX_DEPENDENCY_TYPE_LENGTH = 1024; + private static final int MAX_TARGET_NAME_LENGTH = 1024; + + private final RemoteDependencyData data; + + public static RemoteDependencyTelemetryBuilder create() { + return new RemoteDependencyTelemetryBuilder(new RemoteDependencyData()); + } + + private RemoteDependencyTelemetryBuilder(RemoteDependencyData data) { + super(data, "RemoteDependency", "RemoteDependencyData"); + this.data = data; + } + + public void setId(String id) { + data.setId(TelemetryTruncation.truncateTelemetry(id, MAX_ID_LENGTH, "RemoteDependency.id")); + } + + public void setName(String name) { + data.setName( + TelemetryTruncation.truncateTelemetry(name, MAX_NAME_LENGTH, "RemoteDependency.name")); + } + + public void setResultCode(String resultCode) { + data.setResultCode( + TelemetryTruncation.truncateTelemetry(resultCode, MAX_RESULT_CODE_LENGTH, "RemoteDependency.resultCode")); + } + + public void setData(String data) { + this.data.setData(TelemetryTruncation.truncateTelemetry(data, MAX_DATA_LENGTH, "RemoteDependency.data")); + } + + public void setType(String type) { + data.setType(TelemetryTruncation.truncateTelemetry(type, MAX_DEPENDENCY_TYPE_LENGTH, "RemoteDependency.type")); + } + + public void setTarget(String target) { + data.setTarget(TelemetryTruncation.truncateTelemetry(target, MAX_TARGET_NAME_LENGTH, "RemoteDependency.target")); + } + + public void setDuration(String duration) { + data.setDuration(duration); + } + + public void setSuccess(Boolean success) { + data.setSuccess(success); + } + + public void addMeasurement(String key, Double value) { + if (key == null || key.isEmpty() || key.length() > MAX_MEASUREMENT_KEY_LENGTH) { + // TODO (trask) log + return; + } + Map measurements = data.getMeasurements(); + if (measurements == null) { + measurements = new HashMap<>(); + data.setMeasurements(measurements); + } + measurements.put(key, value); + } + + @Override + protected Map getProperties() { + Map properties = data.getProperties(); + if (properties == null) { + properties = new HashMap<>(); + data.setProperties(properties); + } + return properties; + } +} diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/RequestTelemetryBuilder.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/RequestTelemetryBuilder.java new file mode 100644 index 0000000000000..e6ef0d5dfe942 --- /dev/null +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/RequestTelemetryBuilder.java @@ -0,0 +1,80 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.monitor.opentelemetry.exporter.implementation.builders; + +import com.azure.monitor.opentelemetry.exporter.implementation.models.RequestData; + +import java.util.HashMap; +import java.util.Map; + +public final class RequestTelemetryBuilder extends AbstractTelemetryBuilder { + + private static final int MAX_SOURCE_LENGTH = 1024; + private static final int MAX_RESPONSE_CODE_LENGTH = 1024; + private static final int MAX_URL_LENGTH = 2048; + + private final RequestData data; + + public static RequestTelemetryBuilder create() { + return new RequestTelemetryBuilder(new RequestData()); + } + + private RequestTelemetryBuilder(RequestData data) { + super(data, "Request", "RequestData"); + this.data = data; + } + + public void setId(String id) { + data.setId(TelemetryTruncation.truncateTelemetry(id, MAX_ID_LENGTH, "Request.id")); + } + + public void setName(String name) { + data.setName(TelemetryTruncation.truncateTelemetry(name, MAX_NAME_LENGTH, "Request.name")); + } + + public void setDuration(String duration) { + data.setDuration(duration); + } + + public void setSuccess(boolean success) { + data.setSuccess(success); + } + + public void setResponseCode(String responseCode) { + data.setResponseCode( + TelemetryTruncation.truncateTelemetry(responseCode, MAX_RESPONSE_CODE_LENGTH, "Request.responseCode")); + } + + public void setSource(String source) { + data.setSource(TelemetryTruncation.truncateTelemetry(source, MAX_SOURCE_LENGTH, "Request.source")); + } + + public void setUrl(String url) { + data.setUrl(TelemetryTruncation.truncateTelemetry(url, MAX_URL_LENGTH, "Request.url")); + } + + public void addMeasurement(String key, Double value) { + if (key == null || key.isEmpty() || key.length() > MAX_MEASUREMENT_KEY_LENGTH) { + // TODO (trask) log + return; + } + Map measurements = data.getMeasurements(); + if (measurements == null) { + measurements = new HashMap<>(); + data.setMeasurements(measurements); + } + measurements.put(key, value); + } + + @Override + protected Map getProperties() { + Map properties = data.getProperties(); + if (properties == null) { + properties = new HashMap<>(); + data.setProperties(properties); + } + return properties; + } +} diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/StackFrameBuilder.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/StackFrameBuilder.java new file mode 100644 index 0000000000000..b601405099d38 --- /dev/null +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/StackFrameBuilder.java @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.monitor.opentelemetry.exporter.implementation.builders; + +import com.azure.monitor.opentelemetry.exporter.implementation.models.StackFrame; + +public final class StackFrameBuilder { + + private static final int MAX_FILE_NAME_LENGTH = 1024; + private static final int MAX_METHOD_NAME_LENGTH = 1024; + private static final int MAX_ASSEMBLY_NAME_LENGTH = 1024; + + private final StackFrame data = new StackFrame(); + + public void setLevel(int level) { + data.setLevel(level); + } + + public void setMethod(String method) { + data.setMethod(TelemetryTruncation.truncateTelemetry(method, MAX_METHOD_NAME_LENGTH, "StackFrame.method")); + } + + public void setAssembly(String assembly) { + data.setAssembly(TelemetryTruncation.truncateTelemetry(assembly, MAX_ASSEMBLY_NAME_LENGTH, "StackFrame.assembly")); + } + + public void setFileName(String fileName) { + data.setFileName(TelemetryTruncation.truncateTelemetry(fileName, MAX_FILE_NAME_LENGTH, "StackFrame.fileName")); + } + + public void setLine(Integer line) { + data.setLine(line); + } + + StackFrame build() { + return data; + } +} diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/StatsbeatTelemetryBuilder.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/StatsbeatTelemetryBuilder.java new file mode 100644 index 0000000000000..1b8ae9c1e0433 --- /dev/null +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/StatsbeatTelemetryBuilder.java @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.monitor.opentelemetry.exporter.implementation.builders; + +import com.azure.monitor.opentelemetry.exporter.implementation.models.DataPointType; +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.utils.FormattedTime; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public final class StatsbeatTelemetryBuilder extends AbstractTelemetryBuilder { + + private final MetricsData data; + + public static StatsbeatTelemetryBuilder create(String name, double value) { + StatsbeatTelemetryBuilder telemetryBuilder = new StatsbeatTelemetryBuilder(new MetricsData()); + + MetricDataPoint point = new MetricDataPoint(); + point.setName(name); + point.setValue(value); + point.setDataPointType(DataPointType.MEASUREMENT); + telemetryBuilder.setMetricDataPoint(point); + + telemetryBuilder.setTime(FormattedTime.offSetDateTimeFromNow()); + + return telemetryBuilder; + } + + private StatsbeatTelemetryBuilder(MetricsData data) { + // not using the default telemetry name for metrics (which is "Metric") + super(data, "Statsbeat", "MetricData"); + this.data = data; + } + + public void setMetricDataPoint(MetricDataPoint point) { + List metrics = data.getMetrics(); + if (metrics == null) { + metrics = new ArrayList<>(); + data.setMetrics(metrics); + } + if (metrics.isEmpty()) { + metrics.add(point); + } + } + + @Override + protected Map getProperties() { + Map properties = data.getProperties(); + if (properties == null) { + properties = new HashMap<>(); + data.setProperties(properties); + } + return properties; + } +} diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/TelemetryTruncation.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/TelemetryTruncation.java new file mode 100644 index 0000000000000..79dd9d17c8baf --- /dev/null +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/builders/TelemetryTruncation.java @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.monitor.opentelemetry.exporter.implementation.builders; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +final class TelemetryTruncation { + + private static final Logger logger = LoggerFactory.getLogger(TelemetryTruncation.class); + + private static final Set alreadyLoggedAttributeNames = ConcurrentHashMap.newKeySet(); + private static final Set alreadyLoggedPropertyKeys = ConcurrentHashMap.newKeySet(); + + static String truncateTelemetry(String value, int maxLength, String attributeName) { + if (value == null || value.length() <= maxLength) { + return value; + } + if (alreadyLoggedAttributeNames.add(attributeName)) { + // this can be expected, so don't want to flood the logs with a lot of these + // (and don't want to log the full value, e.g. sql text > 8192 characters) + logger.warn( + "truncated {} attribute value to {} characters (this message will only be logged once" + + " per attribute name): {}", + attributeName, + maxLength, + trimTo80(value)); + } + logger.debug( + "truncated {} attribute value to {} characters: {}", attributeName, maxLength, value); + return value.substring(0, maxLength); + } + + static String truncatePropertyValue(String value, int maxLength, String propertyKey) { + if (value == null || value.length() <= maxLength) { + return value; + } + if (alreadyLoggedPropertyKeys.size() < 10 && alreadyLoggedPropertyKeys.add(propertyKey)) { + // this can be expected, so don't want to flood the logs with a lot of these + logger.warn( + "truncated {} property value to {} characters (this message will only be logged once" + + " per property key, and only for at most 10 different property keys): {}", + propertyKey, + maxLength, + trimTo80(value)); + } + logger.debug("truncated {} property value to {} characters: {}", propertyKey, maxLength, value); + return value.substring(0, maxLength); + } + + private static String trimTo80(String value) { + if (value.length() <= 80) { + return value; + } + return value.substring(0, 80) + "..."; + } + + private TelemetryTruncation() { + } +} diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/FormattedDuration.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/FormattedDuration.java similarity index 91% rename from sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/FormattedDuration.java rename to sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/FormattedDuration.java index a1f38240415fa..6ccc0deb930c9 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/FormattedDuration.java +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/FormattedDuration.java @@ -19,9 +19,13 @@ * DEALINGS IN THE SOFTWARE. */ -package com.azure.monitor.opentelemetry.exporter.implementation; +package com.azure.monitor.opentelemetry.exporter.implementation.utils; -import static java.util.concurrent.TimeUnit.*; +import static java.util.concurrent.TimeUnit.DAYS; +import static java.util.concurrent.TimeUnit.HOURS; +import static java.util.concurrent.TimeUnit.MINUTES; +import static java.util.concurrent.TimeUnit.NANOSECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; public final class FormattedDuration { diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/FormattedTime.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/FormattedTime.java similarity index 80% rename from sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/FormattedTime.java rename to sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/FormattedTime.java index 4617e03e475db..3ed9a272cf192 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/FormattedTime.java +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/FormattedTime.java @@ -19,21 +19,28 @@ * DEALINGS IN THE SOFTWARE. */ -package com.azure.monitor.opentelemetry.exporter.implementation; +package com.azure.monitor.opentelemetry.exporter.implementation.utils; import java.time.Instant; import java.time.OffsetDateTime; import java.time.ZoneOffset; -import java.util.Date; import static java.util.concurrent.TimeUnit.NANOSECONDS; public final class FormattedTime { + public static OffsetDateTime offSetDateTimeFromNow() { + return offSetDateTimeFromEpochMillis(System.currentTimeMillis()); + } + public static OffsetDateTime offSetDateTimeFromEpochNanos(long epochNanos) { return Instant.ofEpochMilli(NANOSECONDS.toMillis(epochNanos)).atOffset(ZoneOffset.UTC); } + public static OffsetDateTime offSetDateTimeFromEpochMillis(long epochMillis) { + return Instant.ofEpochMilli(epochMillis).atOffset(ZoneOffset.UTC); + } + private FormattedTime() { } } diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/UrlParser.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/UrlParser.java new file mode 100644 index 0000000000000..33571d8a2ce38 --- /dev/null +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/UrlParser.java @@ -0,0 +1,127 @@ +/* + * 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.utils; + +import reactor.util.annotation.Nullable; + +public class UrlParser { + + /** + * Returns the "target" (host:port) portion of the url. + * + *

Returns {@code null} if the target cannot be extracted from url for any reason. + */ + @Nullable + public static String getTargetFromUrl(String url) { + + int schemeEndIndex = url.indexOf(':'); + if (schemeEndIndex == -1) { + // not a valid url + return null; + } + + int len = url.length(); + if (schemeEndIndex + 2 < len + && url.charAt(schemeEndIndex + 1) == '/' + && url.charAt(schemeEndIndex + 2) == '/') { + // has authority component + // look for + // '/' - start of path + // '?' or end of string - empty path + int index; + for (index = schemeEndIndex + 3; index < len; index++) { + char c = url.charAt(index); + if (c == '/' || c == '?' || c == '#') { + break; + } + } + String target = url.substring(schemeEndIndex + 3, index); + return target.isEmpty() ? null : target; + } else { + // has no authority + return null; + } + } + + /** + * Returns the path portion of the url. + * + *

Returns {@code null} if the path cannot be extracted from url for any reason. + */ + @Nullable + public static String getPathFromUrl(String url) { + + int schemeEndIndex = url.indexOf(':'); + if (schemeEndIndex == -1) { + // not a valid url + return null; + } + + int len = url.length(); + if (schemeEndIndex + 2 < len + && url.charAt(schemeEndIndex + 1) == '/' + && url.charAt(schemeEndIndex + 2) == '/') { + // has authority component + // look for + // '/' - start of path + // '?' or end of string - empty path + int pathStartIndex = -1; + for (int i = schemeEndIndex + 3; i < len; i++) { + char c = url.charAt(i); + if (c == '/') { + pathStartIndex = i; + break; + } else if (c == '?' || c == '#') { + // empty path + return ""; + } + } + if (pathStartIndex == -1) { + // end of the url was reached while scanning for the beginning of the path + // which means the path is empty + return ""; + } + int pathEndIndex = getPathEndIndex(url, pathStartIndex + 1); + return url.substring(pathStartIndex, pathEndIndex); + } else { + // has no authority, path starts right away + int pathStartIndex = schemeEndIndex + 1; + int pathEndIndex = getPathEndIndex(url, pathStartIndex); + return url.substring(pathStartIndex, pathEndIndex); + } + } + + // returns the ending index of the path component (exclusive) + private static int getPathEndIndex(String url, int startIndex) { + int len = url.length(); + for (int i = startIndex; i < len; i++) { + char c = url.charAt(i); + if (c == '?' || c == '#') { + return i; + } + } + return len; + } + + private UrlParser() { + } +} diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/VersionGenerator.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/VersionGenerator.java similarity index 96% rename from sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/VersionGenerator.java rename to sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/VersionGenerator.java index 022d7ded05691..65519e0dd809d 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/VersionGenerator.java +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/VersionGenerator.java @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.monitor.opentelemetry.exporter.implementation; +package com.azure.monitor.opentelemetry.exporter.implementation.utils; import com.azure.core.util.CoreUtils; import java.util.Map; diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/MonitorExporterClientTestBase.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/MonitorExporterClientTestBase.java index 38a8c0fa9c4ec..0d47abda3d447 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/MonitorExporterClientTestBase.java +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/MonitorExporterClientTestBase.java @@ -13,7 +13,7 @@ import com.azure.monitor.opentelemetry.exporter.implementation.models.MonitorDomain; import com.azure.monitor.opentelemetry.exporter.implementation.models.RequestData; import com.azure.monitor.opentelemetry.exporter.implementation.models.TelemetryItem; -import com.azure.monitor.opentelemetry.exporter.implementation.FormattedDuration; +import com.azure.monitor.opentelemetry.exporter.implementation.utils.FormattedDuration; import java.time.Duration; import java.time.OffsetDateTime; diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/ExceptionsTest.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/ExceptionsTest.java deleted file mode 100644 index c38c8ec5c14ea..0000000000000 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/ExceptionsTest.java +++ /dev/null @@ -1,184 +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.azure.monitor.opentelemetry.exporter.implementation; - -import com.azure.monitor.opentelemetry.exporter.implementation.models.TelemetryExceptionDetails; -import org.junit.jupiter.api.Test; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -public class ExceptionsTest { - - @Test - public void testMinimalParse() { - // given - String str = toString(new IllegalStateException("test")); - - // when - List list = Exceptions.minimalParse(str); - - // then - assertThat(list.size()).isEqualTo(1); - - TelemetryExceptionDetails details = list.get(0); - assertThat(details.getTypeName()).isEqualTo(IllegalStateException.class.getName()); - assertThat(details.getMessage()).isEqualTo("test"); - } - - @Test - public void testMinimalParseWithNoMessage() { - // given - String str = toString(new IllegalStateException()); - - // when - List list = Exceptions.minimalParse(str); - - // then - assertThat(list.size()).isEqualTo(1); - - TelemetryExceptionDetails details = list.get(0); - assertThat(details.getTypeName()).isEqualTo(IllegalStateException.class.getName()); - assertThat(details.getMessage()).isEqualTo(IllegalStateException.class.getName()); - } - - @Test - public void testMinimalParseWithProblematicMessage() { - // given - String str = toString(new ProblematicException()); - - // when - List list = Exceptions.minimalParse(str); - - // then - assertThat(list.size()).isEqualTo(1); - - TelemetryExceptionDetails details = list.get(0); - assertThat(details.getTypeName()).isEqualTo(ProblematicException.class.getName()); - assertThat(details.getMessage()).isEqualTo(ProblematicException.class.getName()); - } - - @Test - public void testFullParse() { - // given - String str = toString(new IllegalStateException("test")); - - // when - List list = Exceptions.fullParse(str); - - // then - assertThat(list.size()).isEqualTo(1); - - TelemetryExceptionDetails details = list.get(0); - assertThat(details.getTypeName()).isEqualTo(IllegalStateException.class.getName()); - assertThat(details.getMessage()).isEqualTo("test"); - } - - @Test - public void testFullParseWithNoMessage() { - // given - String str = toString(new IllegalStateException()); - - // when - List list = Exceptions.fullParse(str); - - // then - assertThat(list.size()).isEqualTo(1); - - TelemetryExceptionDetails details = list.get(0); - assertThat(details.getTypeName()).isEqualTo(IllegalStateException.class.getName()); - assertThat(details.getMessage()).isEqualTo(IllegalStateException.class.getName()); - } - - @Test - public void testFullParseWithProblematicMessage() { - // given - String str = toString(new ProblematicException()); - - // when - List list = Exceptions.fullParse(str); - - // then - assertThat(list.size()).isEqualTo(1); - - TelemetryExceptionDetails details = list.get(0); - assertThat(details.getTypeName()).isEqualTo(ProblematicException.class.getName()); - assertThat(details.getMessage()).isEqualTo(ProblematicException.class.getName()); - } - - @Test - public void testWithCausedBy() { - // given - RuntimeException causedBy = new RuntimeException("the cause"); - String str = toString(new IllegalStateException("test", causedBy)); - - // when - List list = Exceptions.fullParse(str); - - // then - assertThat(list.size()).isEqualTo(2); - - TelemetryExceptionDetails details = list.get(0); - assertThat(details.getTypeName()).isEqualTo(IllegalStateException.class.getName()); - assertThat(details.getMessage()).isEqualTo("test"); - - TelemetryExceptionDetails causedByDetails = list.get(1); - assertThat(causedByDetails.getTypeName()).isEqualTo(RuntimeException.class.getName()); - assertThat(causedByDetails.getMessage()).isEqualTo("the cause"); - } - - @Test - public void shouldIgnoreSuppressed() { - // given - RuntimeException suppressed = new RuntimeException("the suppressed"); - IllegalStateException exception = new IllegalStateException("test"); - exception.addSuppressed(suppressed); - String str = toString(exception); - - // when - List list = Exceptions.fullParse(str); - - // then - assertThat(list.size()).isEqualTo(1); - - TelemetryExceptionDetails details = list.get(0); - assertThat(details.getTypeName()).isEqualTo(IllegalStateException.class.getName()); - assertThat(details.getMessage()).isEqualTo("test"); - } - - private static String toString(Throwable t) { - StringWriter out = new StringWriter(); - t.printStackTrace(new PrintWriter(out)); - return out.toString(); - } - - @SuppressWarnings("OverrideThrowableToString") - private static class ProblematicException extends Exception { - @Override - public String toString() { - return ProblematicException.class.getName() + ":"; - } - } -} diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/UrlParserPathTest.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/UrlParserPathTest.java deleted file mode 100644 index 023f2bf520807..0000000000000 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/UrlParserPathTest.java +++ /dev/null @@ -1,158 +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.azure.monitor.opentelemetry.exporter.implementation; - -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -public class UrlParserPathTest { - - @Test - public void testGetPathFromUrl() { - assertThat(UrlParser.getPathFromUrl("https://localhost")).isEqualTo(""); - assertThat(UrlParser.getPathFromUrl("https://localhost/")).isEqualTo("/"); - assertThat(UrlParser.getPathFromUrl("https://localhost/path")).isEqualTo("/path"); - assertThat(UrlParser.getPathFromUrl("https://localhost/path/")).isEqualTo("/path/"); - assertThat(UrlParser.getPathFromUrl("https://localhost/more/path")).isEqualTo("/more/path"); - assertThat(UrlParser.getPathFromUrl("https://localhost/more/path/")).isEqualTo("/more/path/"); - - assertThat(UrlParser.getPathFromUrl("https://localhost?")).isEqualTo(""); - assertThat(UrlParser.getPathFromUrl("https://localhost/?")).isEqualTo("/"); - assertThat(UrlParser.getPathFromUrl("https://localhost/path?")).isEqualTo("/path"); - assertThat(UrlParser.getPathFromUrl("https://localhost/path/?")).isEqualTo("/path/"); - assertThat(UrlParser.getPathFromUrl("https://localhost/more/path?")).isEqualTo("/more/path"); - assertThat(UrlParser.getPathFromUrl("https://localhost/more/path/?")).isEqualTo("/more/path/"); - - assertThat(UrlParser.getPathFromUrl("https://localhost?query")).isEqualTo(""); - assertThat(UrlParser.getPathFromUrl("https://localhost/?query")).isEqualTo("/"); - assertThat(UrlParser.getPathFromUrl("https://localhost/path?query")).isEqualTo("/path"); - assertThat(UrlParser.getPathFromUrl("https://localhost/path/?query")).isEqualTo("/path/"); - assertThat(UrlParser.getPathFromUrl("https://localhost/more/path?query")) - .isEqualTo("/more/path"); - assertThat(UrlParser.getPathFromUrl("https://localhost/more/path/?query")) - .isEqualTo("/more/path/"); - - assertThat(UrlParser.getPathFromUrl("https://localhost#")).isEqualTo(""); - assertThat(UrlParser.getPathFromUrl("https://localhost/#")).isEqualTo("/"); - assertThat(UrlParser.getPathFromUrl("https://localhost/path#")).isEqualTo("/path"); - assertThat(UrlParser.getPathFromUrl("https://localhost/path/#")).isEqualTo("/path/"); - assertThat(UrlParser.getPathFromUrl("https://localhost/more/path#")).isEqualTo("/more/path"); - assertThat(UrlParser.getPathFromUrl("https://localhost/more/path/#")).isEqualTo("/more/path/"); - - assertThat(UrlParser.getPathFromUrl("https://localhost#fragment")).isEqualTo(""); - assertThat(UrlParser.getPathFromUrl("https://localhost/#fragment")).isEqualTo("/"); - assertThat(UrlParser.getPathFromUrl("https://localhost/path#fragment")).isEqualTo("/path"); - assertThat(UrlParser.getPathFromUrl("https://localhost/path/#fragment")).isEqualTo("/path/"); - assertThat(UrlParser.getPathFromUrl("https://localhost/more/path#fragment")) - .isEqualTo("/more/path"); - assertThat(UrlParser.getPathFromUrl("https://localhost/more/path/#fragment")) - .isEqualTo("/more/path/"); - } - - @Test - public void testGetPathFromUrlWithPort() { - assertThat(UrlParser.getPathFromUrl("https://localhost:8080")).isEqualTo(""); - assertThat(UrlParser.getPathFromUrl("https://localhost:8080/")).isEqualTo("/"); - assertThat(UrlParser.getPathFromUrl("https://localhost:8080/path")).isEqualTo("/path"); - assertThat(UrlParser.getPathFromUrl("https://localhost:8080/path/")).isEqualTo("/path/"); - assertThat(UrlParser.getPathFromUrl("https://localhost:8080/more/path")) - .isEqualTo("/more/path"); - assertThat(UrlParser.getPathFromUrl("https://localhost:8080/more/path/")) - .isEqualTo("/more/path/"); - - assertThat(UrlParser.getPathFromUrl("https://localhost:8080?")).isEqualTo(""); - assertThat(UrlParser.getPathFromUrl("https://localhost:8080/?")).isEqualTo("/"); - assertThat(UrlParser.getPathFromUrl("https://localhost:8080/path?")).isEqualTo("/path"); - assertThat(UrlParser.getPathFromUrl("https://localhost:8080/path/?")).isEqualTo("/path/"); - assertThat(UrlParser.getPathFromUrl("https://localhost:8080/more/path?")) - .isEqualTo("/more/path"); - assertThat(UrlParser.getPathFromUrl("https://localhost:8080/more/path/?")) - .isEqualTo("/more/path/"); - - assertThat(UrlParser.getPathFromUrl("https://localhost:8080?query")).isEqualTo(""); - assertThat(UrlParser.getPathFromUrl("https://localhost:8080/?query")).isEqualTo("/"); - assertThat(UrlParser.getPathFromUrl("https://localhost:8080/path?query")).isEqualTo("/path"); - assertThat(UrlParser.getPathFromUrl("https://localhost:8080/path/?query")).isEqualTo("/path/"); - assertThat(UrlParser.getPathFromUrl("https://localhost:8080/more/path?query")) - .isEqualTo("/more/path"); - assertThat(UrlParser.getPathFromUrl("https://localhost:8080/more/path/?query")) - .isEqualTo("/more/path/"); - - assertThat(UrlParser.getPathFromUrl("https://localhost:8080#")).isEqualTo(""); - assertThat(UrlParser.getPathFromUrl("https://localhost:8080/#")).isEqualTo("/"); - assertThat(UrlParser.getPathFromUrl("https://localhost:8080/path#")).isEqualTo("/path"); - assertThat(UrlParser.getPathFromUrl("https://localhost:8080/path/#")).isEqualTo("/path/"); - assertThat(UrlParser.getPathFromUrl("https://localhost:8080/more/path#")) - .isEqualTo("/more/path"); - assertThat(UrlParser.getPathFromUrl("https://localhost:8080/more/path/#")) - .isEqualTo("/more/path/"); - - assertThat(UrlParser.getPathFromUrl("https://localhost:8080#fragment")).isEqualTo(""); - assertThat(UrlParser.getPathFromUrl("https://localhost:8080/#fragment")).isEqualTo("/"); - assertThat(UrlParser.getPathFromUrl("https://localhost:8080/path#fragment")).isEqualTo("/path"); - assertThat(UrlParser.getPathFromUrl("https://localhost:8080/path/#fragment")) - .isEqualTo("/path/"); - assertThat(UrlParser.getPathFromUrl("https://localhost:8080/more/path#fragment")) - .isEqualTo("/more/path"); - assertThat(UrlParser.getPathFromUrl("https://localhost:8080/more/path/#fragment")) - .isEqualTo("/more/path/"); - } - - @Test - public void testGetPathFromUrlWithNoAuthority() { - assertThat(UrlParser.getPathFromUrl("https:")).isEqualTo(""); - assertThat(UrlParser.getPathFromUrl("https:/")).isEqualTo("/"); - assertThat(UrlParser.getPathFromUrl("https:/path")).isEqualTo("/path"); - assertThat(UrlParser.getPathFromUrl("https:/path/")).isEqualTo("/path/"); - assertThat(UrlParser.getPathFromUrl("https:/more/path")).isEqualTo("/more/path"); - assertThat(UrlParser.getPathFromUrl("https:/more/path/")).isEqualTo("/more/path/"); - - assertThat(UrlParser.getPathFromUrl("https:?")).isEqualTo(""); - assertThat(UrlParser.getPathFromUrl("https:/?")).isEqualTo("/"); - assertThat(UrlParser.getPathFromUrl("https:/path?")).isEqualTo("/path"); - assertThat(UrlParser.getPathFromUrl("https:/path/?")).isEqualTo("/path/"); - assertThat(UrlParser.getPathFromUrl("https:/more/path?")).isEqualTo("/more/path"); - assertThat(UrlParser.getPathFromUrl("https:/more/path/?")).isEqualTo("/more/path/"); - - assertThat(UrlParser.getPathFromUrl("https:?query")).isEqualTo(""); - assertThat(UrlParser.getPathFromUrl("https:/?query")).isEqualTo("/"); - assertThat(UrlParser.getPathFromUrl("https:/path?query")).isEqualTo("/path"); - assertThat(UrlParser.getPathFromUrl("https:/path/?query")).isEqualTo("/path/"); - assertThat(UrlParser.getPathFromUrl("https:/more/path?query")).isEqualTo("/more/path"); - assertThat(UrlParser.getPathFromUrl("https:/more/path/?query")).isEqualTo("/more/path/"); - - assertThat(UrlParser.getPathFromUrl("https:#")).isEqualTo(""); - assertThat(UrlParser.getPathFromUrl("https:/#")).isEqualTo("/"); - assertThat(UrlParser.getPathFromUrl("https:/path#")).isEqualTo("/path"); - assertThat(UrlParser.getPathFromUrl("https:/path/#")).isEqualTo("/path/"); - assertThat(UrlParser.getPathFromUrl("https:/more/path#")).isEqualTo("/more/path"); - assertThat(UrlParser.getPathFromUrl("https:/more/path/#")).isEqualTo("/more/path/"); - - assertThat(UrlParser.getPathFromUrl("https:#fragment")).isEqualTo(""); - assertThat(UrlParser.getPathFromUrl("https:/#fragment")).isEqualTo("/"); - assertThat(UrlParser.getPathFromUrl("https:/path#fragment")).isEqualTo("/path"); - assertThat(UrlParser.getPathFromUrl("https:/path/#fragment")).isEqualTo("/path/"); - assertThat(UrlParser.getPathFromUrl("https:/more/path#fragment")).isEqualTo("/more/path"); - assertThat(UrlParser.getPathFromUrl("https:/more/path/#fragment")).isEqualTo("/more/path/"); - } -} diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/UrlParserTargetTest.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/UrlParserTargetTest.java deleted file mode 100644 index e2de5f31dfe76..0000000000000 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/UrlParserTargetTest.java +++ /dev/null @@ -1,175 +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.azure.monitor.opentelemetry.exporter.implementation; - -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -public class UrlParserTargetTest { - - // there are more test cases here than needed, but they are mirroring tests in UrlParserPathTest - - @Test - public void testGetTargetFromUrl() { - assertThat(UrlParser.getTargetFromUrl("https://localhost")).isEqualTo("localhost"); - assertThat(UrlParser.getTargetFromUrl("https://localhost/")).isEqualTo("localhost"); - assertThat(UrlParser.getTargetFromUrl("https://localhost/path")).isEqualTo("localhost"); - assertThat(UrlParser.getTargetFromUrl("https://localhost/path/")).isEqualTo("localhost"); - assertThat(UrlParser.getTargetFromUrl("https://localhost/more/path")).isEqualTo("localhost"); - assertThat(UrlParser.getTargetFromUrl("https://localhost/more/path/")).isEqualTo("localhost"); - - assertThat(UrlParser.getTargetFromUrl("https://localhost?")).isEqualTo("localhost"); - assertThat(UrlParser.getTargetFromUrl("https://localhost/?")).isEqualTo("localhost"); - assertThat(UrlParser.getTargetFromUrl("https://localhost/path?")).isEqualTo("localhost"); - assertThat(UrlParser.getTargetFromUrl("https://localhost/path/?")).isEqualTo("localhost"); - assertThat(UrlParser.getTargetFromUrl("https://localhost/more/path?")).isEqualTo("localhost"); - assertThat(UrlParser.getTargetFromUrl("https://localhost/more/path/?")).isEqualTo("localhost"); - - assertThat(UrlParser.getTargetFromUrl("https://localhost?query")).isEqualTo("localhost"); - assertThat(UrlParser.getTargetFromUrl("https://localhost/?query")).isEqualTo("localhost"); - assertThat(UrlParser.getTargetFromUrl("https://localhost/path?query")).isEqualTo("localhost"); - assertThat(UrlParser.getTargetFromUrl("https://localhost/path/?query")).isEqualTo("localhost"); - assertThat(UrlParser.getTargetFromUrl("https://localhost/more/path?query")) - .isEqualTo("localhost"); - assertThat(UrlParser.getTargetFromUrl("https://localhost/more/path/?query")) - .isEqualTo("localhost"); - - assertThat(UrlParser.getTargetFromUrl("https://localhost#")).isEqualTo("localhost"); - assertThat(UrlParser.getTargetFromUrl("https://localhost/#")).isEqualTo("localhost"); - assertThat(UrlParser.getTargetFromUrl("https://localhost/path#")).isEqualTo("localhost"); - assertThat(UrlParser.getTargetFromUrl("https://localhost/path/#")).isEqualTo("localhost"); - assertThat(UrlParser.getTargetFromUrl("https://localhost/more/path#")).isEqualTo("localhost"); - assertThat(UrlParser.getTargetFromUrl("https://localhost/more/path/#")).isEqualTo("localhost"); - - assertThat(UrlParser.getTargetFromUrl("https://localhost#fragment")).isEqualTo("localhost"); - assertThat(UrlParser.getTargetFromUrl("https://localhost/#fragment")).isEqualTo("localhost"); - assertThat(UrlParser.getTargetFromUrl("https://localhost/path#fragment")) - .isEqualTo("localhost"); - assertThat(UrlParser.getTargetFromUrl("https://localhost/path/#fragment")) - .isEqualTo("localhost"); - assertThat(UrlParser.getTargetFromUrl("https://localhost/more/path#fragment")) - .isEqualTo("localhost"); - assertThat(UrlParser.getTargetFromUrl("https://localhost/more/path/#fragment")) - .isEqualTo("localhost"); - } - - @Test - public void testGetTargetFromUrlWithPort() { - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080")).isEqualTo("localhost:8080"); - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/")).isEqualTo("localhost:8080"); - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/path")) - .isEqualTo("localhost:8080"); - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/path/")) - .isEqualTo("localhost:8080"); - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/more/path")) - .isEqualTo("localhost:8080"); - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/more/path/")) - .isEqualTo("localhost:8080"); - - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080?")).isEqualTo("localhost:8080"); - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/?")).isEqualTo("localhost:8080"); - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/path?")) - .isEqualTo("localhost:8080"); - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/path/?")) - .isEqualTo("localhost:8080"); - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/more/path?")) - .isEqualTo("localhost:8080"); - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/more/path/?")) - .isEqualTo("localhost:8080"); - - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080?query")) - .isEqualTo("localhost:8080"); - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/?query")) - .isEqualTo("localhost:8080"); - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/path?query")) - .isEqualTo("localhost:8080"); - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/path/?query")) - .isEqualTo("localhost:8080"); - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/more/path?query")) - .isEqualTo("localhost:8080"); - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/more/path/?query")) - .isEqualTo("localhost:8080"); - - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080#")).isEqualTo("localhost:8080"); - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/#")).isEqualTo("localhost:8080"); - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/path#")) - .isEqualTo("localhost:8080"); - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/path/#")) - .isEqualTo("localhost:8080"); - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/more/path#")) - .isEqualTo("localhost:8080"); - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/more/path/#")) - .isEqualTo("localhost:8080"); - - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080#fragment")) - .isEqualTo("localhost:8080"); - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/#fragment")) - .isEqualTo("localhost:8080"); - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/path#fragment")) - .isEqualTo("localhost:8080"); - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/path/#fragment")) - .isEqualTo("localhost:8080"); - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/more/path#fragment")) - .isEqualTo("localhost:8080"); - assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/more/path/#fragment")) - .isEqualTo("localhost:8080"); - } - - @Test - public void testGetTargetFromUrlWithNoAuthority() { - assertThat(UrlParser.getTargetFromUrl("https:")).isNull(); - assertThat(UrlParser.getTargetFromUrl("https:/")).isNull(); - assertThat(UrlParser.getTargetFromUrl("https:/path")).isNull(); - assertThat(UrlParser.getTargetFromUrl("https:/path/")).isNull(); - assertThat(UrlParser.getTargetFromUrl("https:/more/path")).isNull(); - assertThat(UrlParser.getTargetFromUrl("https:/more/path/")).isNull(); - - assertThat(UrlParser.getTargetFromUrl("https:?")).isNull(); - assertThat(UrlParser.getTargetFromUrl("https:/?")).isNull(); - assertThat(UrlParser.getTargetFromUrl("https:/path?")).isNull(); - assertThat(UrlParser.getTargetFromUrl("https:/path/?")).isNull(); - assertThat(UrlParser.getTargetFromUrl("https:/more/path?")).isNull(); - assertThat(UrlParser.getTargetFromUrl("https:/more/path/?")).isNull(); - - assertThat(UrlParser.getTargetFromUrl("https:?query")).isNull(); - assertThat(UrlParser.getTargetFromUrl("https:/?query")).isNull(); - assertThat(UrlParser.getTargetFromUrl("https:/path?query")).isNull(); - assertThat(UrlParser.getTargetFromUrl("https:/path/?query")).isNull(); - assertThat(UrlParser.getTargetFromUrl("https:/more/path?query")).isNull(); - assertThat(UrlParser.getTargetFromUrl("https:/more/path/?query")).isNull(); - - assertThat(UrlParser.getTargetFromUrl("https:#")).isNull(); - assertThat(UrlParser.getTargetFromUrl("https:/#")).isNull(); - assertThat(UrlParser.getTargetFromUrl("https:/path#")).isNull(); - assertThat(UrlParser.getTargetFromUrl("https:/path/#")).isNull(); - assertThat(UrlParser.getTargetFromUrl("https:/more/path#")).isNull(); - assertThat(UrlParser.getTargetFromUrl("https:/more/path/#")).isNull(); - - assertThat(UrlParser.getTargetFromUrl("https:#fragment")).isNull(); - assertThat(UrlParser.getTargetFromUrl("https:/#fragment")).isNull(); - assertThat(UrlParser.getTargetFromUrl("https:/path#fragment")).isNull(); - assertThat(UrlParser.getTargetFromUrl("https:/path/#fragment")).isNull(); - assertThat(UrlParser.getTargetFromUrl("https:/more/path#fragment")).isNull(); - assertThat(UrlParser.getTargetFromUrl("https:/more/path/#fragment")).isNull(); - } -} diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/ExceptionsTest.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/ExceptionsTest.java new file mode 100644 index 0000000000000..25a2fd5f4a0d2 --- /dev/null +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/ExceptionsTest.java @@ -0,0 +1,98 @@ +/* + * 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.utils; + +import com.azure.monitor.opentelemetry.exporter.implementation.builders.ExceptionDetailBuilder; +import com.azure.monitor.opentelemetry.exporter.implementation.builders.Exceptions; +import com.azure.monitor.opentelemetry.exporter.implementation.models.TelemetryExceptionDetails; +import org.junit.jupiter.api.Test; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ExceptionsTest { + + @Test + public void testMinimalParse() { + // given + String str = toString(new IllegalStateException("test")); + + // when + List list = Exceptions.minimalParse(str); + + // then + assertThat(list.size()).isEqualTo(1); + + TelemetryExceptionDetails details = list.get(0).build(); + assertThat(details.getTypeName()).isEqualTo(IllegalStateException.class.getName()); + assertThat(details.getMessage()).isEqualTo("test"); + } + + @Test + public void testMinimalParseWithNoMessage() { + // given + String str = toString(new IllegalStateException()); + + // when + List list = Exceptions.minimalParse(str); + + // then + assertThat(list.size()).isEqualTo(1); + + TelemetryExceptionDetails details = list.get(0).build(); + assertThat(details.getTypeName()).isEqualTo(IllegalStateException.class.getName()); + assertThat(details.getMessage()).isEqualTo(IllegalStateException.class.getName()); + } + + @Test + public void testMinimalParseWithProblematicMessage() { + // given + String str = toString(new ProblematicException()); + + // when + List list = Exceptions.minimalParse(str); + + // then + assertThat(list.size()).isEqualTo(1); + + TelemetryExceptionDetails details = list.get(0).build(); + assertThat(details.getTypeName()).isEqualTo(ProblematicException.class.getName()); + assertThat(details.getMessage()).isEqualTo(ProblematicException.class.getName()); + } + + private static String toString(Throwable t) { + StringWriter out = new StringWriter(); + t.printStackTrace(new PrintWriter(out)); + return out.toString(); + } + + @SuppressWarnings("OverrideThrowableToString") + private static class ProblematicException extends Exception { + @Override + public String toString() { + return ProblematicException.class.getName() + ":"; + } + } +} diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/FormattedDurationTest.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/FormattedDurationTest.java similarity index 94% rename from sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/FormattedDurationTest.java rename to sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/FormattedDurationTest.java index 14da81a73fe16..154513eefa747 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/FormattedDurationTest.java +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/FormattedDurationTest.java @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package com.azure.monitor.opentelemetry.exporter.implementation; +package com.azure.monitor.opentelemetry.exporter.implementation.utils; import org.junit.jupiter.api.Test; diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/UrlParserPathTest.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/UrlParserPathTest.java new file mode 100644 index 0000000000000..9886ffe6e4c58 --- /dev/null +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/UrlParserPathTest.java @@ -0,0 +1,158 @@ +/* + * 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.utils; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class UrlParserPathTest { + + @Test + public void testGetPathFromUrl() { + assertThat(UrlParser.getPathFromUrl("https://localhost")).isEqualTo(""); + assertThat(UrlParser.getPathFromUrl("https://localhost/")).isEqualTo("/"); + assertThat(UrlParser.getPathFromUrl("https://localhost/path")).isEqualTo("/path"); + assertThat(UrlParser.getPathFromUrl("https://localhost/path/")).isEqualTo("/path/"); + assertThat(UrlParser.getPathFromUrl("https://localhost/more/path")).isEqualTo("/more/path"); + assertThat(UrlParser.getPathFromUrl("https://localhost/more/path/")).isEqualTo("/more/path/"); + + assertThat(UrlParser.getPathFromUrl("https://localhost?")).isEqualTo(""); + assertThat(UrlParser.getPathFromUrl("https://localhost/?")).isEqualTo("/"); + assertThat(UrlParser.getPathFromUrl("https://localhost/path?")).isEqualTo("/path"); + assertThat(UrlParser.getPathFromUrl("https://localhost/path/?")).isEqualTo("/path/"); + assertThat(UrlParser.getPathFromUrl("https://localhost/more/path?")).isEqualTo("/more/path"); + assertThat(UrlParser.getPathFromUrl("https://localhost/more/path/?")).isEqualTo("/more/path/"); + + assertThat(UrlParser.getPathFromUrl("https://localhost?query")).isEqualTo(""); + assertThat(UrlParser.getPathFromUrl("https://localhost/?query")).isEqualTo("/"); + assertThat(UrlParser.getPathFromUrl("https://localhost/path?query")).isEqualTo("/path"); + assertThat(UrlParser.getPathFromUrl("https://localhost/path/?query")).isEqualTo("/path/"); + assertThat(UrlParser.getPathFromUrl("https://localhost/more/path?query")) + .isEqualTo("/more/path"); + assertThat(UrlParser.getPathFromUrl("https://localhost/more/path/?query")) + .isEqualTo("/more/path/"); + + assertThat(UrlParser.getPathFromUrl("https://localhost#")).isEqualTo(""); + assertThat(UrlParser.getPathFromUrl("https://localhost/#")).isEqualTo("/"); + assertThat(UrlParser.getPathFromUrl("https://localhost/path#")).isEqualTo("/path"); + assertThat(UrlParser.getPathFromUrl("https://localhost/path/#")).isEqualTo("/path/"); + assertThat(UrlParser.getPathFromUrl("https://localhost/more/path#")).isEqualTo("/more/path"); + assertThat(UrlParser.getPathFromUrl("https://localhost/more/path/#")).isEqualTo("/more/path/"); + + assertThat(UrlParser.getPathFromUrl("https://localhost#fragment")).isEqualTo(""); + assertThat(UrlParser.getPathFromUrl("https://localhost/#fragment")).isEqualTo("/"); + assertThat(UrlParser.getPathFromUrl("https://localhost/path#fragment")).isEqualTo("/path"); + assertThat(UrlParser.getPathFromUrl("https://localhost/path/#fragment")).isEqualTo("/path/"); + assertThat(UrlParser.getPathFromUrl("https://localhost/more/path#fragment")) + .isEqualTo("/more/path"); + assertThat(UrlParser.getPathFromUrl("https://localhost/more/path/#fragment")) + .isEqualTo("/more/path/"); + } + + @Test + public void testGetPathFromUrlWithPort() { + assertThat(UrlParser.getPathFromUrl("https://localhost:8080")).isEqualTo(""); + assertThat(UrlParser.getPathFromUrl("https://localhost:8080/")).isEqualTo("/"); + assertThat(UrlParser.getPathFromUrl("https://localhost:8080/path")).isEqualTo("/path"); + assertThat(UrlParser.getPathFromUrl("https://localhost:8080/path/")).isEqualTo("/path/"); + assertThat(UrlParser.getPathFromUrl("https://localhost:8080/more/path")) + .isEqualTo("/more/path"); + assertThat(UrlParser.getPathFromUrl("https://localhost:8080/more/path/")) + .isEqualTo("/more/path/"); + + assertThat(UrlParser.getPathFromUrl("https://localhost:8080?")).isEqualTo(""); + assertThat(UrlParser.getPathFromUrl("https://localhost:8080/?")).isEqualTo("/"); + assertThat(UrlParser.getPathFromUrl("https://localhost:8080/path?")).isEqualTo("/path"); + assertThat(UrlParser.getPathFromUrl("https://localhost:8080/path/?")).isEqualTo("/path/"); + assertThat(UrlParser.getPathFromUrl("https://localhost:8080/more/path?")) + .isEqualTo("/more/path"); + assertThat(UrlParser.getPathFromUrl("https://localhost:8080/more/path/?")) + .isEqualTo("/more/path/"); + + assertThat(UrlParser.getPathFromUrl("https://localhost:8080?query")).isEqualTo(""); + assertThat(UrlParser.getPathFromUrl("https://localhost:8080/?query")).isEqualTo("/"); + assertThat(UrlParser.getPathFromUrl("https://localhost:8080/path?query")).isEqualTo("/path"); + assertThat(UrlParser.getPathFromUrl("https://localhost:8080/path/?query")).isEqualTo("/path/"); + assertThat(UrlParser.getPathFromUrl("https://localhost:8080/more/path?query")) + .isEqualTo("/more/path"); + assertThat(UrlParser.getPathFromUrl("https://localhost:8080/more/path/?query")) + .isEqualTo("/more/path/"); + + assertThat(UrlParser.getPathFromUrl("https://localhost:8080#")).isEqualTo(""); + assertThat(UrlParser.getPathFromUrl("https://localhost:8080/#")).isEqualTo("/"); + assertThat(UrlParser.getPathFromUrl("https://localhost:8080/path#")).isEqualTo("/path"); + assertThat(UrlParser.getPathFromUrl("https://localhost:8080/path/#")).isEqualTo("/path/"); + assertThat(UrlParser.getPathFromUrl("https://localhost:8080/more/path#")) + .isEqualTo("/more/path"); + assertThat(UrlParser.getPathFromUrl("https://localhost:8080/more/path/#")) + .isEqualTo("/more/path/"); + + assertThat(UrlParser.getPathFromUrl("https://localhost:8080#fragment")).isEqualTo(""); + assertThat(UrlParser.getPathFromUrl("https://localhost:8080/#fragment")).isEqualTo("/"); + assertThat(UrlParser.getPathFromUrl("https://localhost:8080/path#fragment")).isEqualTo("/path"); + assertThat(UrlParser.getPathFromUrl("https://localhost:8080/path/#fragment")) + .isEqualTo("/path/"); + assertThat(UrlParser.getPathFromUrl("https://localhost:8080/more/path#fragment")) + .isEqualTo("/more/path"); + assertThat(UrlParser.getPathFromUrl("https://localhost:8080/more/path/#fragment")) + .isEqualTo("/more/path/"); + } + + @Test + public void testGetPathFromUrlWithNoAuthority() { + assertThat(UrlParser.getPathFromUrl("https:")).isEqualTo(""); + assertThat(UrlParser.getPathFromUrl("https:/")).isEqualTo("/"); + assertThat(UrlParser.getPathFromUrl("https:/path")).isEqualTo("/path"); + assertThat(UrlParser.getPathFromUrl("https:/path/")).isEqualTo("/path/"); + assertThat(UrlParser.getPathFromUrl("https:/more/path")).isEqualTo("/more/path"); + assertThat(UrlParser.getPathFromUrl("https:/more/path/")).isEqualTo("/more/path/"); + + assertThat(UrlParser.getPathFromUrl("https:?")).isEqualTo(""); + assertThat(UrlParser.getPathFromUrl("https:/?")).isEqualTo("/"); + assertThat(UrlParser.getPathFromUrl("https:/path?")).isEqualTo("/path"); + assertThat(UrlParser.getPathFromUrl("https:/path/?")).isEqualTo("/path/"); + assertThat(UrlParser.getPathFromUrl("https:/more/path?")).isEqualTo("/more/path"); + assertThat(UrlParser.getPathFromUrl("https:/more/path/?")).isEqualTo("/more/path/"); + + assertThat(UrlParser.getPathFromUrl("https:?query")).isEqualTo(""); + assertThat(UrlParser.getPathFromUrl("https:/?query")).isEqualTo("/"); + assertThat(UrlParser.getPathFromUrl("https:/path?query")).isEqualTo("/path"); + assertThat(UrlParser.getPathFromUrl("https:/path/?query")).isEqualTo("/path/"); + assertThat(UrlParser.getPathFromUrl("https:/more/path?query")).isEqualTo("/more/path"); + assertThat(UrlParser.getPathFromUrl("https:/more/path/?query")).isEqualTo("/more/path/"); + + assertThat(UrlParser.getPathFromUrl("https:#")).isEqualTo(""); + assertThat(UrlParser.getPathFromUrl("https:/#")).isEqualTo("/"); + assertThat(UrlParser.getPathFromUrl("https:/path#")).isEqualTo("/path"); + assertThat(UrlParser.getPathFromUrl("https:/path/#")).isEqualTo("/path/"); + assertThat(UrlParser.getPathFromUrl("https:/more/path#")).isEqualTo("/more/path"); + assertThat(UrlParser.getPathFromUrl("https:/more/path/#")).isEqualTo("/more/path/"); + + assertThat(UrlParser.getPathFromUrl("https:#fragment")).isEqualTo(""); + assertThat(UrlParser.getPathFromUrl("https:/#fragment")).isEqualTo("/"); + assertThat(UrlParser.getPathFromUrl("https:/path#fragment")).isEqualTo("/path"); + assertThat(UrlParser.getPathFromUrl("https:/path/#fragment")).isEqualTo("/path/"); + assertThat(UrlParser.getPathFromUrl("https:/more/path#fragment")).isEqualTo("/more/path"); + assertThat(UrlParser.getPathFromUrl("https:/more/path/#fragment")).isEqualTo("/more/path/"); + } +} diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/UrlParserTargetTest.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/UrlParserTargetTest.java new file mode 100644 index 0000000000000..34398fea72127 --- /dev/null +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/UrlParserTargetTest.java @@ -0,0 +1,175 @@ +/* + * 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.utils; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class UrlParserTargetTest { + + // there are more test cases here than needed, but they are mirroring tests in UrlParserPathTest + + @Test + public void testGetTargetFromUrl() { + assertThat(UrlParser.getTargetFromUrl("https://localhost")).isEqualTo("localhost"); + assertThat(UrlParser.getTargetFromUrl("https://localhost/")).isEqualTo("localhost"); + assertThat(UrlParser.getTargetFromUrl("https://localhost/path")).isEqualTo("localhost"); + assertThat(UrlParser.getTargetFromUrl("https://localhost/path/")).isEqualTo("localhost"); + assertThat(UrlParser.getTargetFromUrl("https://localhost/more/path")).isEqualTo("localhost"); + assertThat(UrlParser.getTargetFromUrl("https://localhost/more/path/")).isEqualTo("localhost"); + + assertThat(UrlParser.getTargetFromUrl("https://localhost?")).isEqualTo("localhost"); + assertThat(UrlParser.getTargetFromUrl("https://localhost/?")).isEqualTo("localhost"); + assertThat(UrlParser.getTargetFromUrl("https://localhost/path?")).isEqualTo("localhost"); + assertThat(UrlParser.getTargetFromUrl("https://localhost/path/?")).isEqualTo("localhost"); + assertThat(UrlParser.getTargetFromUrl("https://localhost/more/path?")).isEqualTo("localhost"); + assertThat(UrlParser.getTargetFromUrl("https://localhost/more/path/?")).isEqualTo("localhost"); + + assertThat(UrlParser.getTargetFromUrl("https://localhost?query")).isEqualTo("localhost"); + assertThat(UrlParser.getTargetFromUrl("https://localhost/?query")).isEqualTo("localhost"); + assertThat(UrlParser.getTargetFromUrl("https://localhost/path?query")).isEqualTo("localhost"); + assertThat(UrlParser.getTargetFromUrl("https://localhost/path/?query")).isEqualTo("localhost"); + assertThat(UrlParser.getTargetFromUrl("https://localhost/more/path?query")) + .isEqualTo("localhost"); + assertThat(UrlParser.getTargetFromUrl("https://localhost/more/path/?query")) + .isEqualTo("localhost"); + + assertThat(UrlParser.getTargetFromUrl("https://localhost#")).isEqualTo("localhost"); + assertThat(UrlParser.getTargetFromUrl("https://localhost/#")).isEqualTo("localhost"); + assertThat(UrlParser.getTargetFromUrl("https://localhost/path#")).isEqualTo("localhost"); + assertThat(UrlParser.getTargetFromUrl("https://localhost/path/#")).isEqualTo("localhost"); + assertThat(UrlParser.getTargetFromUrl("https://localhost/more/path#")).isEqualTo("localhost"); + assertThat(UrlParser.getTargetFromUrl("https://localhost/more/path/#")).isEqualTo("localhost"); + + assertThat(UrlParser.getTargetFromUrl("https://localhost#fragment")).isEqualTo("localhost"); + assertThat(UrlParser.getTargetFromUrl("https://localhost/#fragment")).isEqualTo("localhost"); + assertThat(UrlParser.getTargetFromUrl("https://localhost/path#fragment")) + .isEqualTo("localhost"); + assertThat(UrlParser.getTargetFromUrl("https://localhost/path/#fragment")) + .isEqualTo("localhost"); + assertThat(UrlParser.getTargetFromUrl("https://localhost/more/path#fragment")) + .isEqualTo("localhost"); + assertThat(UrlParser.getTargetFromUrl("https://localhost/more/path/#fragment")) + .isEqualTo("localhost"); + } + + @Test + public void testGetTargetFromUrlWithPort() { + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080")).isEqualTo("localhost:8080"); + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/")).isEqualTo("localhost:8080"); + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/path")) + .isEqualTo("localhost:8080"); + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/path/")) + .isEqualTo("localhost:8080"); + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/more/path")) + .isEqualTo("localhost:8080"); + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/more/path/")) + .isEqualTo("localhost:8080"); + + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080?")).isEqualTo("localhost:8080"); + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/?")).isEqualTo("localhost:8080"); + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/path?")) + .isEqualTo("localhost:8080"); + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/path/?")) + .isEqualTo("localhost:8080"); + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/more/path?")) + .isEqualTo("localhost:8080"); + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/more/path/?")) + .isEqualTo("localhost:8080"); + + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080?query")) + .isEqualTo("localhost:8080"); + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/?query")) + .isEqualTo("localhost:8080"); + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/path?query")) + .isEqualTo("localhost:8080"); + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/path/?query")) + .isEqualTo("localhost:8080"); + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/more/path?query")) + .isEqualTo("localhost:8080"); + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/more/path/?query")) + .isEqualTo("localhost:8080"); + + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080#")).isEqualTo("localhost:8080"); + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/#")).isEqualTo("localhost:8080"); + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/path#")) + .isEqualTo("localhost:8080"); + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/path/#")) + .isEqualTo("localhost:8080"); + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/more/path#")) + .isEqualTo("localhost:8080"); + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/more/path/#")) + .isEqualTo("localhost:8080"); + + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080#fragment")) + .isEqualTo("localhost:8080"); + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/#fragment")) + .isEqualTo("localhost:8080"); + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/path#fragment")) + .isEqualTo("localhost:8080"); + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/path/#fragment")) + .isEqualTo("localhost:8080"); + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/more/path#fragment")) + .isEqualTo("localhost:8080"); + assertThat(UrlParser.getTargetFromUrl("https://localhost:8080/more/path/#fragment")) + .isEqualTo("localhost:8080"); + } + + @Test + public void testGetTargetFromUrlWithNoAuthority() { + assertThat(UrlParser.getTargetFromUrl("https:")).isNull(); + assertThat(UrlParser.getTargetFromUrl("https:/")).isNull(); + assertThat(UrlParser.getTargetFromUrl("https:/path")).isNull(); + assertThat(UrlParser.getTargetFromUrl("https:/path/")).isNull(); + assertThat(UrlParser.getTargetFromUrl("https:/more/path")).isNull(); + assertThat(UrlParser.getTargetFromUrl("https:/more/path/")).isNull(); + + assertThat(UrlParser.getTargetFromUrl("https:?")).isNull(); + assertThat(UrlParser.getTargetFromUrl("https:/?")).isNull(); + assertThat(UrlParser.getTargetFromUrl("https:/path?")).isNull(); + assertThat(UrlParser.getTargetFromUrl("https:/path/?")).isNull(); + assertThat(UrlParser.getTargetFromUrl("https:/more/path?")).isNull(); + assertThat(UrlParser.getTargetFromUrl("https:/more/path/?")).isNull(); + + assertThat(UrlParser.getTargetFromUrl("https:?query")).isNull(); + assertThat(UrlParser.getTargetFromUrl("https:/?query")).isNull(); + assertThat(UrlParser.getTargetFromUrl("https:/path?query")).isNull(); + assertThat(UrlParser.getTargetFromUrl("https:/path/?query")).isNull(); + assertThat(UrlParser.getTargetFromUrl("https:/more/path?query")).isNull(); + assertThat(UrlParser.getTargetFromUrl("https:/more/path/?query")).isNull(); + + assertThat(UrlParser.getTargetFromUrl("https:#")).isNull(); + assertThat(UrlParser.getTargetFromUrl("https:/#")).isNull(); + assertThat(UrlParser.getTargetFromUrl("https:/path#")).isNull(); + assertThat(UrlParser.getTargetFromUrl("https:/path/#")).isNull(); + assertThat(UrlParser.getTargetFromUrl("https:/more/path#")).isNull(); + assertThat(UrlParser.getTargetFromUrl("https:/more/path/#")).isNull(); + + assertThat(UrlParser.getTargetFromUrl("https:#fragment")).isNull(); + assertThat(UrlParser.getTargetFromUrl("https:/#fragment")).isNull(); + assertThat(UrlParser.getTargetFromUrl("https:/path#fragment")).isNull(); + assertThat(UrlParser.getTargetFromUrl("https:/path/#fragment")).isNull(); + assertThat(UrlParser.getTargetFromUrl("https:/more/path#fragment")).isNull(); + assertThat(UrlParser.getTargetFromUrl("https:/more/path/#fragment")).isNull(); + } +} diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/VersionTest.java b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/VersionTest.java similarity index 91% rename from sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/VersionTest.java rename to sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/VersionTest.java index 378b7718d390d..d846eddd76917 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/VersionTest.java +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/src/test/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/VersionTest.java @@ -1,4 +1,4 @@ -package com.azure.monitor.opentelemetry.exporter.implementation; +package com.azure.monitor.opentelemetry.exporter.implementation.utils; import org.junit.jupiter.api.Test;