diff --git a/google-http-client/pom.xml b/google-http-client/pom.xml
index 69bf450f4..81414b925 100644
--- a/google-http-client/pom.xml
+++ b/google-http-client/pom.xml
@@ -175,7 +175,14 @@
com.google.j2objc
j2objc-annotations
- 1.1
+
+
+ io.opencensus
+ opencensus-api
+
+
+ io.opencensus
+ opencensus-contrib-http-util
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 856666a68..1c68d9036 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
@@ -18,11 +18,18 @@
import com.google.api.client.util.IOUtils;
import com.google.api.client.util.LoggingStreamingContent;
import com.google.api.client.util.ObjectParser;
+import com.google.api.client.util.OpenCensusUtils;
import com.google.api.client.util.Preconditions;
import com.google.api.client.util.Sleeper;
import com.google.api.client.util.StreamingContent;
import com.google.api.client.util.StringUtils;
+import io.opencensus.common.Scope;
+import io.opencensus.contrib.http.util.HttpTraceAttributeConstants;
+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.concurrent.Callable;
@@ -215,6 +222,9 @@ static String executeAndGetValueOfSomeCustomHeader(HttpRequest request) {
/** Sleeper. */
private Sleeper sleeper = Sleeper.DEFAULT;
+ /** OpenCensus tracing component. */
+ private Tracer tracer = OpenCensusUtils.getTracer();
+
/**
* @param transport HTTP transport
* @param requestMethod HTTP request method or {@code null} for none
@@ -883,7 +893,12 @@ public HttpResponse execute() throws IOException {
Preconditions.checkNotNull(requestMethod);
Preconditions.checkNotNull(url);
+ Span span = tracer
+ .spanBuilder(OpenCensusUtils.SPAN_NAME_HTTP_REQUEST_EXECUTE)
+ .setRecordEvents(OpenCensusUtils.isRecordEvent())
+ .startSpan();
do {
+ span.addAnnotation("retry #" + (numRetries - retriesRemaining));
// Cleanup any unneeded response from a previous iteration
if (response != null) {
response.ignore();
@@ -898,6 +913,11 @@ public HttpResponse execute() throws IOException {
}
// build low-level HTTP request
String urlString = url.build();
+ addSpanAttribute(span, HttpTraceAttributeConstants.HTTP_METHOD, requestMethod);
+ addSpanAttribute(span, HttpTraceAttributeConstants.HTTP_HOST, url.getHost());
+ addSpanAttribute(span, HttpTraceAttributeConstants.HTTP_PATH, url.getRawPath());
+ addSpanAttribute(span, HttpTraceAttributeConstants.HTTP_URL, urlString);
+
LowLevelHttpRequest lowLevelHttpRequest = transport.buildRequest(requestMethod, urlString);
Logger logger = HttpTransport.LOGGER;
boolean loggable = loggingEnabled && logger.isLoggable(Level.CONFIG);
@@ -923,10 +943,15 @@ public HttpResponse execute() throws IOException {
if (!suppressUserAgentSuffix) {
if (originalUserAgent == null) {
headers.setUserAgent(USER_AGENT_SUFFIX);
+ addSpanAttribute(span, HttpTraceAttributeConstants.HTTP_USER_AGENT, USER_AGENT_SUFFIX);
} else {
- headers.setUserAgent(originalUserAgent + " " + USER_AGENT_SUFFIX);
+ String newUserAgent = originalUserAgent + " " + USER_AGENT_SUFFIX;
+ headers.setUserAgent(newUserAgent);
+ addSpanAttribute(span, HttpTraceAttributeConstants.HTTP_USER_AGENT, newUserAgent);
}
}
+ OpenCensusUtils.propagateTracingContext(span, headers);
+
// headers
HttpHeaders.serializeHeaders(headers, logbuf, curlbuf, logger, lowLevelHttpRequest);
if (!suppressUserAgentSuffix) {
@@ -1007,8 +1032,16 @@ public HttpResponse execute() throws IOException {
// execute
lowLevelHttpRequest.setTimeout(connectTimeout, readTimeout);
lowLevelHttpRequest.setWriteTimeout(writeTimeout);
+
+ // switch tracing scope to current span
+ @SuppressWarnings("MustBeClosedChecker")
+ Scope ws = tracer.withSpan(span);
+ OpenCensusUtils.recordSentMessageEvent(span, lowLevelHttpRequest.getContentLength());
try {
LowLevelHttpResponse lowLevelHttpResponse = lowLevelHttpRequest.execute();
+ if (lowLevelHttpResponse != null) {
+ OpenCensusUtils.recordReceivedMessageEvent(span, lowLevelHttpResponse.getContentLength());
+ }
// Flag used to indicate if an exception is thrown before the response is constructed.
boolean responseConstructed = false;
try {
@@ -1032,6 +1065,8 @@ public HttpResponse execute() throws IOException {
if (loggable) {
logger.log(Level.WARNING, "exception thrown while executing request", e);
}
+ } finally {
+ ws.close();
}
// Flag used to indicate if an exception is thrown before the response has completed
@@ -1087,6 +1122,7 @@ public HttpResponse execute() throws IOException {
}
}
} while (retryRequest);
+ span.end(OpenCensusUtils.getEndSpanOptions(response == null ? null : response.getStatusCode()));
if (response == null) {
// Retries did not help resolve the execute exception, re-throw it.
@@ -1201,4 +1237,10 @@ public HttpRequest setSleeper(Sleeper sleeper) {
this.sleeper = Preconditions.checkNotNull(sleeper);
return this;
}
+
+ private static void addSpanAttribute(Span span, String key, String value) {
+ if (value != null) {
+ span.putAttribute(key, AttributeValue.stringAttributeValue(value));
+ }
+ }
}
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
new file mode 100644
index 000000000..c2a2cc000
--- /dev/null
+++ b/google-http-client/src/main/java/com/google/api/client/util/OpenCensusUtils.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2018 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.api.client.util;
+
+import com.google.api.client.http.HttpHeaders;
+import com.google.api.client.http.HttpRequest;
+import com.google.api.client.http.HttpStatusCodes;
+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.Status;
+import io.opencensus.trace.Tracer;
+import io.opencensus.trace.Tracing;
+import io.opencensus.trace.propagation.TextFormat;
+
+import java.util.Collections;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.annotation.Nullable;
+
+/**
+ * Utilities for Census monitoring and tracing.
+ *
+ * @author Hailong Wen
+ * @since 1.24
+ */
+public class OpenCensusUtils {
+
+ private static final Logger logger = Logger.getLogger(OpenCensusUtils.class.getName());
+
+ /**
+ * Span name for tracing {@link HttpRequest#execute()}.
+ */
+ public static final String SPAN_NAME_HTTP_REQUEST_EXECUTE =
+ "Sent." + HttpRequest.class.getName() + ".execute";
+
+ /**
+ * OpenCensus tracing component. When no OpenCensus implementation is provided, it will return a
+ * no-op tracer.
+ */
+ 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.
+ */
+ private static volatile boolean isRecordEvent = true;
+
+ /**
+ * {@link TextFormat} used in tracing context propagation.
+ */
+ @Nullable
+ @VisibleForTesting
+ static volatile TextFormat propagationTextFormat = null;
+
+ /**
+ * {@link TextFormat.Setter} for {@link #propagationTextFormat}.
+ */
+ @Nullable
+ @VisibleForTesting
+ static volatile TextFormat.Setter propagationTextFormatSetter = null;
+
+ /**
+ * Sets the {@link TextFormat} used in context propagation.
+ *
+ *
This API allows users of google-http-client to specify other text format, or disable context
+ * propagation by setting it to {@code null}. It should be used along with {@link
+ * #setPropagationTextFormatSetter} for setting purpose.
+ *
+ * @param textFormat the text format.
+ */
+ public static void setPropagationTextFormat(@Nullable TextFormat textFormat) {
+ propagationTextFormat = textFormat;
+ }
+
+ /**
+ * Sets the {@link TextFormat.Setter} used in context propagation.
+ *
+ * This API allows users of google-http-client to specify other text format setter, or disable
+ * context propagation by setting it to {@code null}. It should be used along with {@link
+ * #setPropagationTextFormat} for setting purpose.
+ *
+ * @param textFormatSetter the {@code TextFormat.Setter} for the text format.
+ */
+ public static void setPropagationTextFormatSetter(@Nullable TextFormat.Setter textFormatSetter) {
+ propagationTextFormatSetter = textFormatSetter;
+ }
+
+ /**
+ * Sets whether spans should be recorded locally.
+ *
+ * This API allows users of google-http-client to turn on/off local span collection.
+ *
+ * @param recordEvent record span locally if true.
+ */
+ public static void setIsRecordEvent(boolean recordEvent) {
+ isRecordEvent = recordEvent;
+ }
+
+ /**
+ * Returns the tracing component of OpenCensus.
+ *
+ * @return the tracing component of OpenCensus.
+ */
+ public static Tracer getTracer() {
+ return tracer;
+ }
+
+ /**
+ * Returns whether spans should be recorded locally.
+ *
+ * @return whether spans should be recorded locally.
+ */
+ public static boolean isRecordEvent() {
+ return isRecordEvent;
+ }
+
+ /**
+ * Propagate information of current tracing context. This information will be injected into HTTP
+ * header.
+ *
+ * @param span the span to be propagated.
+ * @param headers the headers used in propagation.
+ */
+ 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 (!span.equals(BlankSpan.INSTANCE)) {
+ propagationTextFormat.inject(span.getContext(), headers, propagationTextFormatSetter);
+ }
+ }
+ }
+
+ /**
+ * Returns an {@link EndSpanOptions} to end a http span according to the status code.
+ *
+ * @param statusCode the status code, can be null to represent no valid response is returned.
+ * @return an {@code EndSpanOptions} that best suits the status code.
+ */
+ public static EndSpanOptions getEndSpanOptions(@Nullable Integer statusCode) {
+ // Always sample the span, but optionally export it.
+ EndSpanOptions.Builder builder = EndSpanOptions.builder();
+ if (statusCode == null) {
+ builder.setStatus(Status.UNKNOWN);
+ } else if (!HttpStatusCodes.isSuccess(statusCode)) {
+ switch (statusCode) {
+ case HttpStatusCodes.STATUS_CODE_BAD_REQUEST:
+ builder.setStatus(Status.INVALID_ARGUMENT);
+ break;
+ case HttpStatusCodes.STATUS_CODE_UNAUTHORIZED:
+ builder.setStatus(Status.UNAUTHENTICATED);
+ break;
+ case HttpStatusCodes.STATUS_CODE_FORBIDDEN:
+ builder.setStatus(Status.PERMISSION_DENIED);
+ break;
+ case HttpStatusCodes.STATUS_CODE_NOT_FOUND:
+ builder.setStatus(Status.NOT_FOUND);
+ break;
+ case HttpStatusCodes.STATUS_CODE_PRECONDITION_FAILED:
+ builder.setStatus(Status.FAILED_PRECONDITION);
+ break;
+ case HttpStatusCodes.STATUS_CODE_SERVER_ERROR:
+ builder.setStatus(Status.UNAVAILABLE);
+ break;
+ default:
+ builder.setStatus(Status.UNKNOWN);
+ }
+ } else {
+ builder.setStatus(Status.OK);
+ }
+ return builder.build();
+ }
+
+ /**
+ * Records a new message event which contains the size of the request content. Note that the size
+ * represents the message size in application layer, i.e., content-length.
+ *
+ * @param span The {@code span} in which the send event occurs.
+ * @param size Size of the request.
+ */
+ public static void recordSentMessageEvent(Span span, long size) {
+ recordMessageEvent(span, size, Type.SENT);
+ }
+
+ /**
+ * Records a new message event which contains the size of the response content. Note that the size
+ * represents the message size in application layer, i.e., content-length.
+ *
+ * @param span The {@code span} in which the receive event occurs.
+ * @param size Size of the response.
+ */
+ public static void recordReceivedMessageEvent(Span span, long size) {
+ recordMessageEvent(span, size, Type.RECV);
+ }
+
+ /**
+ * Records a message event of a certain {@link NetworkEvent.Type}. This method is package
+ * protected since {@link NetworkEvent} might be deprecated in future releases.
+ *
+ * @param span The {@code span} in which the event occurs.
+ * @param size Size of the message.
+ * @param eventType The {@code NetworkEvent.Type} of the message event.
+ */
+ @VisibleForTesting
+ 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, idGenerator.getAndIncrement())
+ .setUncompressedMessageSize(size)
+ .build();
+ span.addNetworkEvent(event);
+ }
+
+ static {
+ try {
+ propagationTextFormat = HttpPropagationUtil.getCloudTraceFormat();
+ propagationTextFormatSetter = new TextFormat.Setter() {
+ @Override
+ public void put(HttpHeaders carrier, String key, String value) {
+ carrier.set(key, value);
+ }
+ };
+ } catch (Exception e) {
+ logger.log(
+ Level.WARNING, "Cannot initialize default OpenCensus HTTP propagation text format.", e);
+ }
+
+ try {
+ Tracing.getExportComponent().getSampledSpanStore().registerSpanNamesForCollection(
+ Collections.singletonList(SPAN_NAME_HTTP_REQUEST_EXECUTE));
+ } catch (Exception e) {
+ logger.log(
+ Level.WARNING, "Cannot register default OpenCensus span names for collection.", e);
+ }
+ }
+
+ private OpenCensusUtils() {}
+}
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
new file mode 100644
index 000000000..069b051ec
--- /dev/null
+++ b/google-http-client/src/test/java/com/google/api/client/util/OpenCensusUtilsTest.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2018 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.api.client.util;
+
+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.Status;
+import io.opencensus.trace.Tracer;
+import io.opencensus.trace.propagation.TextFormat;
+import java.util.List;
+import java.util.Map;
+import junit.framework.TestCase;
+import org.junit.Assert;
+import org.junit.Rule;
+
+/**
+ * Tests {@link OpenCensusUtils}.
+ *
+ * @author Hailong Wen
+ */
+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);
+ }
+
+ @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);
+ }
+
+ public void testInitializatoin() {
+ assertNotNull(OpenCensusUtils.getTracer());
+ assertNotNull(OpenCensusUtils.propagationTextFormat);
+ assertNotNull(OpenCensusUtils.propagationTextFormatSetter);
+ }
+
+ public void testSetPropagationTextFormat() {
+ OpenCensusUtils.setPropagationTextFormat(mockTextFormat);
+ assertEquals(mockTextFormat, OpenCensusUtils.propagationTextFormat);
+ }
+
+ public void testSetPropagationTextFormatSetter() {
+ OpenCensusUtils.setPropagationTextFormatSetter(mockTextFormatSetter);
+ assertEquals(mockTextFormatSetter, OpenCensusUtils.propagationTextFormatSetter);
+ }
+
+ public void testPropagateTracingContextInjection() {
+ OpenCensusUtils.setPropagationTextFormat(mockTextFormat);
+ try {
+ OpenCensusUtils.propagateTracingContext(mockSpan, headers);
+ fail("expected " + UnsupportedOperationException.class);
+ } catch (UnsupportedOperationException e) {
+ assertEquals(e.getMessage(), "TextFormat.inject");
+ }
+ }
+
+ public void testPropagateTracingContextHeader() {
+ OpenCensusUtils.setPropagationTextFormatSetter(mockTextFormatSetter);
+ try {
+ OpenCensusUtils.propagateTracingContext(mockSpan, headers);
+ fail("expected " + UnsupportedOperationException.class);
+ } catch (UnsupportedOperationException e) {
+ assertEquals(e.getMessage(), "TextFormat.Setter.put");
+ }
+ }
+
+ public void testPropagateTracingContextNullSpan() {
+ OpenCensusUtils.setPropagationTextFormat(mockTextFormat);
+ try {
+ OpenCensusUtils.propagateTracingContext(null, headers);
+ fail("expected " + IllegalArgumentException.class);
+ } catch (IllegalArgumentException e) {
+ assertEquals(e.getMessage(), "span should not be null.");
+ }
+ }
+
+ public void testPropagateTracingContextNullHeaders() {
+ OpenCensusUtils.setPropagationTextFormat(mockTextFormat);
+ try {
+ OpenCensusUtils.propagateTracingContext(mockSpan, null);
+ fail("expected " + IllegalArgumentException.class);
+ } catch (IllegalArgumentException e) {
+ assertEquals(e.getMessage(), "headers should not be null.");
+ }
+ }
+
+ public void testPropagateTracingContextInvalidSpan() {
+ OpenCensusUtils.setPropagationTextFormat(mockTextFormat);
+ // No injection. No exceptions should be thrown.
+ OpenCensusUtils.propagateTracingContext(BlankSpan.INSTANCE, headers);
+ }
+
+ public void testGetEndSpanOptionsNoResponse() {
+ EndSpanOptions expected = EndSpanOptions.builder().setStatus(Status.UNKNOWN).build();
+ assertEquals(expected, OpenCensusUtils.getEndSpanOptions(null));
+ }
+
+ public void testGetEndSpanOptionsSuccess() {
+ EndSpanOptions expected = EndSpanOptions.builder().setStatus(Status.OK).build();
+ assertEquals(expected, OpenCensusUtils.getEndSpanOptions(200));
+ assertEquals(expected, OpenCensusUtils.getEndSpanOptions(201));
+ assertEquals(expected, OpenCensusUtils.getEndSpanOptions(202));
+ }
+
+ public void testGetEndSpanOptionsBadRequest() {
+ EndSpanOptions expected = EndSpanOptions.builder().setStatus(Status.INVALID_ARGUMENT).build();
+ assertEquals(expected, OpenCensusUtils.getEndSpanOptions(400));
+ }
+
+ public void testGetEndSpanOptionsUnauthorized() {
+ EndSpanOptions expected = EndSpanOptions.builder().setStatus(Status.UNAUTHENTICATED).build();
+ assertEquals(expected, OpenCensusUtils.getEndSpanOptions(401));
+ }
+
+ public void testGetEndSpanOptionsForbidden() {
+ EndSpanOptions expected = EndSpanOptions.builder().setStatus(Status.PERMISSION_DENIED).build();
+ assertEquals(expected, OpenCensusUtils.getEndSpanOptions(403));
+ }
+
+ public void testGetEndSpanOptionsNotFound() {
+ EndSpanOptions expected = EndSpanOptions.builder().setStatus(Status.NOT_FOUND).build();
+ assertEquals(expected, OpenCensusUtils.getEndSpanOptions(404));
+ }
+
+ public void testGetEndSpanOptionsPreconditionFailed() {
+ EndSpanOptions expected = EndSpanOptions.builder().setStatus(Status.FAILED_PRECONDITION).build();
+ assertEquals(expected, OpenCensusUtils.getEndSpanOptions(412));
+ }
+
+ public void testGetEndSpanOptionsServerError() {
+ EndSpanOptions expected = EndSpanOptions.builder().setStatus(Status.UNAVAILABLE).build();
+ assertEquals(expected, OpenCensusUtils.getEndSpanOptions(500));
+ }
+
+ public void testGetEndSpanOptionsOther() {
+ EndSpanOptions expected = EndSpanOptions.builder().setStatus(Status.UNKNOWN).build();
+ // test some random unsupported statuses
+ assertEquals(expected, OpenCensusUtils.getEndSpanOptions(301));
+ assertEquals(expected, OpenCensusUtils.getEndSpanOptions(402));
+ assertEquals(expected, OpenCensusUtils.getEndSpanOptions(501));
+ }
+
+ public void testRecordMessageEventInNullSpan() {
+ try {
+ OpenCensusUtils.recordMessageEvent(null, 0, NetworkEvent.Type.SENT);
+ fail("expected " + IllegalArgumentException.class);
+ } catch (IllegalArgumentException e) {
+ assertEquals(e.getMessage(), "span should not be null.");
+ }
+ }
+
+ public void testRecordMessageEvent() {
+ try {
+ OpenCensusUtils.recordMessageEvent(mockSpan, 0, NetworkEvent.Type.SENT);
+ fail("expected " + UnsupportedOperationException.class);
+ } catch (UnsupportedOperationException e) {
+ assertEquals(e.getMessage(), "Span.addNetworkEvent");
+ }
+ }
+}
diff --git a/pom.xml b/pom.xml
index 3794f581a..56c870e1b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -268,6 +268,16 @@
j2objc-annotations
1.1
+
+ io.opencensus
+ opencensus-api
+ ${project.opencensus.version}
+
+
+ io.opencensus
+ opencensus-contrib-http-util
+ ${project.opencensus.version}
+
@@ -550,6 +560,7 @@
3.2.1
3.2.1
4.0.3
+ 0.18.0