Skip to content

Commit dc60684

Browse files
committed
adding support for other clients
1 parent 8dabf28 commit dc60684

File tree

46 files changed

+1180
-86
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1180
-86
lines changed

instrumentation/apache-httpasyncclient-4.1/src/test/java/io/opentelemetry/instrumentation/hypertrace/apachehttpasyncclient/ApacheAsyncClientInstrumentationModuleTest.java

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@
2424
import java.io.InputStreamReader;
2525
import java.io.UnsupportedEncodingException;
2626
import java.net.URI;
27-
import java.nio.charset.Charset;
2827
import java.nio.charset.StandardCharsets;
2928
import java.util.List;
3029
import java.util.concurrent.ExecutionException;
3130
import java.util.concurrent.Future;
3231
import java.util.concurrent.TimeoutException;
32+
import java.util.zip.GZIPInputStream;
3333
import org.apache.http.Header;
3434
import org.apache.http.HttpEntity;
3535
import org.apache.http.HttpResponse;
@@ -127,6 +127,51 @@ public void postJsonNonRepeatableEntity()
127127
postJsonEntity(entity);
128128
}
129129

130+
@Disabled("This is flaky !!")
131+
@Test
132+
public void getGzipResponse()
133+
throws ExecutionException, InterruptedException, TimeoutException, IOException {
134+
HttpGet getRequest =
135+
new HttpGet(String.format("http://localhost:%s/gzip", testHttpServer.port()));
136+
getRequest.addHeader("foo", "bar");
137+
Future<HttpResponse> futureResponse = client.execute(getRequest, new NoopFutureCallback());
138+
139+
HttpResponse response = futureResponse.get();
140+
Assertions.assertEquals(200, response.getStatusLine().getStatusCode());
141+
try (InputStream gzipStream = new GZIPInputStream(response.getEntity().getContent())) {
142+
String responseBody = readInputStream(gzipStream);
143+
Assertions.assertEquals(TestHttpServer.GzipHandler.RESPONSE_BODY, responseBody);
144+
}
145+
146+
TEST_WRITER.waitForTraces(1);
147+
// exclude server spans
148+
List<List<Span>> traces =
149+
TEST_WRITER.waitForSpans(2, span -> span.getKind().equals(Span.SpanKind.SPAN_KIND_SERVER));
150+
Assertions.assertEquals(1, traces.size());
151+
Assertions.assertEquals(2, traces.get(0).size());
152+
Span clientSpan = traces.get(0).get(1);
153+
Span responseBodySpan = traces.get(0).get(0);
154+
if (traces.get(0).get(0).getKind().equals(Span.SpanKind.SPAN_KIND_CLIENT)) {
155+
clientSpan = traces.get(0).get(0);
156+
responseBodySpan = traces.get(0).get(1);
157+
}
158+
159+
Assertions.assertEquals(
160+
"test-value",
161+
TEST_WRITER
162+
.getAttributesMap(clientSpan)
163+
.get("http.response.header.test-response-header")
164+
.getStringValue());
165+
Assertions.assertEquals(
166+
"bar",
167+
TEST_WRITER.getAttributesMap(clientSpan).get("http.request.header.foo").getStringValue());
168+
Assertions.assertNull(TEST_WRITER.getAttributesMap(clientSpan).get("http.request.body"));
169+
170+
Assertions.assertEquals(
171+
TestHttpServer.GzipHandler.RESPONSE_BODY,
172+
TEST_WRITER.getAttributesMap(responseBodySpan).get("http.response.body").getStringValue());
173+
}
174+
130175
public void postJsonEntity(HttpEntity entity)
131176
throws TimeoutException, InterruptedException, IOException, ExecutionException {
132177
HttpPost postRequest = new HttpPost();
@@ -165,8 +210,7 @@ private static String readInputStream(InputStream inputStream) throws IOExceptio
165210
StringBuilder textBuilder = new StringBuilder();
166211

167212
try (BufferedReader reader =
168-
new BufferedReader(
169-
new InputStreamReader(inputStream, Charset.forName(StandardCharsets.UTF_8.name())))) {
213+
new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
170214
int c;
171215
while ((c = reader.read()) != -1) {
172216
textBuilder.append((char) c);

instrumentation/apache-httpclient-4.0/src/main/java/io/opentelemetry/javaagent/instrumentation/hypertrace/apachehttpclient/v4_0/ApacheHttpClientUtils.java

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@
2020
import io.opentelemetry.api.trace.Span;
2121
import io.opentelemetry.javaagent.instrumentation.hypertrace.apachehttpclient.v4_0.ApacheHttpClientObjectRegistry.SpanAndAttributeKey;
2222
import java.io.IOException;
23-
import java.io.UnsupportedEncodingException;
23+
import java.io.InputStream;
24+
import java.io.InputStreamReader;
25+
import java.io.OutputStreamWriter;
2426
import java.nio.charset.Charset;
2527
import java.util.function.Function;
28+
import java.util.zip.GZIPInputStream;
2629
import org.apache.http.Header;
2730
import org.apache.http.HeaderIterator;
2831
import org.apache.http.HttpEntity;
@@ -100,26 +103,32 @@ public static void traceEntity(
100103
if (contentType == null || !ContentTypeUtils.shouldCapture(contentType.getValue())) {
101104
return;
102105
}
103-
104106
String charsetStr = ContentTypeUtils.parseCharset(contentType.getValue());
105107
Charset charset = ContentTypeCharsetUtils.toCharset(charsetStr);
106-
108+
// Get the content encoding header and check if it's gzip
109+
Header contentEncoding = entity.getContentEncoding();
110+
boolean isGzipEncoded =
111+
contentEncoding != null
112+
&& contentEncoding.getValue() != null
113+
&& contentEncoding.getValue().toLowerCase().contains("gzip");
107114
if (entity.isRepeatable()) {
108115
try {
109-
BoundedByteArrayOutputStream byteArrayOutputStream =
110-
BoundedBuffersFactory.createStream(charset);
111-
entity.writeTo(byteArrayOutputStream);
112-
113-
try {
114-
String body = byteArrayOutputStream.toStringWithSuppliedCharset();
115-
span.setAttribute(bodyAttributeKey, body);
116-
} catch (UnsupportedEncodingException e) {
117-
log.error("Could not parse charset from encoding {}", charsetStr, e);
116+
InputStream contentStream = entity.getContent();
117+
if (isGzipEncoded) {
118+
try {
119+
contentStream = new GZIPInputStream(contentStream);
120+
} catch (IOException e) {
121+
log.error("Failed to create GZIPInputStream", e);
122+
return;
123+
}
118124
}
125+
126+
String body = readInputStream(contentStream, charset);
127+
span.setAttribute(bodyAttributeKey, body);
128+
119129
} catch (IOException e) {
120-
log.error("Could not read request input stream from repeatable request entity/body", e);
130+
throw new RuntimeException(e);
121131
}
122-
123132
return;
124133
}
125134

@@ -133,4 +142,18 @@ public static void traceEntity(
133142
ApacheHttpClientObjectRegistry.entityToSpan.put(
134143
entity, new SpanAndAttributeKey(span, bodyAttributeKey));
135144
}
145+
146+
public static String readInputStream(InputStream inputStream, Charset charset)
147+
throws IOException {
148+
BoundedByteArrayOutputStream outputStream = BoundedBuffersFactory.createStream(charset);
149+
try (InputStreamReader reader = new InputStreamReader(inputStream, charset);
150+
OutputStreamWriter writer = new OutputStreamWriter(outputStream, charset)) {
151+
int c;
152+
while ((c = reader.read()) != -1) {
153+
writer.write(c);
154+
}
155+
writer.flush();
156+
}
157+
return outputStream.toStringWithSuppliedCharset();
158+
}
136159
}

instrumentation/apache-httpclient-4.0/src/main/java/io/opentelemetry/javaagent/instrumentation/hypertrace/apachehttpclient/v4_0/HttpEntityInstrumentation.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,18 @@ public static void exit(@Advice.This HttpEntity thizz, @Advice.Return InputStrea
9292
}
9393
Charset charset = ContentTypeCharsetUtils.toCharset(charsetStr);
9494

95+
String contentEncoding = null;
96+
Header contentEncodingHeader = thizz.getContentEncoding();
97+
if (contentEncodingHeader != null) {
98+
contentEncoding = contentEncodingHeader.getValue();
99+
}
95100
SpanAndBuffer spanAndBuffer =
96101
new SpanAndBuffer(
97102
clientSpan.span,
98103
BoundedBuffersFactory.createStream((int) contentSize, charset),
99104
clientSpan.attributeKey,
100-
charset);
105+
charset,
106+
contentEncoding);
101107
VirtualField.find(InputStream.class, SpanAndBuffer.class).set(inputStream, spanAndBuffer);
102108
}
103109
}

instrumentation/java-streams/src/main/java/io/opentelemetry/javaagent/instrumentation/hypertrace/java/inputstream/InputStreamInstrumentationModule.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,8 @@ public static void exit(@Advice.This InputStream thizz, @Advice.Return int avail
268268
spanAndBuffer.span,
269269
spanAndBuffer.attributeKey,
270270
spanAndBuffer.byteArrayBuffer,
271-
spanAndBuffer.charset);
271+
spanAndBuffer.charset,
272+
spanAndBuffer.contentEncoding);
272273
contextStore.set(thizz, null);
273274
}
274275
}

instrumentation/java-streams/src/main/java/io/opentelemetry/javaagent/instrumentation/hypertrace/java/inputstream/InputStreamUtils.java

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,22 @@
2323
import io.opentelemetry.api.trace.Tracer;
2424
import io.opentelemetry.context.Context;
2525
import io.opentelemetry.instrumentation.api.util.VirtualField;
26+
import java.io.ByteArrayInputStream;
2627
import java.io.ByteArrayOutputStream;
2728
import java.io.IOException;
2829
import java.io.InputStream;
30+
import java.io.InputStreamReader;
31+
import java.io.OutputStreamWriter;
2932
import java.io.UnsupportedEncodingException;
3033
import java.lang.reflect.InvocationTargetException;
3134
import java.lang.reflect.Method;
3235
import java.nio.charset.Charset;
36+
import java.util.zip.GZIPInputStream;
3337
import org.hypertrace.agent.core.instrumentation.HypertraceCallDepthThreadLocalMap;
3438
import org.hypertrace.agent.core.instrumentation.HypertraceSemanticAttributes;
3539
import org.hypertrace.agent.core.instrumentation.SpanAndBuffer;
40+
import org.hypertrace.agent.core.instrumentation.buffer.BoundedBuffersFactory;
41+
import org.hypertrace.agent.core.instrumentation.buffer.BoundedByteArrayOutputStream;
3642
import org.slf4j.Logger;
3743
import org.slf4j.LoggerFactory;
3844

@@ -85,6 +91,13 @@ public static void addAttribute(Span span, AttributeKey<String> attributeKey, St
8591
spanBuilder.setAttribute(
8692
"http.response.header.content-type", (String) resContentType);
8793
}
94+
Object resContentEncoding =
95+
getAttribute.invoke(
96+
span, HypertraceSemanticAttributes.HTTP_RESPONSE_HEADER_CONTENT_ENCODING);
97+
if (resContentEncoding != null) {
98+
spanBuilder.setAttribute(
99+
"http.response.header.content-encoding", (String) resContentEncoding);
100+
}
88101
}
89102
} catch (IllegalAccessException | InvocationTargetException e) {
90103
// ignore and continue
@@ -100,12 +113,31 @@ public static void addAttribute(Span span, AttributeKey<String> attributeKey, St
100113
}
101114

102115
public static void addBody(
103-
Span span, AttributeKey<String> attributeKey, ByteArrayOutputStream buffer, Charset charset) {
116+
Span span,
117+
AttributeKey<String> attributeKey,
118+
ByteArrayOutputStream buffer,
119+
Charset charset,
120+
String contentEncoding) {
104121
try {
105-
String body = buffer.toString(charset.name());
106-
InputStreamUtils.addAttribute(span, attributeKey, body);
122+
byte[] data = buffer.toByteArray();
123+
124+
// if content-encoding is gzip,
125+
if (contentEncoding != null && contentEncoding.toLowerCase().contains("gzip")) {
126+
try (GZIPInputStream gzipInputStream =
127+
new GZIPInputStream(new ByteArrayInputStream(data))) {
128+
InputStreamReader reader = new InputStreamReader(gzipInputStream, charset);
129+
String body = readInputStream(reader, charset);
130+
InputStreamUtils.addAttribute(span, attributeKey, body);
131+
}
132+
} else {
133+
// No decompression needed, convert directly to string
134+
String body = new String(data, charset);
135+
InputStreamUtils.addAttribute(span, attributeKey, body);
136+
}
107137
} catch (UnsupportedEncodingException e) {
108-
log.error("Failed to parse encofing from charset {}", charset, e);
138+
log.error("Failed to parse encoding from charset {}", charset, e);
139+
} catch (IOException e) {
140+
log.error("Failed to read or decompress data", e);
109141
}
110142
}
111143

@@ -132,7 +164,8 @@ public static void read(
132164
spanAndBuffer.span,
133165
spanAndBuffer.attributeKey,
134166
spanAndBuffer.byteArrayBuffer,
135-
spanAndBuffer.charset);
167+
spanAndBuffer.charset,
168+
spanAndBuffer.contentEncoding);
136169
contextStore.set(inputStream, null);
137170
}
138171
}
@@ -146,7 +179,8 @@ public static void read(
146179
spanAndBuffer.span,
147180
spanAndBuffer.attributeKey,
148181
spanAndBuffer.byteArrayBuffer,
149-
spanAndBuffer.charset);
182+
spanAndBuffer.charset,
183+
spanAndBuffer.contentEncoding);
150184
VirtualField.find(InputStream.class, SpanAndBuffer.class).set(inputStream, null);
151185
}
152186
}
@@ -166,7 +200,8 @@ public static void read(
166200
spanAndBuffer.span,
167201
spanAndBuffer.attributeKey,
168202
spanAndBuffer.byteArrayBuffer,
169-
spanAndBuffer.charset);
203+
spanAndBuffer.charset,
204+
spanAndBuffer.contentEncoding);
170205
contextStore.set(inputStream, null);
171206
}
172207
}
@@ -194,10 +229,24 @@ public static void readNBytes(
194229
spanAndBuffer.span,
195230
spanAndBuffer.attributeKey,
196231
spanAndBuffer.byteArrayBuffer,
197-
spanAndBuffer.charset);
232+
spanAndBuffer.charset,
233+
spanAndBuffer.contentEncoding);
198234
contextStore.set(inputStream, null);
199235
} else {
200236
spanAndBuffer.byteArrayBuffer.write(b, off, read);
201237
}
202238
}
239+
240+
public static String readInputStream(InputStreamReader inputReader, Charset charset)
241+
throws IOException {
242+
BoundedByteArrayOutputStream outputStream = BoundedBuffersFactory.createStream(charset);
243+
try (OutputStreamWriter writer = new OutputStreamWriter(outputStream, charset)) {
244+
int c;
245+
while ((c = inputReader.read()) != -1) {
246+
writer.write(c);
247+
}
248+
writer.flush();
249+
}
250+
return outputStream.toStringWithSuppliedCharset();
251+
}
203252
}

instrumentation/micronaut-1.0/src/test/java/io/opentelemetry/javaagent/instrumentation/hypertrace/micronaut/MicronautClientInstrumentationTest.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import io.micronaut.http.client.annotation.Client;
2323
import io.micronaut.test.annotation.MicronautTest;
2424
import io.opentelemetry.proto.trace.v1.Span;
25+
import java.io.IOException;
2526
import java.util.List;
2627
import java.util.concurrent.TimeoutException;
2728
import javax.inject.Inject;
@@ -135,4 +136,41 @@ public void post() throws InterruptedException, TimeoutException {
135136
TEST_WRITER.getAttributesMap(clientSpan).get("http.request.body").getStringValue());
136137
Assertions.assertNull(TEST_WRITER.getAttributesMap(clientSpan).get("http.response.body"));
137138
}
139+
140+
@Test
141+
public void getGzipResponse() throws TimeoutException, InterruptedException, IOException {
142+
String retrieve =
143+
client
144+
.toBlocking()
145+
.retrieve(
146+
HttpRequest.GET(String.format("http://localhost:%d/gzip", testHttpServer.port()))
147+
.header(REQUEST_HEADER_NAME, REQUEST_HEADER_VALUE));
148+
Assertions.assertEquals("{\"message\": \"hello\"}", retrieve);
149+
150+
TEST_WRITER.waitForTraces(1);
151+
List<List<Span>> traces =
152+
TEST_WRITER.waitForSpans(
153+
1,
154+
span ->
155+
!span.getKind().equals(Span.SpanKind.SPAN_KIND_CLIENT)
156+
|| span.getAttributesList().stream()
157+
.noneMatch(
158+
keyValue ->
159+
keyValue.getKey().equals("http.url")
160+
&& keyValue.getValue().getStringValue().contains("/gzip")));
161+
Assertions.assertEquals(1, traces.size());
162+
Assertions.assertEquals(1, traces.get(0).size());
163+
Span clientSpan = traces.get(0).get(0);
164+
Assertions.assertEquals(
165+
REQUEST_HEADER_VALUE,
166+
TEST_WRITER
167+
.getAttributesMap(clientSpan)
168+
.get("http.request.header." + REQUEST_HEADER_NAME)
169+
.getStringValue());
170+
Assertions.assertNull(TEST_WRITER.getAttributesMap(clientSpan).get("http.request.body"));
171+
172+
String respBodyCapturedInSpan =
173+
TEST_WRITER.getAttributesMap(clientSpan).get("http.response.body").getStringValue();
174+
Assertions.assertEquals("{\"message\": \"hello\"}", respBodyCapturedInSpan);
175+
}
138176
}

0 commit comments

Comments
 (0)