Skip to content

Commit

Permalink
Fix Azure SDK target mapping (#2787)
Browse files Browse the repository at this point in the history
See #2699

Co-authored-by: github-actions[bot] <github-action[bot]@users.noreply.github.com>
  • Loading branch information
trask and github-actions[bot] committed Dec 13, 2022
1 parent 0f60ec0 commit 3aa7d31
Show file tree
Hide file tree
Showing 4 changed files with 422 additions and 296 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ private static String getDependencyName(SpanData span) {
return name;
}

String path = UrlParser.getPathFromUrl(url);
String path = UrlParser.getPath(url);
if (path == null) {
return name;
}
Expand Down Expand Up @@ -289,7 +289,8 @@ private static void setOperationName(
private static void applyHttpClientSpan(
RemoteDependencyTelemetryBuilder telemetryBuilder, Attributes attributes) {

int defaultPort = getDefaultPortForHttpUrl(attributes.get(SemanticAttributes.HTTP_URL));
String httpUrl = attributes.get(SemanticAttributes.HTTP_URL);
int defaultPort = getDefaultPortForHttpUrl(httpUrl);
String target = getTargetOrDefault(attributes, defaultPort, "Http");

telemetryBuilder.setType("Http");
Expand All @@ -300,8 +301,7 @@ private static void applyHttpClientSpan(
telemetryBuilder.setResultCode(Long.toString(httpStatusCode));
}

String url = attributes.get(SemanticAttributes.HTTP_URL);
telemetryBuilder.setData(url);
telemetryBuilder.setData(httpUrl);
}

private static void applyRpcClientSpan(
Expand Down Expand Up @@ -350,6 +350,12 @@ private static String getTargetOrNull(Attributes attributes, int defaultPort) {
Long port = attributes.get(AiSemanticAttributes.NET_SOCK_PEER_PORT);
return getTarget(host, port, defaultPort);
}
String httpUrl = attributes.get(SemanticAttributes.HTTP_URL);
if (httpUrl != null) {
// this is needed for instrumentations which don't yet follow the latest OpenTelemetry
// semantic attributes (in particular Azure SDK instrumentation)
return UrlParser.getTarget(httpUrl);
}
return null;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,107 +1,191 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

// Includes work from:
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

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.
*
* <p>Returns {@code null} if the target cannot be extracted from url for any reason.
*/
@Nullable
public static String getTargetFromUrl(String url) {
public static String getTarget(String url) {

int schemeEndIndex = url.indexOf(':');
if (schemeEndIndex == -1) {
// not a valid url
int schemeEndIndexExclusive = getSchemeEndIndexExclusive(url);
if (schemeEndIndexExclusive == -1) {
// invalid 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
int hostEndIndexExclusive = getHostEndIndexExclusive(url, schemeEndIndexExclusive);
if (hostEndIndexExclusive == schemeEndIndexExclusive) {
// no host (or port)
return null;
}

if (hostEndIndexExclusive < url.length() && url.charAt(hostEndIndexExclusive) != ':') {
// no port
return url.substring(schemeEndIndexExclusive, hostEndIndexExclusive);
}

int portStartIndex = hostEndIndexExclusive + 1;

int portEndIndexExclusive = getPortEndIndexExclusive(url, portStartIndex);
if (portEndIndexExclusive == portStartIndex) {
// no port
return url.substring(schemeEndIndexExclusive, hostEndIndexExclusive);
}

String port = url.substring(portStartIndex, portEndIndexExclusive);

if ((port.equals("80") && url.startsWith("http://"))
|| (port.equals("443") && url.startsWith("https://"))) {
return url.substring(schemeEndIndexExclusive, hostEndIndexExclusive);
}

return url.substring(schemeEndIndexExclusive, portEndIndexExclusive);
}

@Nullable
public static String getPath(String url) {

int schemeEndIndexExclusive = getSchemeEndIndexExclusive(url);
if (schemeEndIndexExclusive == -1) {
// invalid url
return null;
}

int hostEndIndexExclusive = getHostEndIndexExclusive(url, schemeEndIndexExclusive);
int portEndIndexExclusive = getPortEndIndexExclusive(url, hostEndIndexExclusive);
int pathEndIndexExclusive = getPathEndIndexExclusive(url, portEndIndexExclusive);

return url.substring(portEndIndexExclusive, pathEndIndexExclusive);
}

@Nullable
public static String getHost(String url) {

int hostStartIndex = getSchemeEndIndexExclusive(url);
if (hostStartIndex == -1) {
// invalid url
return null;
}

int hostEndIndexExclusive = getHostEndIndexExclusive(url, hostStartIndex);
if (hostEndIndexExclusive == hostStartIndex) {
// no host
return null;
}

return url.substring(hostStartIndex, hostEndIndexExclusive);
}

/**
* Returns the path portion of the url.
*
* <p>Returns {@code null} if the path cannot be extracted from url for any reason.
*/
@Nullable
public static String getPathFromUrl(String url) {
public static Integer getPort(String url) {

int schemeEndIndexExclusive = getSchemeEndIndexExclusive(url);
if (schemeEndIndexExclusive == -1) {
// invalid url
return null;
}

int hostEndIndexExclusive = getHostEndIndexExclusive(url, schemeEndIndexExclusive);
if (hostEndIndexExclusive == schemeEndIndexExclusive) {
// no host (or port)
return null;
}

if (hostEndIndexExclusive < url.length() && url.charAt(hostEndIndexExclusive) != ':') {
// no port
return null;
}

int portStartIndex = hostEndIndexExclusive + 1;

int portEndIndexExclusive = getPortEndIndexExclusive(url, portStartIndex);
if (portEndIndexExclusive == portStartIndex) {
// no port
return null;
}

return safeParse(url.substring(portStartIndex, portEndIndexExclusive));
}

public static int getSchemeEndIndexExclusive(String url) {

int schemeEndIndex = url.indexOf(':');
if (schemeEndIndex == -1) {
// not a valid url
return null;
// invalid url
return -1;
}

int len = url.length();
if (len <= schemeEndIndex + 2
|| url.charAt(schemeEndIndex + 1) != '/'
|| url.charAt(schemeEndIndex + 2) != '/') {
// has no authority component
return -1;
}

return schemeEndIndex + 3;
}

public static int getHostEndIndexExclusive(String url, int startIndex) {
// look for the end of the host:
// ':' ==> start of port, or
// '/', '?', '#' ==> start of path
int index;
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 "";
}
for (index = startIndex; index < len; index++) {
char c = url.charAt(index);
if (c == ':' || c == '/' || c == '?' || c == '#') {
break;
}
if (pathStartIndex == -1) {
// end of the url was reached while scanning for the beginning of the path
// which means the path is empty
return "";
}
return index;
}

public static int getPortEndIndexExclusive(String url, int startIndex) {
// look for the end of the port:
// '/', '?', '#' ==> start of path
int index;
int len = url.length();
for (index = startIndex; index < len; index++) {
char c = url.charAt(index);
if (c == '/' || c == '?' || c == '#') {
break;
}
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);
}
return index;
}

@Nullable
private static Integer safeParse(String port) {
try {
return Integer.valueOf(port);
} catch (NumberFormatException e) {
return null;
}
}

// returns the ending index of the path component (exclusive)
private static int getPathEndIndex(String url, int startIndex) {
private static int getPathEndIndexExclusive(String url, int startIndex) {
// look for the end of the port:
// '/', '?', '#' ==> start of path
int index;
int len = url.length();
for (int i = startIndex; i < len; i++) {
char c = url.charAt(i);
for (index = startIndex; index < len; index++) {
char c = url.charAt(index);
if (c == '?' || c == '#') {
return i;
break;
}
}
return len;
return index;
}

private UrlParser() {}
Expand Down

0 comments on commit 3aa7d31

Please sign in to comment.