Skip to content

Commit aab703e

Browse files
committed
feat: Add more tracing to OpenCensusTracer on requests
1 parent 1c76cd0 commit aab703e

File tree

8 files changed

+315
-174
lines changed

8 files changed

+315
-174
lines changed

src/main/java/com/spotify/github/tracing/Span.java

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
* Licensed under the Apache License, Version 2.0 (the "License");
88
* you may not use this file except in compliance with the License.
99
* You may obtain a copy of the License at
10-
*
10+
*
1111
* http://www.apache.org/licenses/LICENSE-2.0
12-
*
12+
*
1313
* Unless required by applicable law or agreed to in writing, software
1414
* distributed under the License is distributed on an "AS IS" BASIS,
1515
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -22,12 +22,21 @@
2222

2323
public interface Span extends AutoCloseable {
2424

25-
Span success();
25+
Span success();
2626

27-
Span failure(Throwable t);
27+
Span failure(Throwable t);
2828

29-
/** Close span. Must be called for any opened span. */
30-
@Override
31-
void close();
32-
}
29+
/** Close span. Must be called for any opened span. */
30+
@Override
31+
void close();
32+
33+
Span addTag(String key, String value);
34+
35+
Span addTag(String key, boolean value);
3336

37+
Span addTag(String key, long value);
38+
39+
Span addTag(String key, double value);
40+
41+
Span addEvent(String description);
42+
}

src/main/java/com/spotify/github/tracing/TraceHelper.java

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,47 @@
2020

2121
package com.spotify.github.tracing;
2222

23+
import com.spotify.github.v3.exceptions.RequestNotOkException;
24+
2325
public class TraceHelper {
24-
// Tracing Headers
25-
public static final String HEADER_CLOUD_TRACE_CONTEXT = "X-Cloud-Trace-Context";
26-
public static final String HEADER_TRACE_PARENT = "traceparent";
27-
public static final String HEADER_TRACE_STATE = "tracestate";
26+
// Tracing Headers
27+
public static final String HEADER_CLOUD_TRACE_CONTEXT = "X-Cloud-Trace-Context";
28+
public static final String HEADER_TRACE_PARENT = "traceparent";
29+
public static final String HEADER_TRACE_STATE = "tracestate";
30+
31+
public static final int NOT_FOUND = 404;
32+
public static final int INTERNAL_SERVER_ERROR = 500;
2833

29-
// Private constructor to prevent instantiation
30-
private TraceHelper() {
31-
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
34+
// Private constructor to prevent instantiation
35+
private TraceHelper() {
36+
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
37+
}
38+
39+
public static Span failSpan(final Span span, final Throwable t) {
40+
if (t instanceof RequestNotOkException) {
41+
RequestNotOkException ex = (RequestNotOkException) t;
42+
span.addTag(TraceHelper.TraceTags.HTTP_STATUS_CODE, ex.statusCode())
43+
.addTag(TraceHelper.TraceTags.ERROR_MESSAGE, ex.getRawMessage());
44+
if (ex.statusCode() - INTERNAL_SERVER_ERROR >= 0) {
45+
span.addTag(TraceHelper.TraceTags.ERROR, true);
46+
}
47+
} else {
48+
if (t != null) {
49+
span.addTag(TraceHelper.TraceTags.ERROR_MESSAGE, t.getMessage());
50+
}
51+
span.addTag(TraceHelper.TraceTags.ERROR, true);
3252
}
53+
return span;
54+
}
55+
56+
public static class TraceTags {
57+
public static final String COMPONENT = "component";
58+
public static final String PEER_SERVICE = "peer.service";
59+
public static final String HTTP_URL = "http.url";
60+
public static final String HTTP_METHOD = "method";
61+
public static final String HTTP_STATUS_CODE = "http.status_code";
62+
public static final String HTTP_STATUS_MESSAGE = "http.status_message";
63+
public static final String ERROR_MESSAGE = "message";
64+
public static final String ERROR = "error";
65+
}
3366
}

src/main/java/com/spotify/github/tracing/opencensus/OpenCensusSpan.java

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -20,46 +20,65 @@
2020

2121
package com.spotify.github.tracing.opencensus;
2222

23+
import static com.spotify.github.tracing.TraceHelper.failSpan;
24+
import static java.util.Objects.requireNonNull;
25+
2326
import com.spotify.github.tracing.Span;
24-
import com.spotify.github.v3.exceptions.RequestNotOkException;
2527
import io.opencensus.trace.AttributeValue;
2628
import io.opencensus.trace.Status;
2729

28-
import static java.util.Objects.requireNonNull;
29-
3030
public class OpenCensusSpan implements Span {
31+
private final io.opencensus.trace.Span span;
3132

32-
public static final int NOT_FOUND = 404;
33-
public static final int INTERNAL_SERVER_ERROR = 500;
34-
private final io.opencensus.trace.Span span;
33+
public OpenCensusSpan(final io.opencensus.trace.Span span) {
34+
this.span = requireNonNull(span);
35+
}
3536

36-
public OpenCensusSpan(final io.opencensus.trace.Span span) {
37-
this.span = requireNonNull(span);
38-
}
37+
@Override
38+
public Span success() {
39+
span.setStatus(Status.OK);
40+
return this;
41+
}
3942

40-
@Override
41-
public Span success() {
42-
span.setStatus(Status.OK);
43-
return this;
44-
}
43+
@Override
44+
public Span failure(final Throwable t) {
45+
failSpan(this, t);
46+
span.setStatus(Status.UNKNOWN);
47+
return this;
48+
}
4549

46-
@Override
47-
public Span failure(final Throwable t) {
48-
if (t instanceof RequestNotOkException) {
49-
RequestNotOkException ex = (RequestNotOkException) t;
50-
span.putAttribute("http.status_code", AttributeValue.longAttributeValue(ex.statusCode()));
51-
span.putAttribute("message", AttributeValue.stringAttributeValue(ex.getRawMessage()));
52-
if (ex.statusCode() - INTERNAL_SERVER_ERROR >= 0) {
53-
span.putAttribute("error", AttributeValue.booleanAttributeValue(true));
54-
}
55-
}
56-
span.setStatus(Status.UNKNOWN);
57-
return this;
58-
}
50+
@Override
51+
public void close() {
52+
span.end();
53+
}
5954

60-
@Override
61-
public void close() {
62-
span.end();
63-
}
64-
}
55+
@Override
56+
public Span addTag(final String key, final String value) {
57+
this.span.putAttribute(key, AttributeValue.stringAttributeValue(value));
58+
return this;
59+
}
6560

61+
@Override
62+
public Span addTag(final String key, final boolean value) {
63+
this.span.putAttribute(key, AttributeValue.booleanAttributeValue(value));
64+
return this;
65+
}
66+
67+
@Override
68+
public Span addTag(final String key, final long value) {
69+
this.span.putAttribute(key, AttributeValue.longAttributeValue(value));
70+
return this;
71+
}
72+
73+
@Override
74+
public Span addTag(final String key, final double value) {
75+
this.span.putAttribute(key, AttributeValue.doubleAttributeValue(value));
76+
return this;
77+
}
78+
79+
@Override
80+
public Span addEvent(final String description) {
81+
this.span.addAnnotation(description);
82+
return this;
83+
}
84+
}

src/main/java/com/spotify/github/tracing/opencensus/OpenCensusTracer.java

Lines changed: 71 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -20,61 +20,89 @@
2020

2121
package com.spotify.github.tracing.opencensus;
2222

23+
import static io.opencensus.trace.Span.Kind.CLIENT;
24+
import static java.util.Objects.requireNonNull;
25+
2326
import com.spotify.github.tracing.BaseTracer;
2427
import com.spotify.github.tracing.Span;
28+
import com.spotify.github.tracing.TraceHelper;
2529
import io.opencensus.trace.Tracing;
26-
import okhttp3.Call;
27-
import okhttp3.OkHttpClient;
28-
import okhttp3.Request;
29-
import org.jetbrains.annotations.NotNull;
30-
30+
import java.io.IOException;
31+
import java.util.concurrent.CompletableFuture;
3132
import java.util.concurrent.CompletionStage;
32-
33-
import static io.opencensus.trace.AttributeValue.stringAttributeValue;
34-
import static io.opencensus.trace.Span.Kind.CLIENT;
35-
import static java.util.Objects.requireNonNull;
33+
import okhttp3.*;
34+
import org.jetbrains.annotations.NotNull;
3635

3736
public class OpenCensusTracer extends BaseTracer {
3837

39-
private static final io.opencensus.trace.Tracer TRACER = Tracing.getTracer();
38+
private static final io.opencensus.trace.Tracer TRACER = Tracing.getTracer();
4039

41-
@SuppressWarnings("MustBeClosedChecker")
42-
protected Span internalSpan(
43-
final String path,
44-
final String method,
45-
final CompletionStage<?> future) {
46-
requireNonNull(path);
40+
@SuppressWarnings("MustBeClosedChecker")
41+
protected Span internalSpan(
42+
final String path, final String method, final CompletionStage<?> future) {
43+
requireNonNull(path);
4744

48-
final io.opencensus.trace.Span ocSpan =
49-
TRACER.spanBuilder("GitHub Request").setSpanKind(CLIENT).startSpan();
45+
final io.opencensus.trace.Span ocSpan =
46+
TRACER.spanBuilder("GitHub Request").setSpanKind(CLIENT).startSpan();
5047

51-
ocSpan.putAttribute("component", stringAttributeValue("github-api-client"));
52-
ocSpan.putAttribute("peer.service", stringAttributeValue("github"));
53-
ocSpan.putAttribute("http.url", stringAttributeValue(path));
54-
ocSpan.putAttribute("method", stringAttributeValue(method));
55-
final Span span = new OpenCensusSpan(ocSpan);
48+
final Span span =
49+
new OpenCensusSpan(ocSpan)
50+
.addTag(TraceHelper.TraceTags.COMPONENT, "github-api-client")
51+
.addTag(TraceHelper.TraceTags.PEER_SERVICE, "github")
52+
.addTag(TraceHelper.TraceTags.HTTP_URL, path)
53+
.addTag(TraceHelper.TraceTags.HTTP_METHOD, method);
5654

57-
if (future != null) {
58-
attachSpanToFuture(span, future);
59-
}
60-
61-
return span;
55+
if (future != null) {
56+
attachSpanToFuture(span, future);
6257
}
6358

64-
@Override
65-
protected Span internalSpan(final Request request, final CompletionStage<?> future) {
66-
requireNonNull(request);
67-
return internalSpan(request.url().toString(), request.method(), future);
68-
}
59+
return span;
60+
}
6961

70-
@Override
71-
public Call.Factory createTracedClient(final OkHttpClient client) {
72-
return new Call.Factory() {
73-
@NotNull
74-
@Override
75-
public Call newCall(@NotNull final Request request) {
76-
return client.newCall(request);
77-
}
78-
};
79-
}
62+
@Override
63+
protected Span internalSpan(final Request request, final CompletionStage<?> future) {
64+
requireNonNull(request);
65+
return internalSpan(request.url().toString(), request.method(), future);
66+
}
67+
68+
@Override
69+
public Call.Factory createTracedClient(final OkHttpClient client) {
70+
return new Call.Factory() {
71+
@NotNull
72+
@Override
73+
public Call newCall(@NotNull final Request request) {
74+
CompletableFuture<Response> future = new CompletableFuture<>();
75+
Span span =
76+
internalSpan(request, future)
77+
.addTag(TraceHelper.TraceTags.HTTP_URL, request.url().toString());
78+
OkHttpClient.Builder okBuilder = client.newBuilder();
79+
okBuilder
80+
.networkInterceptors()
81+
.add(
82+
0,
83+
new Interceptor() {
84+
@NotNull
85+
@Override
86+
public Response intercept(@NotNull final Chain chain) throws IOException {
87+
try {
88+
Response response = chain.proceed(chain.request());
89+
span.addTag(TraceHelper.TraceTags.HTTP_STATUS_CODE, response.code())
90+
.addTag(TraceHelper.TraceTags.HTTP_STATUS_MESSAGE, response.message())
91+
.success();
92+
future.complete(response);
93+
return response;
94+
} catch (Exception ex) {
95+
span.failure(ex);
96+
future.completeExceptionally(ex);
97+
throw ex;
98+
} finally {
99+
span.close();
100+
}
101+
}
102+
});
103+
104+
return okBuilder.build().newCall(request);
105+
}
106+
};
107+
}
80108
}

0 commit comments

Comments
 (0)