From 86223ff36f9c4b147f322ba646607727b92fbe7b Mon Sep 17 00:00:00 2001 From: minherz Date: Tue, 23 Nov 2021 21:24:18 +0200 Subject: [PATCH] feat: implement context handler to store HTTP request and tracing information (#752) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provide context abstraction to instantiate a context with the info about HttpRequest and tracing (trace id and span id). Provide handler to setup current context context per-thread to support Web servers that handle each request in a dedicated thread. Add empty HttpRequest instance as a constant object to reference when building a new Context. Remove compilation warnings related to serialVersionUID and unused objects. Pull latest env-tests-logging submodule. Support (via configuration property) a choice between InheritableThreadLocal and ThreadLocal as holders for current context. * 🦉 Updates from OwlBot See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md Co-authored-by: Owl Bot --- env-tests-logging | 2 +- .../com/google/cloud/logging/Context.java | 235 ++++++++++++++++++ .../google/cloud/logging/ContextHandler.java | 50 ++++ .../com/google/cloud/logging/HttpRequest.java | 1 + .../cloud/logging/LogDestinationName.java | 1 + .../google/cloud/logging/LoggingConfig.java | 17 +- .../com/google/cloud/logging/LoggingImpl.java | 2 + .../cloud/logging/TraceLoggingEnhancer.java | 11 +- .../com/google/cloud/logging/ContextTest.java | 185 ++++++++++++++ .../google/cloud/logging/HttpRequestTest.java | 1 + 10 files changed, 493 insertions(+), 12 deletions(-) create mode 100644 google-cloud-logging/src/main/java/com/google/cloud/logging/Context.java create mode 100644 google-cloud-logging/src/main/java/com/google/cloud/logging/ContextHandler.java create mode 100644 google-cloud-logging/src/test/java/com/google/cloud/logging/ContextTest.java diff --git a/env-tests-logging b/env-tests-logging index c283c2943..8dbce5f6a 160000 --- a/env-tests-logging +++ b/env-tests-logging @@ -1 +1 @@ -Subproject commit c283c2943363d9c18d846827a44cac282a730437 +Subproject commit 8dbce5f6a710f210f0a3d2b0639b3b10439d2a73 diff --git a/google-cloud-logging/src/main/java/com/google/cloud/logging/Context.java b/google-cloud-logging/src/main/java/com/google/cloud/logging/Context.java new file mode 100644 index 000000000..e88980d36 --- /dev/null +++ b/google-cloud-logging/src/main/java/com/google/cloud/logging/Context.java @@ -0,0 +1,235 @@ +/* + * Copyright 2021 Google LLC + * + * 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 + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.logging; + +import com.google.cloud.logging.HttpRequest.RequestMethod; +import com.google.common.base.MoreObjects; +import com.google.common.base.Strings; +import java.util.Objects; + +/** Class to hold context attributes including information about {@see HttpRequest} and tracing. */ +public class Context { + private final HttpRequest request; + private final String traceId; + private final String spanId; + + /** A builder for {@see Context} objects. */ + public static final class Builder { + private HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(); + private String traceId; + private String spanId; + + Builder() {} + + Builder(Context context) { + this.requestBuilder = context.request.toBuilder(); + this.traceId = context.traceId; + this.spanId = context.spanId; + } + + /** Sets the HTTP request. */ + public Builder setRequest(HttpRequest request) { + this.requestBuilder = request.toBuilder(); + return this; + } + + public Builder setRequestUrl(String url) { + this.requestBuilder.setRequestUrl(url); + return this; + } + + /** Sets the HTTP request method. */ + public Builder setRequestMethod(RequestMethod method) { + this.requestBuilder.setRequestMethod(method); + return this; + } + + /** + * Sets the referer URL of the request, as defined in HTTP/1.1 Header Field Definitions. + * + * @see HTTP/1.1 Header Field + * Definitions + */ + public Builder setReferer(String referer) { + this.requestBuilder.setReferer(referer); + return this; + } + + /** + * Sets the IP address (IPv4 or IPv6) of the client that issued the HTTP request. Examples: + * {@code 192.168.1.1}, {@code FE80::0202:B3FF:FE1E:8329}. + */ + public Builder setRemoteIp(String remoteIp) { + this.requestBuilder.setRemoteIp(remoteIp); + return this; + } + + /** + * Sets the IP address (IPv4 or IPv6) of the origin server that the request was sent to. + * Examples: {@code 192.168.1.1}, {@code FE80::0202:B3FF:FE1E:8329}. + */ + public Builder setServerIp(String serverIp) { + this.requestBuilder.setServerIp(serverIp); + return this; + } + + /** Sets the string as a trace id value. */ + public Builder setTraceId(String traceId) { + this.traceId = traceId; + return this; + } + + /** Sets the string as a span id value. */ + public Builder setSpanId(String spanId) { + this.spanId = spanId; + return this; + } + + /** + * Sets the trace id and span id values by parsing the string which represents xCloud Trace + * Context. The Cloud Trace Context is passed as {@code x-cloud-trace-context} header (can be in + * Pascal case format). The string format is TRACE_ID/SPAN_ID;o=TRACE_TRUE. + * + * @see Cloud Trace header + * format. + */ + public Builder loadCloudTraceContext(String cloudTrace) { + if (cloudTrace != null) { + cloudTrace = cloudTrace.split(";")[0]; + int split = cloudTrace.indexOf('/'); + if (split >= 0) { + String traceId = cloudTrace.substring(0, split); + String spanId = cloudTrace.substring(split + 1); + if (!traceId.isEmpty()) { + setTraceId(traceId); + // do not set span Id without trace Id + if (!spanId.isEmpty()) { + setSpanId(spanId); + } + } + } else if (!cloudTrace.isEmpty()) { + setTraceId(cloudTrace); + } + } + return this; + } + + /** + * Sets the trace id and span id values by parsing the string which represents the standard W3C + * trace context propagation header. The context propagation header is passed as {@code + * traceparent} header. The method currently supports ONLY version {@code "00"}. The string + * format is 00-TRACE_ID-SPAN_ID-FLAGS. field of the {@code version-format} value. + * + * @see traceparent header + * value format + * @throws IllegalArgumentException if passed argument does not follow the @W3C trace format or + * the format version is not supported. + */ + public Builder loadW3CTraceParentContext(String traceParent) throws IllegalArgumentException { + if (traceParent != null) { + String[] fields = traceParent.split("-"); + if (fields.length > 3) { + String versionFormat = fields[0]; + if (!versionFormat.equals("00")) { + throw new IllegalArgumentException("Not supporting versionFormat other than \"00\""); + } + } else { + throw new IllegalArgumentException( + "Invalid format of the header value. Expected \"00-traceid-spanid-arguments\""); + } + String traceId = fields[1]; + if (!traceId.isEmpty()) { + setTraceId(traceId); + } + if (!Strings.isNullOrEmpty(traceId)) { + String spanId = fields[2]; + if (!spanId.isEmpty()) { + setSpanId(spanId); + } + } + } + return this; + } + + /** Creates a {@see Context} object for this builder. */ + public Context build() { + return new Context(this); + } + } + + Context(Builder builder) { + HttpRequest request = builder.requestBuilder.build(); + if (!HttpRequest.EMPTY.equals(request)) { + this.request = request; + } else { + this.request = null; + } + this.traceId = builder.traceId; + this.spanId = builder.spanId; + } + + public HttpRequest getHttpRequest() { + return this.request; + } + + public String getTraceId() { + return this.traceId; + } + + public String getSpanId() { + return this.spanId; + } + + @Override + public int hashCode() { + return Objects.hash(request, traceId, spanId); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("request", request) + .add("traceId", traceId) + .add("spanId", spanId) + .toString(); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof Context)) { + return false; + } + Context other = (Context) obj; + return Objects.equals(request, other.request) + && Objects.equals(traceId, other.traceId) + && Objects.equals(spanId, other.spanId); + } + + /** Returns a builder for this object. */ + public Builder toBuilder() { + return new Builder(this); + } + + /** Returns a builder for {@code HttpRequest} objects. */ + public static Builder newBuilder() { + return new Builder(); + } +} diff --git a/google-cloud-logging/src/main/java/com/google/cloud/logging/ContextHandler.java b/google-cloud-logging/src/main/java/com/google/cloud/logging/ContextHandler.java new file mode 100644 index 000000000..8af084f27 --- /dev/null +++ b/google-cloud-logging/src/main/java/com/google/cloud/logging/ContextHandler.java @@ -0,0 +1,50 @@ +/* + * Copyright 2021 Google LLC + * + * 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 + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.logging; + +/** Class provides a per-thread storage of the {@see Context} instances. */ +public class ContextHandler { + private static final ThreadLocal contextHolder = initContextHolder(); + + /** + * Initializes the context holder to {@link InheritableThreadLocal} if {@link LogManager} + * configuration property {@code com.google.cloud.logging.ContextHandler.useInheritedContext} is + * set to {@code true} or to {@link ThreadLocal} otherwise. + * + * @return instance of the context holder. + */ + private static ThreadLocal initContextHolder() { + LoggingConfig config = new LoggingConfig(ContextHandler.class.getName()); + if (config.getUseInheritedContext()) { + return new InheritableThreadLocal<>(); + } else { + return new ThreadLocal<>(); + } + } + + public Context getCurrentContext() { + return contextHolder.get(); + } + + public void setCurrentContext(Context context) { + contextHolder.set(context); + } + + public void removeCurrentContext() { + contextHolder.remove(); + } +} diff --git a/google-cloud-logging/src/main/java/com/google/cloud/logging/HttpRequest.java b/google-cloud-logging/src/main/java/com/google/cloud/logging/HttpRequest.java index 2ba5e99dd..5c4b71ed9 100644 --- a/google-cloud-logging/src/main/java/com/google/cloud/logging/HttpRequest.java +++ b/google-cloud-logging/src/main/java/com/google/cloud/logging/HttpRequest.java @@ -36,6 +36,7 @@ public final class HttpRequest implements Serializable { private static final long serialVersionUID = -274998005454709817L; + public static final HttpRequest EMPTY = newBuilder().build(); private final RequestMethod requestMethod; private final String requestUrl; diff --git a/google-cloud-logging/src/main/java/com/google/cloud/logging/LogDestinationName.java b/google-cloud-logging/src/main/java/com/google/cloud/logging/LogDestinationName.java index e23446b7a..9b284c070 100644 --- a/google-cloud-logging/src/main/java/com/google/cloud/logging/LogDestinationName.java +++ b/google-cloud-logging/src/main/java/com/google/cloud/logging/LogDestinationName.java @@ -27,6 +27,7 @@ * parameter in https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry) */ public final class LogDestinationName extends Option { + private static final long serialVersionUID = 7944256748441111191L; enum DestinationType implements Option.OptionType { PROJECT, diff --git a/google-cloud-logging/src/main/java/com/google/cloud/logging/LoggingConfig.java b/google-cloud-logging/src/main/java/com/google/cloud/logging/LoggingConfig.java index 3c220cfa7..d2a001fb0 100644 --- a/google-cloud-logging/src/main/java/com/google/cloud/logging/LoggingConfig.java +++ b/google-cloud-logging/src/main/java/com/google/cloud/logging/LoggingConfig.java @@ -40,6 +40,7 @@ class LoggingConfig { private static final String SYNCHRONICITY_TAG = "synchronicity"; private static final String RESOURCE_TYPE_TAG = "resourceType"; private static final String ENHANCERS_TAG = "enhancers"; + private static final String USE_INHERITED_CONTEXT = "useInheritedContext"; public LoggingConfig(String className) { this.className = className; @@ -100,6 +101,18 @@ List getEnhancers() { return Collections.emptyList(); } + /** + * Returns boolean value of the property {@code + * com.google.cloud.logging.context.ContextHandler.useInheritedContext}. If no value is defined or + * the property does not represent a valid boolean value returns {@code false}. + * + * @return {@code true} or {@code false} + */ + boolean getUseInheritedContext() { + String flag = getProperty(USE_INHERITED_CONTEXT, "FALSE"); + return Boolean.parseBoolean(flag); + } + private String getProperty(String name, String defaultValue) { return firstNonNull(getProperty(name), defaultValue); } @@ -121,7 +134,7 @@ private Filter getFilterProperty(String name, Filter defaultValue) { String stringFilter = getProperty(name); try { if (stringFilter != null) { - Class clz = ClassLoader.getSystemClassLoader().loadClass(stringFilter); + Class clz = ClassLoader.getSystemClassLoader().loadClass(stringFilter); return (Filter) clz.getDeclaredConstructor().newInstance(); } } catch (Exception ex) { @@ -134,7 +147,7 @@ private Formatter getFormatterProperty(String name, Formatter defaultValue) { String stringFilter = getProperty(name); try { if (stringFilter != null) { - Class clz = ClassLoader.getSystemClassLoader().loadClass(stringFilter); + Class clz = ClassLoader.getSystemClassLoader().loadClass(stringFilter); return (Formatter) clz.getDeclaredConstructor().newInstance(); } } catch (Exception ex) { diff --git a/google-cloud-logging/src/main/java/com/google/cloud/logging/LoggingImpl.java b/google-cloud-logging/src/main/java/com/google/cloud/logging/LoggingImpl.java index 2f2d194bf..789f825cb 100644 --- a/google-cloud-logging/src/main/java/com/google/cloud/logging/LoggingImpl.java +++ b/google-cloud-logging/src/main/java/com/google/cloud/logging/LoggingImpl.java @@ -200,6 +200,7 @@ public ApiFuture> getNextPage() { } private static class LogNamePageFetcher extends BasePageFetcher { + private static final long serialVersionUID = 5308841362690185583L; LogNamePageFetcher( LoggingOptions serviceOptions, String cursor, Map requestOptions) { @@ -244,6 +245,7 @@ public ApiFuture> getNextPage() { } private static class ExclusionPageFetcher extends BasePageFetcher { + private static final long serialVersionUID = -1414118808031778916L; ExclusionPageFetcher( LoggingOptions serviceOptions, String cursor, Map requestOptions) { diff --git a/google-cloud-logging/src/main/java/com/google/cloud/logging/TraceLoggingEnhancer.java b/google-cloud-logging/src/main/java/com/google/cloud/logging/TraceLoggingEnhancer.java index 80aea34ec..f1593eb8a 100644 --- a/google-cloud-logging/src/main/java/com/google/cloud/logging/TraceLoggingEnhancer.java +++ b/google-cloud-logging/src/main/java/com/google/cloud/logging/TraceLoggingEnhancer.java @@ -19,16 +19,9 @@ /* Adds tracing support for logging with thread-local trace ID tracking. */ public class TraceLoggingEnhancer implements LoggingEnhancer { - private static final String TRACE_ID = "trace_id"; - private final String traceIdLabel; + public TraceLoggingEnhancer() {} - public TraceLoggingEnhancer() { - traceIdLabel = TRACE_ID; - } - - public TraceLoggingEnhancer(String prefix) { - traceIdLabel = (prefix != null) ? prefix + TRACE_ID : TRACE_ID; - } + public TraceLoggingEnhancer(String prefix) {} private static final ThreadLocal traceId = new ThreadLocal<>(); diff --git a/google-cloud-logging/src/test/java/com/google/cloud/logging/ContextTest.java b/google-cloud-logging/src/test/java/com/google/cloud/logging/ContextTest.java new file mode 100644 index 000000000..72c91236a --- /dev/null +++ b/google-cloud-logging/src/test/java/com/google/cloud/logging/ContextTest.java @@ -0,0 +1,185 @@ +/* + * Copyright 2021 Google LLC + * + * 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 + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.logging; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.threeten.bp.Duration; + +public class ContextTest { + + private static final HttpRequest.RequestMethod REQUEST_METHOD = HttpRequest.RequestMethod.GET; + private static final String REQUEST_URL = "https://test.domain?arg=val"; + private static final String CLIENT_IP = "123.123.123.123"; + private static final String SERVER_IP = "123.321.321.321"; + private static final String REQUEST_REFERER = "Referer: https://referer.test.domain"; + // DO NOT use dash in trace and span id because W3C traceparent format uses dash as a delimieter + private static final String TEST_TRACE_ID = "test_trace_id"; + private static final String TEST_SPAN_ID = "test_span_id"; + + private static final HttpRequest REQUEST = + HttpRequest.newBuilder() + .setRequestMethod(REQUEST_METHOD) + .setRequestUrl(REQUEST_URL) + .setRequestSize(101L) + .setStatus(200) + .setResponseSize(202L) + .setUserAgent("Test User Agent") + .setRemoteIp(CLIENT_IP) + .setServerIp(SERVER_IP) + .setReferer(REQUEST_REFERER) + .setCacheLookup(true) + .setCacheHit(false) + .setCacheValidatedWithOriginServer(true) + .setCacheFillBytes(303L) + .setLatency(Duration.ofSeconds(123, 456)) + .build(); + private static final HttpRequest PARTIAL_REQUEST = + HttpRequest.newBuilder() + .setRequestMethod(REQUEST_METHOD) + .setRequestUrl(REQUEST_URL) + .setRemoteIp(CLIENT_IP) + .setServerIp(SERVER_IP) + .setReferer(REQUEST_REFERER) + .build(); + private static final Context TEST_CONTEXT = + Context.newBuilder() + .setRequest(PARTIAL_REQUEST) + .setTraceId(TEST_TRACE_ID) + .setSpanId(TEST_SPAN_ID) + .build(); + + @Test + public void testCompareContexts() { + Context context1 = + Context.newBuilder() + .setRequest(REQUEST) + .setTraceId(TEST_TRACE_ID) + .setSpanId(TEST_SPAN_ID) + .build(); + Context context2 = + Context.newBuilder() + .setRequestUrl(REQUEST_URL) + .setRequestMethod(REQUEST_METHOD) + .setReferer(REQUEST_REFERER) + .setRemoteIp(CLIENT_IP) + .setServerIp(SERVER_IP) + .setTraceId(TEST_TRACE_ID) + .setSpanId(TEST_SPAN_ID) + .build(); + + assertNotEquals(TEST_CONTEXT, context1); + assertFalse(TEST_CONTEXT.hashCode() == context1.hashCode()); + assertTrue(TEST_CONTEXT.equals(context2)); + assertTrue(TEST_CONTEXT.hashCode() == context2.hashCode()); + } + + @Test + public void testContextBuilder() { + Context emptyContext = Context.newBuilder().build(); + Context anotherContext = TEST_CONTEXT.toBuilder().build(); + + assertEquals(PARTIAL_REQUEST, TEST_CONTEXT.getHttpRequest()); + assertEquals(TEST_TRACE_ID, TEST_CONTEXT.getTraceId()); + assertEquals(TEST_SPAN_ID, TEST_CONTEXT.getSpanId()); + assertNull(emptyContext.getHttpRequest()); + assertNull(emptyContext.getTraceId()); + assertNull(emptyContext.getSpanId()); + assertEquals(TEST_CONTEXT, anotherContext); + } + + @Test + public void testParsingCloudTraceContext() { + final String X_CLOUD_TRACE_NO_TRACE = "/SPAN_ID;o=TRACE_TRUE"; + final String X_CLOUD_TRACE_ONLY = TEST_TRACE_ID; + final String X_CLOUD_TRACE_WITH_SPAN = TEST_TRACE_ID + "/" + TEST_SPAN_ID; + final String X_CLOUD_TRACE_FULL = TEST_TRACE_ID + "/" + TEST_SPAN_ID + ";o=TRACE_TRUE"; + + Context.Builder builder = Context.newBuilder(); + + builder.loadCloudTraceContext(null); + assertTraceAndSpan(builder.build(), null, null); + builder.loadCloudTraceContext(""); + assertTraceAndSpan(builder.build(), null, null); + builder.loadCloudTraceContext(X_CLOUD_TRACE_NO_TRACE); + assertTraceAndSpan(builder.build(), null, null); + builder.loadCloudTraceContext(X_CLOUD_TRACE_ONLY); + assertTraceAndSpan(builder.build(), TEST_TRACE_ID, null); + builder.loadCloudTraceContext(X_CLOUD_TRACE_WITH_SPAN); + assertTraceAndSpan(builder.build(), TEST_TRACE_ID, TEST_SPAN_ID); + builder.loadCloudTraceContext(X_CLOUD_TRACE_FULL); + assertTraceAndSpan(builder.build(), TEST_TRACE_ID, TEST_SPAN_ID); + } + + @Test + public void testParsingW3CTraceParent() { + final String TRACEPARENT_NO_TRACE = "00--SPAN_ID-FLAGS"; + final String TRACEPARENT_TRACE_ONLY = "00-" + TEST_TRACE_ID + "--SPAN_ID-FLAGS"; + final String TRACEPARENT_TRACE_FULL = "00-" + TEST_TRACE_ID + "-" + TEST_SPAN_ID + "-FLAGS"; + + Context.Builder builder = Context.newBuilder(); + + builder.loadW3CTraceParentContext(null); + assertTraceAndSpan(builder.build(), null, null); + builder.loadW3CTraceParentContext(TRACEPARENT_NO_TRACE); + assertTraceAndSpan(builder.build(), null, null); + builder.loadW3CTraceParentContext(TRACEPARENT_TRACE_ONLY); + assertTraceAndSpan(builder.build(), TEST_TRACE_ID, null); + builder.loadW3CTraceParentContext(TRACEPARENT_TRACE_FULL); + assertTraceAndSpan(builder.build(), TEST_TRACE_ID, TEST_SPAN_ID); + } + + @Test(expected = IllegalArgumentException.class) + public void testEmptyW3CTraceParent() { + Context.Builder builder = Context.newBuilder(); + builder.loadW3CTraceParentContext(""); + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidFormatW3CTraceParent() { + Context.Builder builder = Context.newBuilder(); + builder.loadW3CTraceParentContext("TRACE_ID/SPAN_ID;o=TRACE_TRUE"); + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidFormatW3CTraceParent1Dash() { + Context.Builder builder = Context.newBuilder(); + builder.loadW3CTraceParentContext("00-TRACE_ID"); + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidFormatW3CTraceParentWithoutFlag() { + Context.Builder builder = Context.newBuilder(); + builder.loadW3CTraceParentContext("00-TRACE_ID-SPAN_ID-"); + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidVersionW3CTraceParent() { + Context.Builder builder = Context.newBuilder(); + builder.loadW3CTraceParentContext("01-TRACE_ID-SPAN_ID-FLAGS"); + } + + private void assertTraceAndSpan(Context context, String expectedTraceId, String expectedSpanId) { + assertEquals(context.getTraceId(), expectedTraceId); + assertEquals(context.getSpanId(), expectedSpanId); + } +} diff --git a/google-cloud-logging/src/test/java/com/google/cloud/logging/HttpRequestTest.java b/google-cloud-logging/src/test/java/com/google/cloud/logging/HttpRequestTest.java index bfcc2f86a..f5934f1ef 100644 --- a/google-cloud-logging/src/test/java/com/google/cloud/logging/HttpRequestTest.java +++ b/google-cloud-logging/src/test/java/com/google/cloud/logging/HttpRequestTest.java @@ -92,6 +92,7 @@ public void testBuilderDefaultValues() { assertFalse(httpRequest.cacheHit()); assertFalse(httpRequest.cacheValidatedWithOriginServer()); assertNull(httpRequest.getCacheFillBytes()); + assertEquals(httpRequest, HttpRequest.EMPTY); } @Test