diff --git a/README.md b/README.md index 2e563e8da..035353f4c 100644 --- a/README.md +++ b/README.md @@ -52,20 +52,20 @@ If you are using Maven without the BOM, add this to your dependencies: If you are using Gradle 5.x or later, add this to your dependencies: ```Groovy -implementation platform('com.google.cloud:libraries-bom:26.34.0') +implementation platform('com.google.cloud:libraries-bom:26.37.0') implementation 'com.google.cloud:google-cloud-logging' ``` If you are using Gradle without BOM, add this to your dependencies: ```Groovy -implementation 'com.google.cloud:google-cloud-logging:3.16.1' +implementation 'com.google.cloud:google-cloud-logging:3.17.0' ``` If you are using SBT, add this to your dependencies: ```Scala -libraryDependencies += "com.google.cloud" % "google-cloud-logging" % "3.16.1" +libraryDependencies += "com.google.cloud" % "google-cloud-logging" % "3.17.0" ``` @@ -452,7 +452,7 @@ Java is a registered trademark of Oracle and/or its affiliates. [kokoro-badge-link-5]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-logging/java11.html [stability-image]: https://img.shields.io/badge/stability-stable-green [maven-version-image]: https://img.shields.io/maven-central/v/com.google.cloud/google-cloud-logging.svg -[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-logging/3.16.1 +[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-logging/3.17.0 [authentication]: https://github.com/googleapis/google-cloud-java#authentication [auth-scopes]: https://developers.google.com/identity/protocols/oauth2/scopes [predefined-iam-roles]: https://cloud.google.com/iam/docs/understanding-roles#predefined_roles 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 index 78b527aa7..3f4a9abc1 100644 --- 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 @@ -22,11 +22,11 @@ import com.google.common.base.Splitter; import com.google.common.collect.Iterables; import com.google.errorprone.annotations.CanIgnoreReturnValue; +import io.opentelemetry.api.trace.Span; import java.util.List; import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; -import io.opentelemetry.api.trace.Span; /** Class to hold context attributes including information about {@see HttpRequest} and tracing. */ public class Context { @@ -132,9 +132,10 @@ public Builder setTraceSampled(boolean traceSampled) { } /** - * Sets the trace id, span id and trace sampled flag 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. + * Sets the trace id, span id and trace sampled flag 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. @@ -165,10 +166,11 @@ public Builder loadCloudTraceContext(String cloudTrace) { } /** - * Sets the trace id, span id and trace sampled flag 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. + * Sets the trace id, span id and trace sampled flag 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 @@ -202,8 +204,7 @@ public Builder loadW3CTraceParentContext(String traceParent) { */ @CanIgnoreReturnValue public Builder loadOpenTelemetryContext() { - if (Span.current().getSpanContext() != null && Span.current().getSpanContext().isValid()) - { + if (Span.current().getSpanContext() != null && Span.current().getSpanContext().isValid()) { setTraceId(Span.current().getSpanContext().getTraceId()); setSpanId(Span.current().getSpanContext().getSpanId()); setTraceSampled(Span.current().getSpanContext().isSampled()); 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 index 1a39223c3..9f3e7674e 100644 --- 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 @@ -16,69 +16,73 @@ package com.google.cloud.logging; -/** - * Class provides a per-thread storage of the {@see Context} instances. - */ +/** Class provides a per-thread storage of the {@see Context} instances. */ public class ContextHandler { - public enum ContextPriority { - NO_INPUT, XCLOUD_HEADER, W3_HEADER, OTEL_EXTRACTED - } - - private static final ThreadLocal contextHolder = initContextHolder(); - private static final ThreadLocal currentPriority = new ThreadLocal(); + public enum ContextPriority { + NO_INPUT, + XCLOUD_HEADER, + W3_HEADER, + OTEL_EXTRACTED + } - /** - * 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<>(); - } - } + private static final ThreadLocal contextHolder = initContextHolder(); + private static final ThreadLocal currentPriority = + new ThreadLocal(); - public Context getCurrentContext() { - return contextHolder.get(); + /** + * 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); - } - - /** - * Sets the context based on the priority. Overrides traceId, spanId and TraceSampled if the passed priority is higher. - * HttpRequest values will be retrieved and combined from existing context if HttpRequest in the new context is empty . - */ + public void setCurrentContext(Context context) { + contextHolder.set(context); + } - public void setCurrentContext(Context context, ContextPriority priority) { - if ((currentPriority.get() == null || priority.compareTo(currentPriority.get()) >= 0) && context != null) { - Context.Builder combinedContextBuilder = Context.newBuilder().setTraceId(context.getTraceId()).setSpanId(context.getSpanId()).setTraceSampled(context.getTraceSampled()); - Context currentContext = getCurrentContext(); + /** + * Sets the context based on the priority. Overrides traceId, spanId and TraceSampled if the + * passed priority is higher. HttpRequest values will be retrieved and combined from existing + * context if HttpRequest in the new context is empty . + */ + public void setCurrentContext(Context context, ContextPriority priority) { + if ((currentPriority.get() == null || priority.compareTo(currentPriority.get()) >= 0) + && context != null) { + Context.Builder combinedContextBuilder = + Context.newBuilder() + .setTraceId(context.getTraceId()) + .setSpanId(context.getSpanId()) + .setTraceSampled(context.getTraceSampled()); + Context currentContext = getCurrentContext(); - if (context.getHttpRequest() != null) - { - combinedContextBuilder.setRequest(context.getHttpRequest()); - } - // Combines HttpRequest from the existing context if HttpRequest in new context is empty. - else if (currentContext != null && currentContext.getHttpRequest() != null ){ - combinedContextBuilder.setRequest(currentContext.getHttpRequest()); - } + if (context.getHttpRequest() != null) { + combinedContextBuilder.setRequest(context.getHttpRequest()); + } + // Combines HttpRequest from the existing context if HttpRequest in new context is empty. + else if (currentContext != null && currentContext.getHttpRequest() != null) { + combinedContextBuilder.setRequest(currentContext.getHttpRequest()); + } - contextHolder.set(combinedContextBuilder.build()); - currentPriority.set(priority); - } + contextHolder.set(combinedContextBuilder.build()); + currentPriority.set(priority); } + } - - public void removeCurrentContext() { - contextHolder.remove(); - } + public void removeCurrentContext() { + contextHolder.remove(); + } } 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 45b3eec13..20bf4b507 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 @@ -41,6 +41,7 @@ import com.google.cloud.MonitoredResourceDescriptor; import com.google.cloud.PageImpl; import com.google.cloud.Tuple; +import com.google.cloud.logging.ContextHandler.ContextPriority; import com.google.cloud.logging.spi.v2.LoggingRpc; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Ascii; @@ -89,6 +90,7 @@ import com.google.logging.v2.WriteLogEntriesResponse; import com.google.protobuf.Empty; import com.google.protobuf.util.Durations; +import io.opentelemetry.api.trace.Span; import java.text.ParseException; import java.util.ArrayList; import java.util.List; @@ -98,8 +100,6 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import io.opentelemetry.api.trace.Span; -import com.google.cloud.logging.ContextHandler.ContextPriority; class LoggingImpl extends BaseService implements Logging { protected static final String RESOURCE_NAME_FORMAT = "projects/%s/traces/%s"; @@ -839,8 +839,7 @@ public Iterable populateMetadata( ContextHandler contextHandler = new ContextHandler(); // Populate trace/span ID from OpenTelemetry span context to logging context. - if (Span.current().getSpanContext().isValid()) - { + if (Span.current().getSpanContext().isValid()) { Context.Builder contextBuilder = Context.newBuilder().loadOpenTelemetryContext(); contextHandler.setCurrentContext(contextBuilder.build(), ContextPriority.OTEL_EXTRACTED); } diff --git a/google-cloud-logging/src/test/java/com/google/cloud/logging/AutoPopulateMetadataTests.java b/google-cloud-logging/src/test/java/com/google/cloud/logging/AutoPopulateMetadataTests.java index fee5f69c5..7972ca7bf 100644 --- a/google-cloud-logging/src/test/java/com/google/cloud/logging/AutoPopulateMetadataTests.java +++ b/google-cloud-logging/src/test/java/com/google/cloud/logging/AutoPopulateMetadataTests.java @@ -111,9 +111,15 @@ public void teardown() { new ContextHandler().removeCurrentContext(); } - private void mockCurrentContext(HttpRequest request, String traceId, String spanId, boolean traceSampled) { + private void mockCurrentContext( + HttpRequest request, String traceId, String spanId, boolean traceSampled) { Context mockedContext = - Context.newBuilder().setRequest(request).setTraceId(traceId).setSpanId(spanId).setTraceSampled(traceSampled).build(); + Context.newBuilder() + .setRequest(request) + .setTraceId(traceId) + .setSpanId(spanId) + .setTraceSampled(traceSampled) + .build(); new ContextHandler().setCurrentContext(mockedContext); } 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 index 17d06e53a..32874b778 100644 --- 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 @@ -21,18 +21,18 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; -import io.opentelemetry.context.Scope; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; -import org.threeten.bp.Duration; -import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.*; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Scope; import io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; import io.opentelemetry.sdk.trace.SdkTracerProvider; import io.opentelemetry.sdk.trace.SpanProcessor; import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.threeten.bp.Duration; @RunWith(JUnit4.class) public class ContextTest { @@ -127,7 +127,8 @@ 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=" + TEST_TRACE_SAMPLED; + final String X_CLOUD_TRACE_FULL = + TEST_TRACE_ID + "/" + TEST_SPAN_ID + ";o=" + TEST_TRACE_SAMPLED; Context.Builder builder = Context.newBuilder(); @@ -150,7 +151,8 @@ public void testParsingW3CTraceParent() { final String W3C_TEST_TRACE_ID = "12345678901234567890123456789012"; final String W3C_TEST_SPAN_ID = "1234567890123456"; final String W3C_TEST_TRACE_SAMPLED = "0f"; - final String W3C_TRACE_CONTEXT = "00-" + W3C_TEST_TRACE_ID + "-" + W3C_TEST_SPAN_ID + "-" + W3C_TEST_TRACE_SAMPLED; + final String W3C_TRACE_CONTEXT = + "00-" + W3C_TEST_TRACE_ID + "-" + W3C_TEST_SPAN_ID + "-" + W3C_TEST_TRACE_SAMPLED; Context.Builder builder = Context.newBuilder(); @@ -165,12 +167,10 @@ public void testParsingOpenTelemetryContext() { InMemorySpanExporter testExporter = InMemorySpanExporter.create(); SpanProcessor inMemorySpanProcessor = SimpleSpanProcessor.create(testExporter); OpenTelemetrySdk openTelemetrySdk = - OpenTelemetrySdk.builder() - .setTracerProvider( - SdkTracerProvider.builder() - .addSpanProcessor(inMemorySpanProcessor) - .build()) - .build(); + OpenTelemetrySdk.builder() + .setTracerProvider( + SdkTracerProvider.builder().addSpanProcessor(inMemorySpanProcessor).build()) + .build(); Tracer tracer = openTelemetrySdk.getTracer("ContextTest"); Span otelSpan = tracer.spanBuilder("Example Span Attributes").startSpan(); @@ -180,8 +180,12 @@ public void testParsingOpenTelemetryContext() { otelSpan.setAttribute("Attribute 1", "first attribute value"); currentOtelContext = otelSpan.getSpanContext(); builder.loadOpenTelemetryContext(); - assertTraceSpanAndSampled(builder.build(), currentOtelContext.getTraceId(), currentOtelContext.getSpanId(), currentOtelContext.isSampled()); - } catch(Throwable t) { + assertTraceSpanAndSampled( + builder.build(), + currentOtelContext.getTraceId(), + currentOtelContext.getSpanId(), + currentOtelContext.isSampled()); + } catch (Throwable t) { otelSpan.recordException(t); throw t; } finally { @@ -189,7 +193,11 @@ public void testParsingOpenTelemetryContext() { } } - private void assertTraceSpanAndSampled(Context context, String expectedTraceId, String expectedSpanId, boolean expectedTraceSampled) { + private void assertTraceSpanAndSampled( + Context context, + String expectedTraceId, + String expectedSpanId, + boolean expectedTraceSampled) { assertEquals(expectedTraceId, context.getTraceId()); assertEquals(expectedSpanId, context.getSpanId()); assertEquals(expectedTraceSampled, context.getTraceSampled());