Skip to content

Commit 8739cdf

Browse files
authored
Capture response headers for HttpUrlConnection (#4417)
1 parent 62c9051 commit 8739cdf

File tree

2 files changed

+39
-23
lines changed

2 files changed

+39
-23
lines changed

instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlConnectionInstrumentation.java

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ public static void methodEnter(
7474
// top-level HttpURLConnection calls
7575
return;
7676
}
77+
// double increment on first entry is used to prevent infinite recursion in case end()
78+
// captures response headers due to HttpUrlConnection.getHeaderField() calling
79+
// HttpUrlConnection.getInputStream() which then enters this advice again
80+
callDepth.getAndIncrement();
81+
7782
Context parentContext = currentContext();
7883
if (!instrumenter().shouldStart(parentContext, connection)) {
7984
return;
@@ -108,35 +113,45 @@ public static void methodExit(
108113
@Advice.Local("otelHttpUrlState") HttpUrlState httpUrlState,
109114
@Advice.Local("otelScope") Scope scope,
110115
@Advice.Local("otelCallDepth") CallDepth callDepth) {
111-
if (callDepth.decrementAndGet() > 0) {
116+
// checking against 1 instead of against 0, because of the double increment which is used to
117+
// prevent infinite recursion in case end() captures response headers
118+
if (callDepth.decrementAndGet() > 1) {
112119
return;
113120
}
114121
if (scope == null) {
122+
// need to perform the second decrement here since bailing out early
123+
callDepth.decrementAndGet();
115124
return;
116125
}
117-
scope.close();
118-
119-
if (throwable != null) {
120-
if (responseCode >= 400) {
121-
// HttpURLConnection unnecessarily throws exception on error response.
122-
// None of the other http clients do this, so not recording the exception on the span
123-
// to be consistent with the telemetry for other http clients.
126+
try {
127+
scope.close();
128+
129+
if (throwable != null) {
130+
if (responseCode >= 400) {
131+
// HttpURLConnection unnecessarily throws exception on error response.
132+
// None of the other http clients do this, so not recording the exception on the span
133+
// to be consistent with the telemetry for other http clients.
134+
instrumenter().end(httpUrlState.context, connection, responseCode, null);
135+
} else {
136+
instrumenter()
137+
.end(
138+
httpUrlState.context,
139+
connection,
140+
responseCode > 0 ? responseCode : null,
141+
throwable);
142+
}
143+
httpUrlState.finished = true;
144+
} else if (methodName.equals("getInputStream") && responseCode > 0) {
145+
// responseCode field is sometimes not populated.
146+
// We can't call getResponseCode() due to some unwanted side-effects
147+
// (e.g. breaks getOutputStream).
124148
instrumenter().end(httpUrlState.context, connection, responseCode, null);
125-
} else {
126-
instrumenter()
127-
.end(
128-
httpUrlState.context,
129-
connection,
130-
responseCode > 0 ? responseCode : null,
131-
throwable);
149+
httpUrlState.finished = true;
132150
}
133-
httpUrlState.finished = true;
134-
} else if (methodName.equals("getInputStream") && responseCode > 0) {
135-
// responseCode field is sometimes not populated.
136-
// We can't call getResponseCode() due to some unwanted side-effects
137-
// (e.g. breaks getOutputStream).
138-
instrumenter().end(httpUrlState.context, connection, responseCode, null);
139-
httpUrlState.finished = true;
151+
} finally {
152+
// double increment is used to prevent infinite recursion in case end() captures response
153+
// headers
154+
callDepth.decrementAndGet();
140155
}
141156
}
142157
}

instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlHttpAttributesExtractor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ protected Long responseContentLengthUncompressed(
7272
@Override
7373
protected List<String> responseHeader(
7474
HttpURLConnection connection, Integer statusCode, String name) {
75-
return emptyList();
75+
String value = connection.getHeaderField(name);
76+
return value == null ? emptyList() : singletonList(value);
7677
}
7778
}

0 commit comments

Comments
 (0)