Skip to content

Commit a9dbba6

Browse files
committed
Get and test metrics for injection failures and skips
1 parent 3e91d8a commit a9dbba6

File tree

4 files changed

+228
-36
lines changed

4 files changed

+228
-36
lines changed

dd-java-agent/instrumentation/servlet/request-3/src/main/java/datadog/trace/instrumentation/servlet3/RumHttpServletResponseWrapper.java

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,37 +23,48 @@ public RumHttpServletResponseWrapper(HttpServletResponse response) {
2323
@Override
2424
public ServletOutputStream getOutputStream() throws IOException {
2525
if (!shouldInject) {
26+
RumInjector.getTelemetryCollector().onInjectionSkipped();
2627
return super.getOutputStream();
2728
}
2829
if (outputStream == null) {
29-
String encoding = getCharacterEncoding();
30-
if (encoding == null) {
31-
encoding = Charset.defaultCharset().name();
30+
try {
31+
String encoding = getCharacterEncoding();
32+
if (encoding == null) {
33+
encoding = Charset.defaultCharset().name();
34+
}
35+
outputStream =
36+
new WrappedServletOutputStream(
37+
super.getOutputStream(),
38+
rumInjector.getMarkerBytes(encoding),
39+
rumInjector.getSnippetBytes(encoding),
40+
this::onInjected);
41+
} catch (Exception e) {
42+
RumInjector.getTelemetryCollector().onInjectionFailed();
43+
throw e;
3244
}
33-
outputStream =
34-
new WrappedServletOutputStream(
35-
super.getOutputStream(),
36-
rumInjector.getMarkerBytes(encoding),
37-
rumInjector.getSnippetBytes(encoding),
38-
this::onInjected);
3945
}
4046
return outputStream;
4147
}
4248

4349
@Override
4450
public PrintWriter getWriter() throws IOException {
45-
final PrintWriter delegate = super.getWriter();
4651
if (!shouldInject) {
47-
return delegate;
52+
RumInjector.getTelemetryCollector().onInjectionSkipped();
53+
return super.getWriter();
4854
}
4955
if (printWriter == null) {
50-
printWriter =
51-
new PrintWriter(
52-
new InjectingPipeWriter(
53-
delegate,
54-
rumInjector.getMarkerChars(),
55-
rumInjector.getSnippetChars(),
56-
this::onInjected));
56+
try {
57+
printWriter =
58+
new PrintWriter(
59+
new InjectingPipeWriter(
60+
super.getWriter(),
61+
rumInjector.getMarkerChars(),
62+
rumInjector.getSnippetChars(),
63+
this::onInjected));
64+
} catch (Exception e) {
65+
RumInjector.getTelemetryCollector().onInjectionFailed();
66+
throw e;
67+
}
5768
}
5869
return printWriter;
5970
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import datadog.trace.agent.test.AgentTestRunner
2+
import datadog.trace.api.rum.RumInjector
3+
import datadog.trace.api.rum.RumTelemetryCollector
4+
import datadog.trace.instrumentation.servlet3.RumHttpServletResponseWrapper
5+
import spock.lang.Subject
6+
7+
import javax.servlet.http.HttpServletResponse
8+
9+
class RumHttpServletResponseWrapperTest extends AgentTestRunner {
10+
11+
def mockResponse = Mock(HttpServletResponse)
12+
def mockTelemetryCollector = Mock(RumTelemetryCollector)
13+
14+
@Subject
15+
RumHttpServletResponseWrapper wrapper
16+
17+
void setup() {
18+
wrapper = new RumHttpServletResponseWrapper(mockResponse)
19+
RumInjector.setTelemetryCollector(mockTelemetryCollector)
20+
}
21+
22+
void cleanup() {
23+
RumInjector.setTelemetryCollector(RumTelemetryCollector.NO_OP)
24+
}
25+
26+
void 'onInjected calls telemetry collector onInjectionSucceed'() {
27+
when:
28+
wrapper.onInjected()
29+
30+
then:
31+
1 * mockTelemetryCollector.onInjectionSucceed()
32+
}
33+
34+
void 'getOutputStream with non-HTML content reports skipped'() {
35+
setup:
36+
wrapper.setContentType("text/plain")
37+
38+
when:
39+
wrapper.getOutputStream()
40+
41+
then:
42+
1 * mockTelemetryCollector.onInjectionSkipped()
43+
1 * mockResponse.getOutputStream()
44+
}
45+
46+
void 'getWriter with non-HTML content reports skipped'() {
47+
setup:
48+
wrapper.setContentType("text/plain")
49+
50+
when:
51+
wrapper.getWriter()
52+
53+
then:
54+
1 * mockTelemetryCollector.onInjectionSkipped()
55+
1 * mockResponse.getWriter()
56+
}
57+
58+
void 'getOutputStream exception reports failure'() {
59+
setup:
60+
wrapper.setContentType("text/html")
61+
mockResponse.getOutputStream() >> { throw new IOException("stream error") }
62+
63+
when:
64+
try {
65+
wrapper.getOutputStream()
66+
} catch (IOException ignored) {}
67+
68+
then:
69+
1 * mockTelemetryCollector.onInjectionFailed()
70+
}
71+
72+
void 'getWriter exception reports failure'() {
73+
setup:
74+
wrapper.setContentType("text/html")
75+
mockResponse.getWriter() >> { throw new IOException("writer error") }
76+
77+
when:
78+
try {
79+
wrapper.getWriter()
80+
} catch (IOException ignored) {}
81+
82+
then:
83+
1 * mockTelemetryCollector.onInjectionFailed()
84+
}
85+
}

dd-java-agent/instrumentation/servlet/request-5/src/main/java/datadog/trace/instrumentation/servlet5/RumHttpServletResponseWrapper.java

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,37 +23,48 @@ public RumHttpServletResponseWrapper(HttpServletResponse response) {
2323
@Override
2424
public ServletOutputStream getOutputStream() throws IOException {
2525
if (!shouldInject) {
26+
RumInjector.getTelemetryCollector().onInjectionSkipped();
2627
return super.getOutputStream();
2728
}
2829
if (outputStream == null) {
29-
String encoding = getCharacterEncoding();
30-
if (encoding == null) {
31-
encoding = Charset.defaultCharset().name();
30+
try {
31+
String encoding = getCharacterEncoding();
32+
if (encoding == null) {
33+
encoding = Charset.defaultCharset().name();
34+
}
35+
outputStream =
36+
new WrappedServletOutputStream(
37+
super.getOutputStream(),
38+
rumInjector.getMarkerBytes(encoding),
39+
rumInjector.getSnippetBytes(encoding),
40+
this::onInjected);
41+
} catch (Exception e) {
42+
RumInjector.getTelemetryCollector().onInjectionFailed();
43+
throw e;
3244
}
33-
outputStream =
34-
new WrappedServletOutputStream(
35-
super.getOutputStream(),
36-
rumInjector.getMarkerBytes(encoding),
37-
rumInjector.getSnippetBytes(encoding),
38-
this::onInjected);
3945
}
4046
return outputStream;
4147
}
4248

4349
@Override
4450
public PrintWriter getWriter() throws IOException {
45-
final PrintWriter delegate = super.getWriter();
4651
if (!shouldInject) {
47-
return delegate;
52+
RumInjector.getTelemetryCollector().onInjectionSkipped();
53+
return super.getWriter();
4854
}
4955
if (printWriter == null) {
50-
printWriter =
51-
new PrintWriter(
52-
new InjectingPipeWriter(
53-
delegate,
54-
rumInjector.getMarkerChars(),
55-
rumInjector.getSnippetChars(),
56-
this::onInjected));
56+
try {
57+
printWriter =
58+
new PrintWriter(
59+
new InjectingPipeWriter(
60+
super.getWriter(),
61+
rumInjector.getMarkerChars(),
62+
rumInjector.getSnippetChars(),
63+
this::onInjected));
64+
} catch (Exception e) {
65+
RumInjector.getTelemetryCollector().onInjectionFailed();
66+
throw e;
67+
}
5768
}
5869
return printWriter;
5970
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import datadog.trace.agent.test.AgentTestRunner
2+
import datadog.trace.api.rum.RumInjector
3+
import datadog.trace.api.rum.RumTelemetryCollector
4+
import datadog.trace.instrumentation.servlet5.RumHttpServletResponseWrapper
5+
import spock.lang.Subject
6+
7+
import jakarta.servlet.http.HttpServletResponse
8+
9+
class RumHttpServletResponseWrapperTest extends AgentTestRunner {
10+
11+
def mockResponse = Mock(HttpServletResponse)
12+
def mockTelemetryCollector = Mock(RumTelemetryCollector)
13+
14+
@Subject
15+
RumHttpServletResponseWrapper wrapper
16+
17+
void setup() {
18+
wrapper = new RumHttpServletResponseWrapper(mockResponse)
19+
RumInjector.setTelemetryCollector(mockTelemetryCollector)
20+
}
21+
22+
void cleanup() {
23+
RumInjector.setTelemetryCollector(RumTelemetryCollector.NO_OP)
24+
}
25+
26+
void 'onInjected calls telemetry collector onInjectionSucceed'() {
27+
when:
28+
wrapper.onInjected()
29+
30+
then:
31+
1 * mockTelemetryCollector.onInjectionSucceed()
32+
}
33+
34+
void 'getOutputStream with non-HTML content reports skipped'() {
35+
setup:
36+
wrapper.setContentType("text/plain")
37+
38+
when:
39+
wrapper.getOutputStream()
40+
41+
then:
42+
1 * mockTelemetryCollector.onInjectionSkipped()
43+
1 * mockResponse.getOutputStream()
44+
}
45+
46+
void 'getWriter with non-HTML content reports skipped'() {
47+
setup:
48+
wrapper.setContentType("text/plain")
49+
50+
when:
51+
wrapper.getWriter()
52+
53+
then:
54+
1 * mockTelemetryCollector.onInjectionSkipped()
55+
1 * mockResponse.getWriter()
56+
}
57+
58+
void 'getOutputStream exception reports failure'() {
59+
setup:
60+
wrapper.setContentType("text/html")
61+
mockResponse.getOutputStream() >> { throw new IOException("stream error") }
62+
63+
when:
64+
try {
65+
wrapper.getOutputStream()
66+
} catch (IOException ignored) {}
67+
68+
then:
69+
1 * mockTelemetryCollector.onInjectionFailed()
70+
}
71+
72+
void 'getWriter exception reports failure'() {
73+
setup:
74+
wrapper.setContentType("text/html")
75+
mockResponse.getWriter() >> { throw new IOException("writer error") }
76+
77+
when:
78+
try {
79+
wrapper.getWriter()
80+
} catch (IOException ignored) {}
81+
82+
then:
83+
1 * mockTelemetryCollector.onInjectionFailed()
84+
}
85+
}

0 commit comments

Comments
 (0)