diff --git a/google-http-client/src/main/java/com/google/api/client/http/HttpRequest.java b/google-http-client/src/main/java/com/google/api/client/http/HttpRequest.java index 82fcaf116..cfeda65b7 100644 --- a/google-http-client/src/main/java/com/google/api/client/http/HttpRequest.java +++ b/google-http-client/src/main/java/com/google/api/client/http/HttpRequest.java @@ -25,14 +25,11 @@ import com.google.api.client.util.StringUtils; import io.opencensus.common.Scope; -import io.opencensus.trace.Annotation; -import io.opencensus.trace.AttributeValue; import io.opencensus.trace.Span; import io.opencensus.trace.Tracer; import java.io.IOException; import java.io.InputStream; -import java.util.Collections; import java.util.concurrent.Callable; import java.util.concurrent.Executor; import java.util.concurrent.Executors; @@ -869,16 +866,8 @@ public HttpResponse execute() throws IOException { .spanBuilder(OpenCensusUtils.SPAN_NAME_HTTP_REQUEST_EXECUTE) .setRecordEvents(OpenCensusUtils.isRecordEvent()) .startSpan(); - long sentIdGenerator = 0L; - long recvIdGenerator = 0L; - do { - span.addAnnotation( - Annotation.fromDescriptionAndAttributes( - "retry", - Collections.singletonMap( - "number", - AttributeValue.longAttributeValue(numRetries - retriesRemaining)))); + span.addAnnotation("retry #" + (numRetries - retriesRemaining)); // Cleanup any unneeded response from a previous iteration if (response != null) { response.ignore(); @@ -922,7 +911,7 @@ public HttpResponse execute() throws IOException { headers.setUserAgent(originalUserAgent + " " + USER_AGENT_SUFFIX); } } - OpenCensusUtils.propagateTracingContext(span.getContext(), headers); + OpenCensusUtils.propagateTracingContext(span, headers); // headers HttpHeaders.serializeHeaders(headers, logbuf, curlbuf, logger, lowLevelHttpRequest); @@ -1006,13 +995,11 @@ public HttpResponse execute() throws IOException { // switch tracing scope to current span @SuppressWarnings("MustBeClosedChecker") Scope ws = tracer.withSpan(span); - OpenCensusUtils.recordSentMessageEvent( - span, sentIdGenerator++, lowLevelHttpRequest.getContentLength()); + OpenCensusUtils.recordSentMessageEvent(span, lowLevelHttpRequest.getContentLength()); try { LowLevelHttpResponse lowLevelHttpResponse = lowLevelHttpRequest.execute(); if (lowLevelHttpResponse != null) { - OpenCensusUtils.recordReceivedMessageEvent( - span, recvIdGenerator++, lowLevelHttpResponse.getContentLength()); + OpenCensusUtils.recordReceivedMessageEvent(span, lowLevelHttpResponse.getContentLength()); } // Flag used to indicate if an exception is thrown before the response is constructed. boolean responseConstructed = false; diff --git a/google-http-client/src/main/java/com/google/api/client/util/OpenCensusUtils.java b/google-http-client/src/main/java/com/google/api/client/util/OpenCensusUtils.java index 40f176a18..112612711 100644 --- a/google-http-client/src/main/java/com/google/api/client/util/OpenCensusUtils.java +++ b/google-http-client/src/main/java/com/google/api/client/util/OpenCensusUtils.java @@ -20,11 +20,11 @@ import com.google.common.annotations.VisibleForTesting; import io.opencensus.contrib.http.util.HttpPropagationUtil; +import io.opencensus.trace.BlankSpan; import io.opencensus.trace.EndSpanOptions; import io.opencensus.trace.NetworkEvent; import io.opencensus.trace.NetworkEvent.Type; import io.opencensus.trace.Span; -import io.opencensus.trace.SpanContext; import io.opencensus.trace.Status; import io.opencensus.trace.Tracer; import io.opencensus.trace.Tracing; @@ -57,6 +57,11 @@ public class OpenCensusUtils { */ private static Tracer tracer = Tracing.getTracer(); + /** + * Sequence id generator for message event. + */ + private static AtomicLong idGenerator = new AtomicLong(); + /** * Whether spans should be recorded locally. Defaults to true. */ @@ -132,18 +137,18 @@ public static boolean isRecordEvent() { } /** - * Propagate information of a given tracing context. This information will be injected into HTTP + * Propagate information of current tracing context. This information will be injected into HTTP * header. * - * @param spanContext the spanContext to be propagated. + * @param span the span to be propagated. * @param headers the headers used in propagation. */ - public static void propagateTracingContext(SpanContext spanContext, HttpHeaders headers) { - Preconditions.checkArgument(spanContext != null, "spanContext should not be null."); + public static void propagateTracingContext(Span span, HttpHeaders headers) { + Preconditions.checkArgument(span != null, "span should not be null."); Preconditions.checkArgument(headers != null, "headers should not be null."); if (propagationTextFormat != null && propagationTextFormatSetter != null) { - if (!spanContext.equals(SpanContext.INVALID)) { - propagationTextFormat.inject(spanContext, headers, propagationTextFormatSetter); + if (!span.equals(BlankSpan.INSTANCE)) { + propagationTextFormat.inject(span.getContext(), headers, propagationTextFormatSetter); } } } @@ -193,11 +198,10 @@ public static EndSpanOptions getEndSpanOptions(@Nullable Integer statusCode) { * represents the message size in application layer, i.e., content-length. * * @param span The {@code span} in which the send event occurs. - * @param id The id for the message, It is unique within an {@link HttpRequest}. * @param size Size of the request. */ - public static void recordSentMessageEvent(Span span, long id, long size) { - recordMessageEvent(span, id, size, Type.SENT); + public static void recordSentMessageEvent(Span span, long size) { + recordMessageEvent(span, size, Type.SENT); } /** @@ -205,11 +209,10 @@ public static void recordSentMessageEvent(Span span, long id, long size) { * represents the message size in application layer, i.e., content-length. * * @param span The {@code span} in which the receive event occurs. - * @param id The id for the message. It is unique within an {@link HttpRequest}. * @param size Size of the response. */ - public static void recordReceivedMessageEvent(Span span, long id, long size) { - recordMessageEvent(span, id, size, Type.RECV); + public static void recordReceivedMessageEvent(Span span, long size) { + recordMessageEvent(span, size, Type.RECV); } /** @@ -217,18 +220,17 @@ public static void recordReceivedMessageEvent(Span span, long id, long size) { * protected since {@link NetworkEvent} might be deprecated in future releases. * * @param span The {@code span} in which the event occurs. - * @param id The id for the message. * @param size Size of the message. * @param eventType The {@code NetworkEvent.Type} of the message event. */ @VisibleForTesting - static void recordMessageEvent(Span span, long id, long size, Type eventType) { + static void recordMessageEvent(Span span, long size, Type eventType) { Preconditions.checkArgument(span != null, "span should not be null."); if (size < 0) { size = 0; } NetworkEvent event = NetworkEvent - .builder(eventType, id) + .builder(eventType, idGenerator.getAndIncrement()) .setUncompressedMessageSize(size) .build(); span.addNetworkEvent(event); diff --git a/google-http-client/src/test/java/com/google/api/client/util/OpenCensusUtilsTest.java b/google-http-client/src/test/java/com/google/api/client/util/OpenCensusUtilsTest.java index 9868a1743..069b051ec 100644 --- a/google-http-client/src/test/java/com/google/api/client/util/OpenCensusUtilsTest.java +++ b/google-http-client/src/test/java/com/google/api/client/util/OpenCensusUtilsTest.java @@ -14,129 +14,166 @@ package com.google.api.client.util; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.mockito.Matchers.isA; -import static org.mockito.Matchers.same; -import static org.mockito.Mockito.verify; - import com.google.api.client.http.HttpHeaders; + +import io.opencensus.trace.BlankSpan; import io.opencensus.trace.EndSpanOptions; +import io.opencensus.trace.Annotation; +import io.opencensus.trace.AttributeValue; +import io.opencensus.trace.Link; import io.opencensus.trace.NetworkEvent; import io.opencensus.trace.Span; import io.opencensus.trace.SpanContext; -import io.opencensus.trace.SpanId; import io.opencensus.trace.Status; -import io.opencensus.trace.TraceId; -import io.opencensus.trace.TraceOptions; import io.opencensus.trace.Tracer; import io.opencensus.trace.propagation.TextFormat; -import java.util.Random; -import org.junit.After; -import org.junit.Before; +import java.util.List; +import java.util.Map; +import junit.framework.TestCase; +import org.junit.Assert; import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; /** * Tests {@link OpenCensusUtils}. * * @author Hailong Wen */ -@RunWith(JUnit4.class) -public class OpenCensusUtilsTest { - - @Rule public final ExpectedException thrown = ExpectedException.none(); - - @Mock TextFormat mockTextFormat; - @Mock TextFormat.Setter mockTextFormatSetter; - @Mock Span mockSpan; - TextFormat originTextFormat = OpenCensusUtils.propagationTextFormat; - TextFormat.Setter originTextFormatSetter = OpenCensusUtils.propagationTextFormatSetter; - HttpHeaders headers = new HttpHeaders(); - Tracer tracer = OpenCensusUtils.getTracer(); - Random random = new Random(1234); - SpanContext spanContext = SpanContext.create( - TraceId.generateRandomId(random), SpanId.generateRandomId(random), TraceOptions.DEFAULT); - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); +public class OpenCensusUtilsTest extends TestCase { + + TextFormat mockTextFormat; + TextFormat.Setter mockTextFormatSetter; + TextFormat originTextFormat; + TextFormat.Setter originTextFormatSetter; + Span mockSpan; + HttpHeaders headers; + Tracer tracer; + + public OpenCensusUtilsTest(String testName) { + super(testName); } - @After + @Override + public void setUp() { + mockTextFormat = new TextFormat() { + @Override + public List fields() { + throw new UnsupportedOperationException("TextFormat.fields"); + } + + @Override + public void inject(SpanContext spanContext, C carrier, Setter setter) { + throw new UnsupportedOperationException("TextFormat.inject"); + } + + @Override + public SpanContext extract(C carrier, Getter getter) { + throw new UnsupportedOperationException("TextFormat.extract"); + } + }; + mockTextFormatSetter = new TextFormat.Setter() { + @Override + public void put(HttpHeaders carrier, String key, String value) { + throw new UnsupportedOperationException("TextFormat.Setter.put"); + } + }; + headers = new HttpHeaders(); + tracer = OpenCensusUtils.getTracer(); + mockSpan = new Span(tracer.getCurrentSpan().getContext(), null) { + + @Override + public void addAnnotation(String description, Map attributes) {} + + @Override + public void addAnnotation(Annotation annotation) {} + + @Override + public void addNetworkEvent(NetworkEvent event) { + throw new UnsupportedOperationException("Span.addNetworkEvent"); + } + + @Override + public void addLink(Link link) {} + + @Override + public void end(EndSpanOptions options) {} + }; + originTextFormat = OpenCensusUtils.propagationTextFormat; + originTextFormatSetter = OpenCensusUtils.propagationTextFormatSetter; + } + + @Override public void tearDown() { OpenCensusUtils.setPropagationTextFormat(originTextFormat); OpenCensusUtils.setPropagationTextFormatSetter(originTextFormatSetter); } - @Test public void testInitializatoin() { assertNotNull(OpenCensusUtils.getTracer()); assertNotNull(OpenCensusUtils.propagationTextFormat); assertNotNull(OpenCensusUtils.propagationTextFormatSetter); } - @Test public void testSetPropagationTextFormat() { OpenCensusUtils.setPropagationTextFormat(mockTextFormat); assertEquals(mockTextFormat, OpenCensusUtils.propagationTextFormat); } - @Test public void testSetPropagationTextFormatSetter() { OpenCensusUtils.setPropagationTextFormatSetter(mockTextFormatSetter); assertEquals(mockTextFormatSetter, OpenCensusUtils.propagationTextFormatSetter); } - @Test public void testPropagateTracingContextInjection() { OpenCensusUtils.setPropagationTextFormat(mockTextFormat); - OpenCensusUtils.propagateTracingContext(spanContext, headers); - verify(mockTextFormat).inject(same(spanContext), same(headers), same(originTextFormatSetter)); + try { + OpenCensusUtils.propagateTracingContext(mockSpan, headers); + fail("expected " + UnsupportedOperationException.class); + } catch (UnsupportedOperationException e) { + assertEquals(e.getMessage(), "TextFormat.inject"); + } } - @Test public void testPropagateTracingContextHeader() { OpenCensusUtils.setPropagationTextFormatSetter(mockTextFormatSetter); - OpenCensusUtils.propagateTracingContext(spanContext, headers); - verify(mockTextFormatSetter).put(same(headers), isA(String.class), isA(String.class)); + try { + OpenCensusUtils.propagateTracingContext(mockSpan, headers); + fail("expected " + UnsupportedOperationException.class); + } catch (UnsupportedOperationException e) { + assertEquals(e.getMessage(), "TextFormat.Setter.put"); + } } - @Test public void testPropagateTracingContextNullSpan() { OpenCensusUtils.setPropagationTextFormat(mockTextFormat); - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("spanContext should not be null."); - OpenCensusUtils.propagateTracingContext(null, headers); + try { + OpenCensusUtils.propagateTracingContext(null, headers); + fail("expected " + IllegalArgumentException.class); + } catch (IllegalArgumentException e) { + assertEquals(e.getMessage(), "span should not be null."); + } } - @Test public void testPropagateTracingContextNullHeaders() { OpenCensusUtils.setPropagationTextFormat(mockTextFormat); - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("headers should not be null."); - OpenCensusUtils.propagateTracingContext(spanContext, null); + try { + OpenCensusUtils.propagateTracingContext(mockSpan, null); + fail("expected " + IllegalArgumentException.class); + } catch (IllegalArgumentException e) { + assertEquals(e.getMessage(), "headers should not be null."); + } } - @Test public void testPropagateTracingContextInvalidSpan() { OpenCensusUtils.setPropagationTextFormat(mockTextFormat); // No injection. No exceptions should be thrown. - OpenCensusUtils.propagateTracingContext(SpanContext.INVALID, headers); + OpenCensusUtils.propagateTracingContext(BlankSpan.INSTANCE, headers); } - @Test public void testGetEndSpanOptionsNoResponse() { EndSpanOptions expected = EndSpanOptions.builder().setStatus(Status.UNKNOWN).build(); assertEquals(expected, OpenCensusUtils.getEndSpanOptions(null)); } - @Test public void testGetEndSpanOptionsSuccess() { EndSpanOptions expected = EndSpanOptions.builder().setStatus(Status.OK).build(); assertEquals(expected, OpenCensusUtils.getEndSpanOptions(200)); @@ -144,44 +181,36 @@ public void testGetEndSpanOptionsSuccess() { assertEquals(expected, OpenCensusUtils.getEndSpanOptions(202)); } - @Test public void testGetEndSpanOptionsBadRequest() { EndSpanOptions expected = EndSpanOptions.builder().setStatus(Status.INVALID_ARGUMENT).build(); assertEquals(expected, OpenCensusUtils.getEndSpanOptions(400)); } - @Test public void testGetEndSpanOptionsUnauthorized() { EndSpanOptions expected = EndSpanOptions.builder().setStatus(Status.UNAUTHENTICATED).build(); assertEquals(expected, OpenCensusUtils.getEndSpanOptions(401)); } - @Test public void testGetEndSpanOptionsForbidden() { EndSpanOptions expected = EndSpanOptions.builder().setStatus(Status.PERMISSION_DENIED).build(); assertEquals(expected, OpenCensusUtils.getEndSpanOptions(403)); } - @Test public void testGetEndSpanOptionsNotFound() { EndSpanOptions expected = EndSpanOptions.builder().setStatus(Status.NOT_FOUND).build(); assertEquals(expected, OpenCensusUtils.getEndSpanOptions(404)); } - @Test public void testGetEndSpanOptionsPreconditionFailed() { - EndSpanOptions expected = EndSpanOptions.builder().setStatus(Status.FAILED_PRECONDITION) - .build(); + EndSpanOptions expected = EndSpanOptions.builder().setStatus(Status.FAILED_PRECONDITION).build(); assertEquals(expected, OpenCensusUtils.getEndSpanOptions(412)); } - @Test public void testGetEndSpanOptionsServerError() { EndSpanOptions expected = EndSpanOptions.builder().setStatus(Status.UNAVAILABLE).build(); assertEquals(expected, OpenCensusUtils.getEndSpanOptions(500)); } - @Test public void testGetEndSpanOptionsOther() { EndSpanOptions expected = EndSpanOptions.builder().setStatus(Status.UNKNOWN).build(); // test some random unsupported statuses @@ -190,16 +219,21 @@ public void testGetEndSpanOptionsOther() { assertEquals(expected, OpenCensusUtils.getEndSpanOptions(501)); } - @Test public void testRecordMessageEventInNullSpan() { - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("span should not be null."); - OpenCensusUtils.recordMessageEvent(null, 0, 0, NetworkEvent.Type.SENT); + try { + OpenCensusUtils.recordMessageEvent(null, 0, NetworkEvent.Type.SENT); + fail("expected " + IllegalArgumentException.class); + } catch (IllegalArgumentException e) { + assertEquals(e.getMessage(), "span should not be null."); + } } - @Test public void testRecordMessageEvent() { - OpenCensusUtils.recordMessageEvent(mockSpan, 0, 0, NetworkEvent.Type.SENT); - verify(mockSpan).addNetworkEvent(isA(NetworkEvent.class)); + try { + OpenCensusUtils.recordMessageEvent(mockSpan, 0, NetworkEvent.Type.SENT); + fail("expected " + UnsupportedOperationException.class); + } catch (UnsupportedOperationException e) { + assertEquals(e.getMessage(), "Span.addNetworkEvent"); + } } }