aboutsummaryrefslogtreecommitdiff
path: root/contrib/http_util/src
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/http_util/src')
-rw-r--r--contrib/http_util/src/main/java/io/opencensus/contrib/http/util/CloudTraceFormat.java149
-rw-r--r--contrib/http_util/src/main/java/io/opencensus/contrib/http/util/HttpMeasureConstants.java175
-rw-r--r--contrib/http_util/src/main/java/io/opencensus/contrib/http/util/HttpPropagationUtil.java41
-rw-r--r--contrib/http_util/src/main/java/io/opencensus/contrib/http/util/HttpViewConstants.java190
-rw-r--r--contrib/http_util/src/main/java/io/opencensus/contrib/http/util/HttpViews.java103
-rw-r--r--contrib/http_util/src/test/java/io/opencensus/contrib/http/util/CloudTraceFormatTest.java295
-rw-r--r--contrib/http_util/src/test/java/io/opencensus/contrib/http/util/HttpMeasureConstantsTest.java67
-rw-r--r--contrib/http_util/src/test/java/io/opencensus/contrib/http/util/HttpPropagationUtilTest.java36
-rw-r--r--contrib/http_util/src/test/java/io/opencensus/contrib/http/util/HttpViewConstantsTest.java148
-rw-r--r--contrib/http_util/src/test/java/io/opencensus/contrib/http/util/HttpViewsTest.java67
10 files changed, 1271 insertions, 0 deletions
diff --git a/contrib/http_util/src/main/java/io/opencensus/contrib/http/util/CloudTraceFormat.java b/contrib/http_util/src/main/java/io/opencensus/contrib/http/util/CloudTraceFormat.java
new file mode 100644
index 00000000..77faa9f9
--- /dev/null
+++ b/contrib/http_util/src/main/java/io/opencensus/contrib/http/util/CloudTraceFormat.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2017, OpenCensus Authors
+ *
+ * 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 io.opencensus.contrib.http.util;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.primitives.UnsignedInts;
+import com.google.common.primitives.UnsignedLongs;
+import io.opencensus.trace.SpanContext;
+import io.opencensus.trace.SpanId;
+import io.opencensus.trace.TraceId;
+import io.opencensus.trace.TraceOptions;
+import io.opencensus.trace.Tracestate;
+import io.opencensus.trace.propagation.SpanContextParseException;
+import io.opencensus.trace.propagation.TextFormat;
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.List;
+
+/*>>>
+import org.checkerframework.checker.nullness.qual.NonNull;
+*/
+
+/**
+ * Implementation of the "X-Cloud-Trace-Context" format, defined by the Google Cloud Trace.
+ *
+ * <p>The supported format is the following:
+ *
+ * <pre>
+ * &lt;TRACE_ID&gt;/&lt;SPAN_ID&gt;[;o=&lt;TRACE_OPTIONS&gt;]
+ * </pre>
+ *
+ * <ul>
+ * <li>TRACE_ID is a 32-character hex value;
+ * <li>SPAN_ID is a decimal representation of a 64-bit unsigned long;
+ * <li>TRACE_OPTIONS is a decimal representation of a 32-bit unsigned integer. The least
+ * significant bit defines whether a request is traced (1 - enabled, 0 - disabled). Behaviors
+ * of other bits are currently undefined. This value is optional. Although upstream service
+ * may leave this value unset to leave the sampling decision up to downstream client, this
+ * utility will always default it to 0 if absent.
+ * </ul>
+ *
+ * <p>Valid values:
+ *
+ * <ul>
+ * <li>"105445aa7843bc8bf206b120001000/123;o=1"
+ * <li>"105445aa7843bc8bf206b120001000/123"
+ * <li>"105445aa7843bc8bf206b120001000/123;o=0"
+ * </ul>
+ */
+final class CloudTraceFormat extends TextFormat {
+ static final String HEADER_NAME = "X-Cloud-Trace-Context";
+ static final List<String> FIELDS = Collections.singletonList(HEADER_NAME);
+ static final char SPAN_ID_DELIMITER = '/';
+ static final String TRACE_OPTION_DELIMITER = ";o=";
+ static final String SAMPLED = "1";
+ static final String NOT_SAMPLED = "0";
+ static final TraceOptions OPTIONS_SAMPLED = TraceOptions.builder().setIsSampled(true).build();
+ static final TraceOptions OPTIONS_NOT_SAMPLED = TraceOptions.DEFAULT;
+ static final int TRACE_ID_SIZE = 2 * TraceId.SIZE;
+ static final int TRACE_OPTION_DELIMITER_SIZE = TRACE_OPTION_DELIMITER.length();
+ static final int SPAN_ID_START_POS = TRACE_ID_SIZE + 1;
+ // 32-digit TRACE_ID + 1 digit SPAN_ID_DELIMITER + at least 1 digit SPAN_ID
+ static final int MIN_HEADER_SIZE = SPAN_ID_START_POS + 1;
+ static final int CLOUD_TRACE_IS_SAMPLED = 0x1;
+ private static final Tracestate TRACESTATE_DEFAULT = Tracestate.builder().build();
+
+ @Override
+ public List<String> fields() {
+ return FIELDS;
+ }
+
+ @Override
+ public <C /*>>> extends @NonNull Object*/> void inject(
+ SpanContext spanContext, C carrier, Setter<C> setter) {
+ checkNotNull(spanContext, "spanContext");
+ checkNotNull(setter, "setter");
+ checkNotNull(carrier, "carrier");
+ StringBuilder builder =
+ new StringBuilder()
+ .append(spanContext.getTraceId().toLowerBase16())
+ .append(SPAN_ID_DELIMITER)
+ .append(UnsignedLongs.toString(spanIdToLong(spanContext.getSpanId())))
+ .append(TRACE_OPTION_DELIMITER)
+ .append(spanContext.getTraceOptions().isSampled() ? SAMPLED : NOT_SAMPLED);
+
+ setter.put(carrier, HEADER_NAME, builder.toString());
+ }
+
+ @Override
+ public <C /*>>> extends @NonNull Object*/> SpanContext extract(C carrier, Getter<C> getter)
+ throws SpanContextParseException {
+ checkNotNull(carrier, "carrier");
+ checkNotNull(getter, "getter");
+ try {
+ String headerStr = getter.get(carrier, HEADER_NAME);
+ if (headerStr == null || headerStr.length() < MIN_HEADER_SIZE) {
+ throw new SpanContextParseException("Missing or too short header: " + HEADER_NAME);
+ }
+ checkArgument(headerStr.charAt(TRACE_ID_SIZE) == SPAN_ID_DELIMITER, "Invalid TRACE_ID size");
+
+ TraceId traceId = TraceId.fromLowerBase16(headerStr.subSequence(0, TRACE_ID_SIZE));
+ int traceOptionsPos = headerStr.indexOf(TRACE_OPTION_DELIMITER, TRACE_ID_SIZE);
+ CharSequence spanIdStr =
+ headerStr.subSequence(
+ SPAN_ID_START_POS, traceOptionsPos < 0 ? headerStr.length() : traceOptionsPos);
+ SpanId spanId = longToSpanId(UnsignedLongs.parseUnsignedLong(spanIdStr.toString(), 10));
+ TraceOptions traceOptions = OPTIONS_NOT_SAMPLED;
+ if (traceOptionsPos > 0) {
+ String traceOptionsStr = headerStr.substring(traceOptionsPos + TRACE_OPTION_DELIMITER_SIZE);
+ if ((UnsignedInts.parseUnsignedInt(traceOptionsStr, 10) & CLOUD_TRACE_IS_SAMPLED) != 0) {
+ traceOptions = OPTIONS_SAMPLED;
+ }
+ }
+ return SpanContext.create(traceId, spanId, traceOptions, TRACESTATE_DEFAULT);
+ } catch (IllegalArgumentException e) {
+ throw new SpanContextParseException("Invalid input", e);
+ }
+ }
+
+ // Using big-endian encoding.
+ private static SpanId longToSpanId(long x) {
+ ByteBuffer buffer = ByteBuffer.allocate(SpanId.SIZE);
+ buffer.putLong(x);
+ return SpanId.fromBytes(buffer.array());
+ }
+
+ // Using big-endian encoding.
+ private static long spanIdToLong(SpanId spanId) {
+ ByteBuffer buffer = ByteBuffer.allocate(SpanId.SIZE);
+ buffer.put(spanId.getBytes());
+ return buffer.getLong(0);
+ }
+}
diff --git a/contrib/http_util/src/main/java/io/opencensus/contrib/http/util/HttpMeasureConstants.java b/contrib/http_util/src/main/java/io/opencensus/contrib/http/util/HttpMeasureConstants.java
new file mode 100644
index 00000000..fd73b8a9
--- /dev/null
+++ b/contrib/http_util/src/main/java/io/opencensus/contrib/http/util/HttpMeasureConstants.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2018, OpenCensus Authors
+ *
+ * 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 io.opencensus.contrib.http.util;
+
+import io.opencensus.stats.Measure;
+import io.opencensus.stats.Measure.MeasureDouble;
+import io.opencensus.stats.Measure.MeasureLong;
+import io.opencensus.tags.TagKey;
+
+/**
+ * A helper class which holds OpenCensus's default HTTP {@link Measure}s and {@link TagKey}s.
+ *
+ * <p>{@link Measure}s and {@link TagKey}s in this class are all public for other
+ * libraries/frameworks to reference and use.
+ *
+ * @since 0.13
+ */
+public final class HttpMeasureConstants {
+
+ private HttpMeasureConstants() {}
+
+ private static final String UNIT_COUNT = "1";
+ private static final String UNIT_SIZE_BYTE = "By";
+ private static final String UNIT_LATENCY_MS = "ms";
+
+ /**
+ * {@link Measure} for the client-side total bytes sent in request body (not including headers).
+ * This is uncompressed bytes.
+ *
+ * @since 0.13
+ */
+ public static final MeasureLong HTTP_CLIENT_SENT_BYTES =
+ Measure.MeasureLong.create(
+ "opencensus.io/http/client/sent_bytes",
+ "Client-side total bytes sent in request body (uncompressed)",
+ UNIT_SIZE_BYTE);
+
+ /**
+ * {@link Measure} for the client-side total bytes received in response bodies (not including
+ * headers but including error responses with bodies). Should be measured from actual bytes
+ * received and read, not the value of the Content-Length header. This is uncompressed bytes.
+ * Responses with no body should record 0 for this value.
+ *
+ * @since 0.13
+ */
+ public static final MeasureLong HTTP_CLIENT_RECEIVED_BYTES =
+ Measure.MeasureLong.create(
+ "opencensus.io/http/client/received_bytes",
+ "Client-side total bytes received in response bodies (uncompressed)",
+ UNIT_SIZE_BYTE);
+
+ /**
+ * {@link Measure} for the client-side time between first byte of request headers sent to last
+ * byte of response received, or terminal error.
+ *
+ * @since 0.13
+ */
+ public static final MeasureDouble HTTP_CLIENT_ROUNDTRIP_LATENCY =
+ Measure.MeasureDouble.create(
+ "opencensus.io/http/client/roundtrip_latency",
+ "Client-side time between first byte of request headers sent to last byte of response "
+ + "received, or terminal error",
+ UNIT_LATENCY_MS);
+
+ /**
+ * {@link Measure} for the server-side total bytes received in request body (not including
+ * headers). This is uncompressed bytes.
+ *
+ * @since 0.13
+ */
+ public static final MeasureLong HTTP_SERVER_RECEIVED_BYTES =
+ Measure.MeasureLong.create(
+ "opencensus.io/http/server/received_bytes",
+ "Server-side total bytes received in request body (uncompressed)",
+ UNIT_SIZE_BYTE);
+
+ /**
+ * {@link Measure} for the server-side total bytes sent in response bodies (not including headers
+ * but including error responses with bodies). Should be measured from actual bytes written and
+ * sent, not the value of the Content-Length header. This is uncompressed bytes. Responses with no
+ * body should record 0 for this value.
+ *
+ * @since 0.13
+ */
+ public static final MeasureLong HTTP_SERVER_SENT_BYTES =
+ Measure.MeasureLong.create(
+ "opencensus.io/http/server/sent_bytes",
+ "Server-side total bytes sent in response bodies (uncompressed)",
+ UNIT_SIZE_BYTE);
+
+ /**
+ * {@link Measure} for the server-side time between first byte of request headers received to last
+ * byte of response sent, or terminal error.
+ *
+ * @since 0.13
+ */
+ public static final MeasureDouble HTTP_SERVER_LATENCY =
+ Measure.MeasureDouble.create(
+ "opencensus.io/http/server/server_latency",
+ "Server-side time between first byte of request headers received to last byte of "
+ + "response sent, or terminal error",
+ UNIT_LATENCY_MS);
+
+ /**
+ * {@link TagKey} for the value of the client-side HTTP host header.
+ *
+ * @since 0.13
+ */
+ public static final TagKey HTTP_CLIENT_HOST = TagKey.create("http_client_host");
+
+ /**
+ * {@link TagKey} for the value of the server-side HTTP host header.
+ *
+ * @since 0.13
+ */
+ public static final TagKey HTTP_SERVER_HOST = TagKey.create("http_server_host");
+
+ /**
+ * {@link TagKey} for the numeric client-side HTTP response status code (e.g. 200, 404, 500). If a
+ * transport error occurred and no status code was read, use "error" as the {@code TagValue}.
+ *
+ * @since 0.13
+ */
+ public static final TagKey HTTP_CLIENT_STATUS = TagKey.create("http_client_status");
+
+ /**
+ * {@link TagKey} for the numeric server-side HTTP response status code (e.g. 200, 404, 500). If a
+ * transport error occurred and no status code was written, use "error" as the {@code TagValue}.
+ *
+ * @since 0.13
+ */
+ public static final TagKey HTTP_SERVER_STATUS = TagKey.create("http_server_status");
+
+ /**
+ * {@link TagKey} for the client-side URL path (not including query string) in the request.
+ *
+ * @since 0.13
+ */
+ public static final TagKey HTTP_CLIENT_PATH = TagKey.create("http_client_path");
+
+ /**
+ * {@link TagKey} for the server-side URL path (not including query string) in the request.
+ *
+ * @since 0.13
+ */
+ public static final TagKey HTTP_SERVER_PATH = TagKey.create("http_server_path");
+
+ /**
+ * {@link TagKey} for the client-side HTTP method of the request, capitalized (GET, POST, etc.).
+ *
+ * @since 0.13
+ */
+ public static final TagKey HTTP_CLIENT_METHOD = TagKey.create("http_client_method");
+
+ /**
+ * {@link TagKey} for the server-side HTTP method of the request, capitalized (GET, POST, etc.).
+ *
+ * @since 0.13
+ */
+ public static final TagKey HTTP_SERVER_METHOD = TagKey.create("http_server_method");
+}
diff --git a/contrib/http_util/src/main/java/io/opencensus/contrib/http/util/HttpPropagationUtil.java b/contrib/http_util/src/main/java/io/opencensus/contrib/http/util/HttpPropagationUtil.java
new file mode 100644
index 00000000..779be8d8
--- /dev/null
+++ b/contrib/http_util/src/main/java/io/opencensus/contrib/http/util/HttpPropagationUtil.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2018, OpenCensus Authors
+ *
+ * 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 io.opencensus.contrib.http.util;
+
+import io.opencensus.trace.propagation.TextFormat;
+
+/**
+ * Utility class to get all supported {@link TextFormat}.
+ *
+ * @since 0.11.0
+ */
+public class HttpPropagationUtil {
+
+ private HttpPropagationUtil() {}
+
+ /**
+ * Returns the Stack Driver format implementation. The header specification for this format is
+ * "X-Cloud-Trace-Context: &lt;TRACE_ID&gt;/&lt;SPAN_ID&gt;[;o=&lt;TRACE_TRUE&gt;]". See this <a
+ * href="https://cloud.google.com/trace/docs/support">page</a> for more information.
+ *
+ * @since 0.11.0
+ * @return the Stack Driver format.
+ */
+ public static TextFormat getCloudTraceFormat() {
+ return new CloudTraceFormat();
+ }
+}
diff --git a/contrib/http_util/src/main/java/io/opencensus/contrib/http/util/HttpViewConstants.java b/contrib/http_util/src/main/java/io/opencensus/contrib/http/util/HttpViewConstants.java
new file mode 100644
index 00000000..54ad20ce
--- /dev/null
+++ b/contrib/http_util/src/main/java/io/opencensus/contrib/http/util/HttpViewConstants.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2018, OpenCensus Authors
+ *
+ * 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 io.opencensus.contrib.http.util;
+
+import static io.opencensus.contrib.http.util.HttpMeasureConstants.HTTP_CLIENT_METHOD;
+import static io.opencensus.contrib.http.util.HttpMeasureConstants.HTTP_CLIENT_PATH;
+import static io.opencensus.contrib.http.util.HttpMeasureConstants.HTTP_CLIENT_RECEIVED_BYTES;
+import static io.opencensus.contrib.http.util.HttpMeasureConstants.HTTP_CLIENT_ROUNDTRIP_LATENCY;
+import static io.opencensus.contrib.http.util.HttpMeasureConstants.HTTP_CLIENT_SENT_BYTES;
+import static io.opencensus.contrib.http.util.HttpMeasureConstants.HTTP_CLIENT_STATUS;
+import static io.opencensus.contrib.http.util.HttpMeasureConstants.HTTP_SERVER_LATENCY;
+import static io.opencensus.contrib.http.util.HttpMeasureConstants.HTTP_SERVER_METHOD;
+import static io.opencensus.contrib.http.util.HttpMeasureConstants.HTTP_SERVER_PATH;
+import static io.opencensus.contrib.http.util.HttpMeasureConstants.HTTP_SERVER_RECEIVED_BYTES;
+import static io.opencensus.contrib.http.util.HttpMeasureConstants.HTTP_SERVER_SENT_BYTES;
+import static io.opencensus.contrib.http.util.HttpMeasureConstants.HTTP_SERVER_STATUS;
+
+import com.google.common.annotations.VisibleForTesting;
+import io.opencensus.stats.Aggregation;
+import io.opencensus.stats.Aggregation.Count;
+import io.opencensus.stats.Aggregation.Distribution;
+import io.opencensus.stats.BucketBoundaries;
+import io.opencensus.stats.View;
+import java.util.Arrays;
+import java.util.Collections;
+
+/**
+ * A helper class that holds OpenCensus's default HTTP {@link View}s.
+ *
+ * <p>{@link View}s in this class are all public for other libraries/frameworks to reference and
+ * use.
+ *
+ * @since 0.13
+ */
+public final class HttpViewConstants {
+
+ private HttpViewConstants() {}
+
+ @VisibleForTesting static final Aggregation COUNT = Count.create();
+
+ @VisibleForTesting
+ static final Aggregation SIZE_DISTRIBUTION =
+ Distribution.create(
+ BucketBoundaries.create(
+ Collections.<Double>unmodifiableList(
+ Arrays.<Double>asList(
+ 0.0,
+ 1024.0,
+ 2048.0,
+ 4096.0,
+ 16384.0,
+ 65536.0,
+ 262144.0,
+ 1048576.0,
+ 4194304.0,
+ 16777216.0,
+ 67108864.0,
+ 268435456.0,
+ 1073741824.0,
+ 4294967296.0))));
+
+ @VisibleForTesting
+ static final Aggregation LATENCY_DISTRIBUTION =
+ Distribution.create(
+ BucketBoundaries.create(
+ Collections.<Double>unmodifiableList(
+ Arrays.<Double>asList(
+ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 8.0, 10.0, 13.0, 16.0, 20.0, 25.0, 30.0,
+ 40.0, 50.0, 65.0, 80.0, 100.0, 130.0, 160.0, 200.0, 250.0, 300.0, 400.0,
+ 500.0, 650.0, 800.0, 1000.0, 2000.0, 5000.0, 10000.0, 20000.0, 50000.0,
+ 100000.0))));
+
+ /**
+ * {@link View} for count of client-side HTTP requests completed.
+ *
+ * @since 0.13
+ */
+ public static final View HTTP_CLIENT_COMPLETED_COUNT_VIEW =
+ View.create(
+ View.Name.create("opencensus.io/http/client/completed_count"),
+ "Count of client-side HTTP requests completed",
+ HTTP_CLIENT_ROUNDTRIP_LATENCY,
+ COUNT,
+ Arrays.asList(HTTP_CLIENT_METHOD, HTTP_CLIENT_PATH));
+
+ /**
+ * {@link View} for size distribution of client-side HTTP request body.
+ *
+ * @since 0.13
+ */
+ public static final View HTTP_CLIENT_SENT_BYTES_VIEW =
+ View.create(
+ View.Name.create("opencensus.io/http/client/sent_bytes"),
+ "Size distribution of client-side HTTP request body",
+ HTTP_CLIENT_SENT_BYTES,
+ SIZE_DISTRIBUTION,
+ Arrays.asList(HTTP_CLIENT_METHOD, HTTP_CLIENT_PATH));
+
+ /**
+ * {@link View} for size distribution of client-side HTTP response body.
+ *
+ * @since 0.13
+ */
+ public static final View HTTP_CLIENT_RECEIVED_BYTES_VIEW =
+ View.create(
+ View.Name.create("opencensus.io/http/client/received_bytes"),
+ "Size distribution of client-side HTTP response body",
+ HTTP_CLIENT_RECEIVED_BYTES,
+ SIZE_DISTRIBUTION,
+ Arrays.asList(HTTP_CLIENT_METHOD, HTTP_CLIENT_PATH));
+
+ /**
+ * {@link View} for roundtrip latency distribution of client-side HTTP requests.
+ *
+ * @since 0.13
+ */
+ public static final View HTTP_CLIENT_ROUNDTRIP_LATENCY_VIEW =
+ View.create(
+ View.Name.create("opencensus.io/http/client/roundtrip_latency"),
+ "Roundtrip latency distribution of client-side HTTP requests",
+ HTTP_CLIENT_ROUNDTRIP_LATENCY,
+ LATENCY_DISTRIBUTION,
+ Arrays.asList(HTTP_CLIENT_METHOD, HTTP_CLIENT_PATH, HTTP_CLIENT_STATUS));
+
+ /**
+ * {@link View} for count of server-side HTTP requests serving completed.
+ *
+ * @since 0.13
+ */
+ public static final View HTTP_SERVER_COMPLETED_COUNT_VIEW =
+ View.create(
+ View.Name.create("opencensus.io/http/server/completed_count"),
+ "Count of HTTP server-side requests serving completed",
+ HTTP_SERVER_LATENCY,
+ COUNT,
+ Arrays.asList(HTTP_SERVER_METHOD, HTTP_SERVER_PATH));
+
+ /**
+ * {@link View} for size distribution of server-side HTTP request body.
+ *
+ * @since 0.13
+ */
+ public static final View HTTP_SERVER_RECEIVED_BYTES_VIEW =
+ View.create(
+ View.Name.create("opencensus.io/http/server/received_bytes"),
+ "Size distribution of server-side HTTP request body",
+ HTTP_SERVER_RECEIVED_BYTES,
+ SIZE_DISTRIBUTION,
+ Arrays.asList(HTTP_SERVER_METHOD, HTTP_SERVER_PATH));
+
+ /**
+ * {@link View} for size distribution of server-side HTTP response body.
+ *
+ * @since 0.13
+ */
+ public static final View HTTP_SERVER_SENT_BYTES_VIEW =
+ View.create(
+ View.Name.create("opencensus.io/http/server/sent_bytes"),
+ "Size distribution of server-side HTTP response body",
+ HTTP_SERVER_SENT_BYTES,
+ SIZE_DISTRIBUTION,
+ Arrays.asList(HTTP_SERVER_METHOD, HTTP_SERVER_PATH));
+
+ /**
+ * {@link View} for latency distribution of server-side HTTP requests serving.
+ *
+ * @since 0.13
+ */
+ public static final View HTTP_SERVER_LATENCY_VIEW =
+ View.create(
+ View.Name.create("opencensus.io/http/server/server_latency"),
+ "Latency distribution of server-side HTTP requests serving",
+ HTTP_SERVER_LATENCY,
+ LATENCY_DISTRIBUTION,
+ Arrays.asList(HTTP_SERVER_METHOD, HTTP_SERVER_PATH, HTTP_SERVER_STATUS));
+}
diff --git a/contrib/http_util/src/main/java/io/opencensus/contrib/http/util/HttpViews.java b/contrib/http_util/src/main/java/io/opencensus/contrib/http/util/HttpViews.java
new file mode 100644
index 00000000..9e3b984e
--- /dev/null
+++ b/contrib/http_util/src/main/java/io/opencensus/contrib/http/util/HttpViews.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2018, OpenCensus Authors
+ *
+ * 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 io.opencensus.contrib.http.util;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableSet;
+import io.opencensus.stats.Stats;
+import io.opencensus.stats.View;
+import io.opencensus.stats.ViewManager;
+
+/**
+ * A helper class that allows users to register HTTP views easily.
+ *
+ * @since 0.13
+ */
+public final class HttpViews {
+
+ private HttpViews() {}
+
+ @VisibleForTesting
+ static final ImmutableSet<View> HTTP_SERVER_VIEWS_SET =
+ ImmutableSet.of(
+ HttpViewConstants.HTTP_SERVER_COMPLETED_COUNT_VIEW,
+ HttpViewConstants.HTTP_SERVER_SENT_BYTES_VIEW,
+ HttpViewConstants.HTTP_SERVER_RECEIVED_BYTES_VIEW,
+ HttpViewConstants.HTTP_SERVER_LATENCY_VIEW);
+
+ @VisibleForTesting
+ static final ImmutableSet<View> HTTP_CLIENT_VIEWS_SET =
+ ImmutableSet.of(
+ HttpViewConstants.HTTP_CLIENT_COMPLETED_COUNT_VIEW,
+ HttpViewConstants.HTTP_CLIENT_RECEIVED_BYTES_VIEW,
+ HttpViewConstants.HTTP_CLIENT_SENT_BYTES_VIEW,
+ HttpViewConstants.HTTP_CLIENT_ROUNDTRIP_LATENCY_VIEW);
+
+ /**
+ * Register all default client views.
+ *
+ * <p>It is recommended to call this method before doing any HTTP call to avoid missing stats.
+ *
+ * @since 0.13
+ */
+ public static final void registerAllClientViews() {
+ registerAllClientViews(Stats.getViewManager());
+ }
+
+ @VisibleForTesting
+ static void registerAllClientViews(ViewManager viewManager) {
+ for (View view : HTTP_CLIENT_VIEWS_SET) {
+ viewManager.registerView(view);
+ }
+ }
+
+ /**
+ * Register all default server views.
+ *
+ * <p>It is recommended to call this method before doing any HTTP call to avoid missing stats.
+ *
+ * @since 0.13
+ */
+ public static final void registerAllServerViews() {
+ registerAllServerViews(Stats.getViewManager());
+ }
+
+ @VisibleForTesting
+ static void registerAllServerViews(ViewManager viewManager) {
+ for (View view : HTTP_SERVER_VIEWS_SET) {
+ viewManager.registerView(view);
+ }
+ }
+
+ /**
+ * Register all default views. Equivalent with calling {@link #registerAllClientViews()} and
+ * {@link #registerAllServerViews()}.
+ *
+ * <p>It is recommended to call this method before doing any HTTP call to avoid missing stats.
+ *
+ * @since 0.13
+ */
+ public static final void registerAllViews() {
+ registerAllViews(Stats.getViewManager());
+ }
+
+ @VisibleForTesting
+ static void registerAllViews(ViewManager viewManager) {
+ registerAllClientViews(viewManager);
+ registerAllServerViews(viewManager);
+ }
+}
diff --git a/contrib/http_util/src/test/java/io/opencensus/contrib/http/util/CloudTraceFormatTest.java b/contrib/http_util/src/test/java/io/opencensus/contrib/http/util/CloudTraceFormatTest.java
new file mode 100644
index 00000000..4492a402
--- /dev/null
+++ b/contrib/http_util/src/test/java/io/opencensus/contrib/http/util/CloudTraceFormatTest.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright 2017, OpenCensus Authors
+ *
+ * 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 io.opencensus.contrib.http.util;
+
+import static com.google.common.truth.Truth.assertThat;
+import static io.opencensus.contrib.http.util.CloudTraceFormat.HEADER_NAME;
+import static io.opencensus.contrib.http.util.CloudTraceFormat.NOT_SAMPLED;
+import static io.opencensus.contrib.http.util.CloudTraceFormat.SAMPLED;
+import static io.opencensus.contrib.http.util.CloudTraceFormat.SPAN_ID_DELIMITER;
+import static io.opencensus.contrib.http.util.CloudTraceFormat.TRACE_OPTION_DELIMITER;
+
+import com.google.common.primitives.UnsignedLong;
+import io.opencensus.trace.SpanContext;
+import io.opencensus.trace.SpanId;
+import io.opencensus.trace.TraceId;
+import io.opencensus.trace.TraceOptions;
+import io.opencensus.trace.propagation.SpanContextParseException;
+import io.opencensus.trace.propagation.TextFormat.Getter;
+import io.opencensus.trace.propagation.TextFormat.Setter;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.Nullable;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Unit tests for {@link CloudTraceFormat}. */
+@RunWith(JUnit4.class)
+public final class CloudTraceFormatTest {
+ private final CloudTraceFormat cloudTraceFormat = new CloudTraceFormat();
+
+ private static final String TRACE_ID_BASE16 = "ff000000000000000000000000000041";
+ private static final String TRACE_ID_BASE16_SHORT = "ff00000000000041";
+ private static final String TRACE_ID_BASE16_LONG = "0000" + TRACE_ID_BASE16;
+ private static final String TRACE_ID_BASE16_INVALID = "ff00000000000000000000000abcdefg";
+ private static final String SPAN_ID_BASE16 = "ff00000000000041";
+ private static final String SPAN_ID_BASE10 = UnsignedLong.valueOf(SPAN_ID_BASE16, 16).toString();
+ private static final String SPAN_ID_BASE10_NEGATIVE = "-12345";
+ private static final String SPAN_ID_BASE10_MAX_UNSIGNED_LONG = UnsignedLong.MAX_VALUE.toString();
+ private static final String SPAN_ID_BASE16_MAX_UNSIGNED_LONG =
+ UnsignedLong.MAX_VALUE.toString(16);
+ private static final String SPAN_ID_BASE10_VERY_LONG =
+ SPAN_ID_BASE10_MAX_UNSIGNED_LONG + SPAN_ID_BASE10_MAX_UNSIGNED_LONG;
+ private static final String SPAN_ID_BASE10_INVALID = "0x12345";
+ private static final String OPTIONS_SAMPLED_MORE_BITS = "11"; // 1011
+ private static final String OPTIONS_NOT_SAMPLED_MORE_BITS = "10"; // 1010
+ private static final String OPTIONS_NEGATIVE = "-1";
+ private static final String OPTIONS_INVALID = "0x1";
+
+ private static final TraceId TRACE_ID = TraceId.fromLowerBase16(TRACE_ID_BASE16);
+ private static final SpanId SPAN_ID = SpanId.fromLowerBase16(SPAN_ID_BASE16);
+ private static final SpanId SPAN_ID_MAX =
+ SpanId.fromLowerBase16(SPAN_ID_BASE16_MAX_UNSIGNED_LONG);
+
+ private static final TraceOptions TRACE_OPTIONS_SAMPLED =
+ TraceOptions.builder().setIsSampled(true).build();
+ private static final TraceOptions TRACE_OPTIONS_NOT_SAMPLED = TraceOptions.DEFAULT;
+
+ @Rule public ExpectedException thrown = ExpectedException.none();
+ private final Setter<Map<String, String>> setter =
+ new Setter<Map<String, String>>() {
+ @Override
+ public void put(Map<String, String> carrier, String key, String value) {
+ carrier.put(key, value);
+ }
+ };
+ private final Getter<Map<String, String>> getter =
+ new Getter<Map<String, String>>() {
+ @Nullable
+ @Override
+ public String get(Map<String, String> carrier, String key) {
+ return carrier.get(key);
+ }
+ };
+
+ private static String constructHeader(String traceId, String spanId) {
+ return traceId + SPAN_ID_DELIMITER + spanId;
+ }
+
+ private static String constructHeader(String traceId, String spanId, String traceOptions) {
+ return traceId + SPAN_ID_DELIMITER + spanId + TRACE_OPTION_DELIMITER + traceOptions;
+ }
+
+ private void parseSuccess(String headerValue, SpanContext expected)
+ throws SpanContextParseException {
+ Map<String, String> header = new HashMap<String, String>();
+ header.put(HEADER_NAME, headerValue);
+ assertThat(cloudTraceFormat.extract(header, getter)).isEqualTo(expected);
+ }
+
+ private void parseFailure(
+ String headerValue, Class<? extends Throwable> expectedThrown, String expectedMessage)
+ throws SpanContextParseException {
+ Map<String, String> header = new HashMap<String, String>();
+ header.put(HEADER_NAME, headerValue);
+ thrown.expect(expectedThrown);
+ thrown.expectMessage(expectedMessage);
+ cloudTraceFormat.extract(header, getter);
+ }
+
+ @Test
+ public void serializeSampledContextShouldSucceed() throws SpanContextParseException {
+ Map<String, String> carrier = new HashMap<String, String>();
+ cloudTraceFormat.inject(
+ SpanContext.create(TRACE_ID, SPAN_ID, TRACE_OPTIONS_SAMPLED), carrier, setter);
+ assertThat(carrier)
+ .containsExactly(HEADER_NAME, constructHeader(TRACE_ID_BASE16, SPAN_ID_BASE10, SAMPLED));
+ }
+
+ @Test
+ public void serializeNotSampledContextShouldSucceed() throws SpanContextParseException {
+ Map<String, String> carrier = new HashMap<String, String>();
+ cloudTraceFormat.inject(
+ SpanContext.create(TRACE_ID, SPAN_ID, TRACE_OPTIONS_NOT_SAMPLED), carrier, setter);
+ assertThat(carrier)
+ .containsExactly(
+ HEADER_NAME, constructHeader(TRACE_ID_BASE16, SPAN_ID_BASE10, NOT_SAMPLED));
+ }
+
+ @Test
+ public void parseSampledShouldSucceed() throws SpanContextParseException {
+ parseSuccess(
+ constructHeader(TRACE_ID_BASE16, SPAN_ID_BASE10, OPTIONS_SAMPLED_MORE_BITS),
+ SpanContext.create(TRACE_ID, SPAN_ID, TRACE_OPTIONS_SAMPLED));
+ }
+
+ @Test
+ public void parseNotSampledShouldSucceed() throws SpanContextParseException {
+ parseSuccess(
+ constructHeader(TRACE_ID_BASE16, SPAN_ID_BASE10, OPTIONS_NOT_SAMPLED_MORE_BITS),
+ SpanContext.create(TRACE_ID, SPAN_ID, TRACE_OPTIONS_NOT_SAMPLED));
+ }
+
+ @Test
+ public void parseMissingTraceOptionsShouldSucceed() throws SpanContextParseException {
+ parseSuccess(
+ constructHeader(TRACE_ID_BASE16, SPAN_ID_BASE10),
+ SpanContext.create(TRACE_ID, SPAN_ID, TRACE_OPTIONS_NOT_SAMPLED));
+ }
+
+ @Test
+ public void parseEmptyTraceOptionsShouldFail() throws SpanContextParseException {
+ parseFailure(
+ constructHeader(TRACE_ID_BASE16, SPAN_ID_BASE10, ""),
+ SpanContextParseException.class,
+ "Invalid input");
+ }
+
+ @Test
+ public void parseNegativeTraceOptionsShouldFail() throws SpanContextParseException {
+ parseFailure(
+ constructHeader(TRACE_ID_BASE16, SPAN_ID_BASE10, OPTIONS_NEGATIVE),
+ SpanContextParseException.class,
+ "Invalid input");
+ }
+
+ @Test
+ public void parseInvalidTraceOptionsShouldFail() throws SpanContextParseException {
+ parseFailure(
+ constructHeader(TRACE_ID_BASE16, SPAN_ID_BASE10, OPTIONS_INVALID),
+ SpanContextParseException.class,
+ "Invalid input");
+ }
+
+ @Test
+ public void parseMissingHeaderShouldFail() throws SpanContextParseException {
+ Map<String, String> headerMissing = new HashMap<String, String>();
+ thrown.expect(SpanContextParseException.class);
+ thrown.expectMessage("Missing or too short header: X-Cloud-Trace-Context");
+ cloudTraceFormat.extract(headerMissing, getter);
+ }
+
+ @Test
+ public void parseEmptyHeaderShouldFail() throws SpanContextParseException {
+ parseFailure(
+ "", SpanContextParseException.class, "Missing or too short header: X-Cloud-Trace-Context");
+ }
+
+ @Test
+ public void parseShortHeaderShouldFail() throws SpanContextParseException {
+ parseFailure(
+ constructHeader(TRACE_ID_BASE16, ""),
+ SpanContextParseException.class,
+ "Missing or too short header: X-Cloud-Trace-Context");
+ }
+
+ @Test
+ public void parseShortTraceIdShouldFail() throws SpanContextParseException {
+ parseFailure(
+ constructHeader(TRACE_ID_BASE16_SHORT, SPAN_ID_BASE10, SAMPLED),
+ SpanContextParseException.class,
+ "Invalid input");
+ }
+
+ @Test
+ public void parseLongTraceIdShouldFail() throws SpanContextParseException {
+ parseFailure(
+ constructHeader(TRACE_ID_BASE16_LONG, SPAN_ID_BASE10, SAMPLED),
+ SpanContextParseException.class,
+ "Invalid input");
+ }
+
+ @Test
+ public void parseMissingTraceIdShouldFail() throws SpanContextParseException {
+ parseFailure(
+ constructHeader("", SPAN_ID_BASE10_VERY_LONG, SAMPLED),
+ SpanContextParseException.class,
+ "Invalid input");
+ }
+
+ @Test
+ public void parseInvalidTraceIdShouldFail() throws SpanContextParseException {
+ parseFailure(
+ constructHeader(TRACE_ID_BASE16_INVALID, SPAN_ID_BASE10, SAMPLED),
+ SpanContextParseException.class,
+ "Invalid input");
+ }
+
+ @Test
+ public void parseMissingSpanIdDelimiterShouldFail() throws SpanContextParseException {
+ parseFailure(TRACE_ID_BASE16_LONG, SpanContextParseException.class, "Invalid input");
+ }
+
+ @Test
+ public void parseNegativeSpanIdShouldFail() throws SpanContextParseException {
+ parseFailure(
+ constructHeader(TRACE_ID_BASE16, SPAN_ID_BASE10_NEGATIVE, SAMPLED),
+ SpanContextParseException.class,
+ "Invalid input");
+ }
+
+ @Test
+ public void parseMaxUnsignedLongSpanIdShouldSucceed() throws SpanContextParseException {
+ parseSuccess(
+ constructHeader(TRACE_ID_BASE16, SPAN_ID_BASE10_MAX_UNSIGNED_LONG, SAMPLED),
+ SpanContext.create(TRACE_ID, SPAN_ID_MAX, TRACE_OPTIONS_SAMPLED));
+ }
+
+ @Test
+ public void parseOverflowSpanIdShouldFail() throws SpanContextParseException {
+ parseFailure(
+ constructHeader(TRACE_ID_BASE16, SPAN_ID_BASE10_VERY_LONG, SAMPLED),
+ SpanContextParseException.class,
+ "Invalid input");
+ }
+
+ @Test
+ public void parseInvalidSpanIdShouldFail() throws SpanContextParseException {
+ parseFailure(
+ constructHeader(TRACE_ID_BASE16, SPAN_ID_BASE10_INVALID, SAMPLED),
+ SpanContextParseException.class,
+ "Invalid input");
+ }
+
+ @Test
+ public void parseMissingSpanIdShouldFail() throws SpanContextParseException {
+ parseFailure(
+ constructHeader(TRACE_ID_BASE16, "", SAMPLED),
+ SpanContextParseException.class,
+ "Invalid input");
+ }
+
+ @Test
+ public void fieldsShouldMatch() {
+ assertThat(cloudTraceFormat.fields()).containsExactly(HEADER_NAME);
+ }
+
+ @Test
+ public void parseWithShortSpanIdAndSamplingShouldSucceed() throws SpanContextParseException {
+ final String spanId = "1";
+ ByteBuffer buffer = ByteBuffer.allocate(SpanId.SIZE);
+ buffer.putLong(Long.parseLong(spanId));
+ SpanId expectedSpanId = SpanId.fromBytes(buffer.array());
+ parseSuccess(
+ constructHeader(TRACE_ID_BASE16, spanId, SAMPLED),
+ SpanContext.create(TRACE_ID, expectedSpanId, TRACE_OPTIONS_SAMPLED));
+ }
+}
diff --git a/contrib/http_util/src/test/java/io/opencensus/contrib/http/util/HttpMeasureConstantsTest.java b/contrib/http_util/src/test/java/io/opencensus/contrib/http/util/HttpMeasureConstantsTest.java
new file mode 100644
index 00000000..dd1c20fb
--- /dev/null
+++ b/contrib/http_util/src/test/java/io/opencensus/contrib/http/util/HttpMeasureConstantsTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2018, OpenCensus Authors
+ *
+ * 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 io.opencensus.contrib.http.util;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import io.opencensus.tags.TagKey;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Test for {@link HttpMeasureConstants}. */
+@RunWith(JUnit4.class)
+public class HttpMeasureConstantsTest {
+
+ @Test
+ public void constants() {
+ // Test TagKeys
+ assertThat(HttpMeasureConstants.HTTP_CLIENT_STATUS)
+ .isEqualTo(TagKey.create("http_client_status"));
+ assertThat(HttpMeasureConstants.HTTP_CLIENT_METHOD)
+ .isEqualTo(TagKey.create("http_client_method"));
+ assertThat(HttpMeasureConstants.HTTP_CLIENT_PATH).isEqualTo(TagKey.create("http_client_path"));
+ assertThat(HttpMeasureConstants.HTTP_CLIENT_HOST).isEqualTo(TagKey.create("http_client_host"));
+ assertThat(HttpMeasureConstants.HTTP_SERVER_STATUS)
+ .isEqualTo(TagKey.create("http_server_status"));
+ assertThat(HttpMeasureConstants.HTTP_SERVER_METHOD)
+ .isEqualTo(TagKey.create("http_server_method"));
+ assertThat(HttpMeasureConstants.HTTP_SERVER_PATH).isEqualTo(TagKey.create("http_server_path"));
+ assertThat(HttpMeasureConstants.HTTP_SERVER_HOST).isEqualTo(TagKey.create("http_server_host"));
+
+ // Test measures
+ assertThat(HttpMeasureConstants.HTTP_CLIENT_SENT_BYTES.getUnit()).isEqualTo("By");
+ assertThat(HttpMeasureConstants.HTTP_CLIENT_RECEIVED_BYTES.getUnit()).isEqualTo("By");
+ assertThat(HttpMeasureConstants.HTTP_CLIENT_ROUNDTRIP_LATENCY.getUnit()).isEqualTo("ms");
+ assertThat(HttpMeasureConstants.HTTP_SERVER_RECEIVED_BYTES.getUnit()).isEqualTo("By");
+ assertThat(HttpMeasureConstants.HTTP_SERVER_SENT_BYTES.getUnit()).isEqualTo("By");
+ assertThat(HttpMeasureConstants.HTTP_SERVER_LATENCY.getUnit()).isEqualTo("ms");
+
+ assertThat(HttpMeasureConstants.HTTP_CLIENT_SENT_BYTES.getName())
+ .contains("opencensus.io/http/client");
+ assertThat(HttpMeasureConstants.HTTP_CLIENT_RECEIVED_BYTES.getName())
+ .contains("opencensus.io/http/client");
+ assertThat(HttpMeasureConstants.HTTP_CLIENT_ROUNDTRIP_LATENCY.getName())
+ .contains("opencensus.io/http/client");
+ assertThat(HttpMeasureConstants.HTTP_SERVER_RECEIVED_BYTES.getName())
+ .contains("opencensus.io/http/server");
+ assertThat(HttpMeasureConstants.HTTP_SERVER_SENT_BYTES.getName())
+ .contains("opencensus.io/http/server");
+ assertThat(HttpMeasureConstants.HTTP_SERVER_LATENCY.getName())
+ .contains("opencensus.io/http/server");
+ }
+}
diff --git a/contrib/http_util/src/test/java/io/opencensus/contrib/http/util/HttpPropagationUtilTest.java b/contrib/http_util/src/test/java/io/opencensus/contrib/http/util/HttpPropagationUtilTest.java
new file mode 100644
index 00000000..f84a4da0
--- /dev/null
+++ b/contrib/http_util/src/test/java/io/opencensus/contrib/http/util/HttpPropagationUtilTest.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2018, OpenCensus Authors
+ *
+ * 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 io.opencensus.contrib.http.util;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import io.opencensus.trace.propagation.TextFormat;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Unit tests for {@link HttpPropagationUtil}. */
+@RunWith(JUnit4.class)
+public class HttpPropagationUtilTest {
+
+ @Test
+ public void cloudTraceFormatNotNull() {
+ TextFormat cloudTraceFormat = HttpPropagationUtil.getCloudTraceFormat();
+ assertThat(cloudTraceFormat).isNotNull();
+ assertThat(cloudTraceFormat).isInstanceOf(CloudTraceFormat.class);
+ }
+}
diff --git a/contrib/http_util/src/test/java/io/opencensus/contrib/http/util/HttpViewConstantsTest.java b/contrib/http_util/src/test/java/io/opencensus/contrib/http/util/HttpViewConstantsTest.java
new file mode 100644
index 00000000..d008348e
--- /dev/null
+++ b/contrib/http_util/src/test/java/io/opencensus/contrib/http/util/HttpViewConstantsTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2018, OpenCensus Authors
+ *
+ * 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 io.opencensus.contrib.http.util;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import io.opencensus.stats.Aggregation.Count;
+import io.opencensus.stats.Aggregation.Distribution;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Test for {@link HttpViewConstants}. */
+@RunWith(JUnit4.class)
+public class HttpViewConstantsTest {
+
+ @Test
+ public void constants() {
+ // Test aggregations, and their bucket boundaries (if they are Distribution).
+ assertThat(HttpViewConstants.COUNT).isEqualTo(Count.create());
+ assertThat(HttpViewConstants.SIZE_DISTRIBUTION).isInstanceOf(Distribution.class);
+ assertThat(
+ ((Distribution) HttpViewConstants.SIZE_DISTRIBUTION)
+ .getBucketBoundaries()
+ .getBoundaries())
+ .containsExactly(
+ 0.0,
+ 1024.0,
+ 2048.0,
+ 4096.0,
+ 16384.0,
+ 65536.0,
+ 262144.0,
+ 1048576.0,
+ 4194304.0,
+ 16777216.0,
+ 67108864.0,
+ 268435456.0,
+ 1073741824.0,
+ 4294967296.0)
+ .inOrder();
+ assertThat(HttpViewConstants.LATENCY_DISTRIBUTION).isInstanceOf(Distribution.class);
+ assertThat(
+ ((Distribution) HttpViewConstants.LATENCY_DISTRIBUTION)
+ .getBucketBoundaries()
+ .getBoundaries())
+ .containsExactly(
+ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 8.0, 10.0, 13.0, 16.0, 20.0, 25.0, 30.0, 40.0, 50.0,
+ 65.0, 80.0, 100.0, 130.0, 160.0, 200.0, 250.0, 300.0, 400.0, 500.0, 650.0, 800.0,
+ 1000.0, 2000.0, 5000.0, 10000.0, 20000.0, 50000.0, 100000.0)
+ .inOrder();
+
+ // Test views.
+ assertThat(HttpViewConstants.HTTP_CLIENT_COMPLETED_COUNT_VIEW.getName().asString())
+ .contains("opencensus.io/http/client");
+ assertThat(HttpViewConstants.HTTP_CLIENT_SENT_BYTES_VIEW.getName().asString())
+ .contains("opencensus.io/http/client");
+ assertThat(HttpViewConstants.HTTP_CLIENT_RECEIVED_BYTES_VIEW.getName().asString())
+ .contains("opencensus.io/http/client");
+ assertThat(HttpViewConstants.HTTP_CLIENT_ROUNDTRIP_LATENCY_VIEW.getName().asString())
+ .contains("opencensus.io/http/client");
+ assertThat(HttpViewConstants.HTTP_SERVER_COMPLETED_COUNT_VIEW.getName().asString())
+ .contains("opencensus.io/http/server");
+ assertThat(HttpViewConstants.HTTP_SERVER_RECEIVED_BYTES_VIEW.getName().asString())
+ .contains("opencensus.io/http/server");
+ assertThat(HttpViewConstants.HTTP_SERVER_SENT_BYTES_VIEW.getName().asString())
+ .contains("opencensus.io/http/server");
+ assertThat(HttpViewConstants.HTTP_SERVER_LATENCY_VIEW.getName().asString())
+ .contains("opencensus.io/http/server");
+
+ assertThat(HttpViewConstants.HTTP_CLIENT_COMPLETED_COUNT_VIEW.getMeasure())
+ .isEqualTo(HttpMeasureConstants.HTTP_CLIENT_ROUNDTRIP_LATENCY);
+ assertThat(HttpViewConstants.HTTP_CLIENT_SENT_BYTES_VIEW.getMeasure())
+ .isEqualTo(HttpMeasureConstants.HTTP_CLIENT_SENT_BYTES);
+ assertThat(HttpViewConstants.HTTP_CLIENT_RECEIVED_BYTES_VIEW.getMeasure())
+ .isEqualTo(HttpMeasureConstants.HTTP_CLIENT_RECEIVED_BYTES);
+ assertThat(HttpViewConstants.HTTP_CLIENT_ROUNDTRIP_LATENCY_VIEW.getMeasure())
+ .isEqualTo(HttpMeasureConstants.HTTP_CLIENT_ROUNDTRIP_LATENCY);
+ assertThat(HttpViewConstants.HTTP_SERVER_COMPLETED_COUNT_VIEW.getMeasure())
+ .isEqualTo(HttpMeasureConstants.HTTP_SERVER_LATENCY);
+ assertThat(HttpViewConstants.HTTP_SERVER_RECEIVED_BYTES_VIEW.getMeasure())
+ .isEqualTo(HttpMeasureConstants.HTTP_SERVER_RECEIVED_BYTES);
+ assertThat(HttpViewConstants.HTTP_SERVER_SENT_BYTES_VIEW.getMeasure())
+ .isEqualTo(HttpMeasureConstants.HTTP_SERVER_SENT_BYTES);
+ assertThat(HttpViewConstants.HTTP_SERVER_LATENCY_VIEW.getMeasure())
+ .isEqualTo(HttpMeasureConstants.HTTP_SERVER_LATENCY);
+
+ assertThat(HttpViewConstants.HTTP_CLIENT_COMPLETED_COUNT_VIEW.getAggregation())
+ .isEqualTo(HttpViewConstants.COUNT);
+ assertThat(HttpViewConstants.HTTP_CLIENT_SENT_BYTES_VIEW.getAggregation())
+ .isEqualTo(HttpViewConstants.SIZE_DISTRIBUTION);
+ assertThat(HttpViewConstants.HTTP_CLIENT_RECEIVED_BYTES_VIEW.getAggregation())
+ .isEqualTo(HttpViewConstants.SIZE_DISTRIBUTION);
+ assertThat(HttpViewConstants.HTTP_CLIENT_ROUNDTRIP_LATENCY_VIEW.getAggregation())
+ .isEqualTo(HttpViewConstants.LATENCY_DISTRIBUTION);
+ assertThat(HttpViewConstants.HTTP_SERVER_COMPLETED_COUNT_VIEW.getAggregation())
+ .isEqualTo(HttpViewConstants.COUNT);
+ assertThat(HttpViewConstants.HTTP_SERVER_RECEIVED_BYTES_VIEW.getAggregation())
+ .isEqualTo(HttpViewConstants.SIZE_DISTRIBUTION);
+ assertThat(HttpViewConstants.HTTP_SERVER_SENT_BYTES_VIEW.getAggregation())
+ .isEqualTo(HttpViewConstants.SIZE_DISTRIBUTION);
+ assertThat(HttpViewConstants.HTTP_SERVER_LATENCY_VIEW.getAggregation())
+ .isEqualTo(HttpViewConstants.LATENCY_DISTRIBUTION);
+
+ assertThat(HttpViewConstants.HTTP_CLIENT_COMPLETED_COUNT_VIEW.getColumns())
+ .containsExactly(
+ HttpMeasureConstants.HTTP_CLIENT_METHOD, HttpMeasureConstants.HTTP_CLIENT_PATH);
+ assertThat(HttpViewConstants.HTTP_CLIENT_SENT_BYTES_VIEW.getColumns())
+ .containsExactly(
+ HttpMeasureConstants.HTTP_CLIENT_METHOD, HttpMeasureConstants.HTTP_CLIENT_PATH);
+ assertThat(HttpViewConstants.HTTP_CLIENT_RECEIVED_BYTES_VIEW.getColumns())
+ .containsExactly(
+ HttpMeasureConstants.HTTP_CLIENT_METHOD, HttpMeasureConstants.HTTP_CLIENT_PATH);
+ assertThat(HttpViewConstants.HTTP_CLIENT_ROUNDTRIP_LATENCY_VIEW.getColumns())
+ .containsExactly(
+ HttpMeasureConstants.HTTP_CLIENT_METHOD,
+ HttpMeasureConstants.HTTP_CLIENT_PATH,
+ HttpMeasureConstants.HTTP_CLIENT_STATUS);
+ assertThat(HttpViewConstants.HTTP_SERVER_COMPLETED_COUNT_VIEW.getColumns())
+ .containsExactly(
+ HttpMeasureConstants.HTTP_SERVER_METHOD, HttpMeasureConstants.HTTP_SERVER_PATH);
+ assertThat(HttpViewConstants.HTTP_SERVER_RECEIVED_BYTES_VIEW.getColumns())
+ .containsExactly(
+ HttpMeasureConstants.HTTP_SERVER_METHOD, HttpMeasureConstants.HTTP_SERVER_PATH);
+ assertThat(HttpViewConstants.HTTP_SERVER_SENT_BYTES_VIEW.getColumns())
+ .containsExactly(
+ HttpMeasureConstants.HTTP_SERVER_METHOD, HttpMeasureConstants.HTTP_SERVER_PATH);
+ assertThat(HttpViewConstants.HTTP_SERVER_LATENCY_VIEW.getColumns())
+ .containsExactly(
+ HttpMeasureConstants.HTTP_SERVER_METHOD,
+ HttpMeasureConstants.HTTP_SERVER_PATH,
+ HttpMeasureConstants.HTTP_SERVER_STATUS);
+ }
+}
diff --git a/contrib/http_util/src/test/java/io/opencensus/contrib/http/util/HttpViewsTest.java b/contrib/http_util/src/test/java/io/opencensus/contrib/http/util/HttpViewsTest.java
new file mode 100644
index 00000000..8adf0a5b
--- /dev/null
+++ b/contrib/http_util/src/test/java/io/opencensus/contrib/http/util/HttpViewsTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2018, OpenCensus Authors
+ *
+ * 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 io.opencensus.contrib.http.util;
+
+import static org.mockito.Mockito.verify;
+
+import io.opencensus.stats.View;
+import io.opencensus.stats.ViewManager;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/** Test for {@link HttpViews}. */
+@RunWith(JUnit4.class)
+public class HttpViewsTest {
+
+ @Mock ViewManager viewManager;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void registerClientViews() {
+ HttpViews.registerAllClientViews(viewManager);
+ for (View view : HttpViews.HTTP_CLIENT_VIEWS_SET) {
+ verify(viewManager).registerView(view);
+ }
+ }
+
+ @Test
+ public void registerServerViews() {
+ HttpViews.registerAllServerViews(viewManager);
+ for (View view : HttpViews.HTTP_SERVER_VIEWS_SET) {
+ verify(viewManager).registerView(view);
+ }
+ }
+
+ @Test
+ public void registerAll() {
+ HttpViews.registerAllViews(viewManager);
+ for (View view : HttpViews.HTTP_CLIENT_VIEWS_SET) {
+ verify(viewManager).registerView(view);
+ }
+ for (View view : HttpViews.HTTP_SERVER_VIEWS_SET) {
+ verify(viewManager).registerView(view);
+ }
+ }
+}