diff options
Diffstat (limited to 'contrib/http_util/src')
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> + * <TRACE_ID>/<SPAN_ID>[;o=<TRACE_OPTIONS>] + * </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: <TRACE_ID>/<SPAN_ID>[;o=<TRACE_TRUE>]". 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); + } + } +} |