Skip to content

Commit 3aa7d31

Browse files
traskgithub-actions[bot]
andauthored
Fix Azure SDK target mapping (#2787)
See #2699 Co-authored-by: github-actions[bot] <github-action[bot]@users.noreply.github.com>
1 parent 0f60ec0 commit 3aa7d31

File tree

4 files changed

+422
-296
lines changed

4 files changed

+422
-296
lines changed

agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/SpanDataMapper.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ private static String getDependencyName(SpanData span) {
198198
return name;
199199
}
200200

201-
String path = UrlParser.getPathFromUrl(url);
201+
String path = UrlParser.getPath(url);
202202
if (path == null) {
203203
return name;
204204
}
@@ -289,7 +289,8 @@ private static void setOperationName(
289289
private static void applyHttpClientSpan(
290290
RemoteDependencyTelemetryBuilder telemetryBuilder, Attributes attributes) {
291291

292-
int defaultPort = getDefaultPortForHttpUrl(attributes.get(SemanticAttributes.HTTP_URL));
292+
String httpUrl = attributes.get(SemanticAttributes.HTTP_URL);
293+
int defaultPort = getDefaultPortForHttpUrl(httpUrl);
293294
String target = getTargetOrDefault(attributes, defaultPort, "Http");
294295

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

303-
String url = attributes.get(SemanticAttributes.HTTP_URL);
304-
telemetryBuilder.setData(url);
304+
telemetryBuilder.setData(httpUrl);
305305
}
306306

307307
private static void applyRpcClientSpan(
@@ -350,6 +350,12 @@ private static String getTargetOrNull(Attributes attributes, int defaultPort) {
350350
Long port = attributes.get(AiSemanticAttributes.NET_SOCK_PEER_PORT);
351351
return getTarget(host, port, defaultPort);
352352
}
353+
String httpUrl = attributes.get(SemanticAttributes.HTTP_URL);
354+
if (httpUrl != null) {
355+
// this is needed for instrumentations which don't yet follow the latest OpenTelemetry
356+
// semantic attributes (in particular Azure SDK instrumentation)
357+
return UrlParser.getTarget(httpUrl);
358+
}
353359
return null;
354360
}
355361

agent/azure-monitor-exporter/src/main/java/com/azure/monitor/opentelemetry/exporter/implementation/utils/UrlParser.java

Lines changed: 153 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,191 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4+
// Includes work from:
5+
/*
6+
* Copyright The OpenTelemetry Authors
7+
* SPDX-License-Identifier: Apache-2.0
8+
*/
9+
410
package com.azure.monitor.opentelemetry.exporter.implementation.utils;
511

612
import reactor.util.annotation.Nullable;
713

814
public class UrlParser {
915

10-
/**
11-
* Returns the "target" (host:port) portion of the url.
12-
*
13-
* <p>Returns {@code null} if the target cannot be extracted from url for any reason.
14-
*/
1516
@Nullable
16-
public static String getTargetFromUrl(String url) {
17+
public static String getTarget(String url) {
1718

18-
int schemeEndIndex = url.indexOf(':');
19-
if (schemeEndIndex == -1) {
20-
// not a valid url
19+
int schemeEndIndexExclusive = getSchemeEndIndexExclusive(url);
20+
if (schemeEndIndexExclusive == -1) {
21+
// invalid url
2122
return null;
2223
}
2324

24-
int len = url.length();
25-
if (schemeEndIndex + 2 < len
26-
&& url.charAt(schemeEndIndex + 1) == '/'
27-
&& url.charAt(schemeEndIndex + 2) == '/') {
28-
// has authority component
29-
// look for
30-
// '/' - start of path
31-
// '?' or end of string - empty path
32-
int index;
33-
for (index = schemeEndIndex + 3; index < len; index++) {
34-
char c = url.charAt(index);
35-
if (c == '/' || c == '?' || c == '#') {
36-
break;
37-
}
38-
}
39-
String target = url.substring(schemeEndIndex + 3, index);
40-
return target.isEmpty() ? null : target;
41-
} else {
42-
// has no authority
25+
int hostEndIndexExclusive = getHostEndIndexExclusive(url, schemeEndIndexExclusive);
26+
if (hostEndIndexExclusive == schemeEndIndexExclusive) {
27+
// no host (or port)
28+
return null;
29+
}
30+
31+
if (hostEndIndexExclusive < url.length() && url.charAt(hostEndIndexExclusive) != ':') {
32+
// no port
33+
return url.substring(schemeEndIndexExclusive, hostEndIndexExclusive);
34+
}
35+
36+
int portStartIndex = hostEndIndexExclusive + 1;
37+
38+
int portEndIndexExclusive = getPortEndIndexExclusive(url, portStartIndex);
39+
if (portEndIndexExclusive == portStartIndex) {
40+
// no port
41+
return url.substring(schemeEndIndexExclusive, hostEndIndexExclusive);
42+
}
43+
44+
String port = url.substring(portStartIndex, portEndIndexExclusive);
45+
46+
if ((port.equals("80") && url.startsWith("http://"))
47+
|| (port.equals("443") && url.startsWith("https://"))) {
48+
return url.substring(schemeEndIndexExclusive, hostEndIndexExclusive);
49+
}
50+
51+
return url.substring(schemeEndIndexExclusive, portEndIndexExclusive);
52+
}
53+
54+
@Nullable
55+
public static String getPath(String url) {
56+
57+
int schemeEndIndexExclusive = getSchemeEndIndexExclusive(url);
58+
if (schemeEndIndexExclusive == -1) {
59+
// invalid url
60+
return null;
61+
}
62+
63+
int hostEndIndexExclusive = getHostEndIndexExclusive(url, schemeEndIndexExclusive);
64+
int portEndIndexExclusive = getPortEndIndexExclusive(url, hostEndIndexExclusive);
65+
int pathEndIndexExclusive = getPathEndIndexExclusive(url, portEndIndexExclusive);
66+
67+
return url.substring(portEndIndexExclusive, pathEndIndexExclusive);
68+
}
69+
70+
@Nullable
71+
public static String getHost(String url) {
72+
73+
int hostStartIndex = getSchemeEndIndexExclusive(url);
74+
if (hostStartIndex == -1) {
75+
// invalid url
4376
return null;
4477
}
78+
79+
int hostEndIndexExclusive = getHostEndIndexExclusive(url, hostStartIndex);
80+
if (hostEndIndexExclusive == hostStartIndex) {
81+
// no host
82+
return null;
83+
}
84+
85+
return url.substring(hostStartIndex, hostEndIndexExclusive);
4586
}
4687

47-
/**
48-
* Returns the path portion of the url.
49-
*
50-
* <p>Returns {@code null} if the path cannot be extracted from url for any reason.
51-
*/
5288
@Nullable
53-
public static String getPathFromUrl(String url) {
89+
public static Integer getPort(String url) {
90+
91+
int schemeEndIndexExclusive = getSchemeEndIndexExclusive(url);
92+
if (schemeEndIndexExclusive == -1) {
93+
// invalid url
94+
return null;
95+
}
96+
97+
int hostEndIndexExclusive = getHostEndIndexExclusive(url, schemeEndIndexExclusive);
98+
if (hostEndIndexExclusive == schemeEndIndexExclusive) {
99+
// no host (or port)
100+
return null;
101+
}
102+
103+
if (hostEndIndexExclusive < url.length() && url.charAt(hostEndIndexExclusive) != ':') {
104+
// no port
105+
return null;
106+
}
107+
108+
int portStartIndex = hostEndIndexExclusive + 1;
109+
110+
int portEndIndexExclusive = getPortEndIndexExclusive(url, portStartIndex);
111+
if (portEndIndexExclusive == portStartIndex) {
112+
// no port
113+
return null;
114+
}
115+
116+
return safeParse(url.substring(portStartIndex, portEndIndexExclusive));
117+
}
118+
119+
public static int getSchemeEndIndexExclusive(String url) {
54120

55121
int schemeEndIndex = url.indexOf(':');
56122
if (schemeEndIndex == -1) {
57-
// not a valid url
58-
return null;
123+
// invalid url
124+
return -1;
125+
}
126+
127+
int len = url.length();
128+
if (len <= schemeEndIndex + 2
129+
|| url.charAt(schemeEndIndex + 1) != '/'
130+
|| url.charAt(schemeEndIndex + 2) != '/') {
131+
// has no authority component
132+
return -1;
59133
}
60134

135+
return schemeEndIndex + 3;
136+
}
137+
138+
public static int getHostEndIndexExclusive(String url, int startIndex) {
139+
// look for the end of the host:
140+
// ':' ==> start of port, or
141+
// '/', '?', '#' ==> start of path
142+
int index;
61143
int len = url.length();
62-
if (schemeEndIndex + 2 < len
63-
&& url.charAt(schemeEndIndex + 1) == '/'
64-
&& url.charAt(schemeEndIndex + 2) == '/') {
65-
// has authority component
66-
// look for
67-
// '/' - start of path
68-
// '?' or end of string - empty path
69-
int pathStartIndex = -1;
70-
for (int i = schemeEndIndex + 3; i < len; i++) {
71-
char c = url.charAt(i);
72-
if (c == '/') {
73-
pathStartIndex = i;
74-
break;
75-
} else if (c == '?' || c == '#') {
76-
// empty path
77-
return "";
78-
}
144+
for (index = startIndex; index < len; index++) {
145+
char c = url.charAt(index);
146+
if (c == ':' || c == '/' || c == '?' || c == '#') {
147+
break;
79148
}
80-
if (pathStartIndex == -1) {
81-
// end of the url was reached while scanning for the beginning of the path
82-
// which means the path is empty
83-
return "";
149+
}
150+
return index;
151+
}
152+
153+
public static int getPortEndIndexExclusive(String url, int startIndex) {
154+
// look for the end of the port:
155+
// '/', '?', '#' ==> start of path
156+
int index;
157+
int len = url.length();
158+
for (index = startIndex; index < len; index++) {
159+
char c = url.charAt(index);
160+
if (c == '/' || c == '?' || c == '#') {
161+
break;
84162
}
85-
int pathEndIndex = getPathEndIndex(url, pathStartIndex + 1);
86-
return url.substring(pathStartIndex, pathEndIndex);
87-
} else {
88-
// has no authority, path starts right away
89-
int pathStartIndex = schemeEndIndex + 1;
90-
int pathEndIndex = getPathEndIndex(url, pathStartIndex);
91-
return url.substring(pathStartIndex, pathEndIndex);
163+
}
164+
return index;
165+
}
166+
167+
@Nullable
168+
private static Integer safeParse(String port) {
169+
try {
170+
return Integer.valueOf(port);
171+
} catch (NumberFormatException e) {
172+
return null;
92173
}
93174
}
94175

95176
// returns the ending index of the path component (exclusive)
96-
private static int getPathEndIndex(String url, int startIndex) {
177+
private static int getPathEndIndexExclusive(String url, int startIndex) {
178+
// look for the end of the port:
179+
// '/', '?', '#' ==> start of path
180+
int index;
97181
int len = url.length();
98-
for (int i = startIndex; i < len; i++) {
99-
char c = url.charAt(i);
182+
for (index = startIndex; index < len; index++) {
183+
char c = url.charAt(index);
100184
if (c == '?' || c == '#') {
101-
return i;
185+
break;
102186
}
103187
}
104-
return len;
188+
return index;
105189
}
106190

107191
private UrlParser() {}

0 commit comments

Comments
 (0)