|
| 1 | +# Observability in Google Cloud Java Client Libraries |
| 2 | + |
| 3 | +This guide explains how to enable and configure observability (tracing and logging) in Google Cloud Java client libraries using OpenTelemetry and SLF4J. |
| 4 | + |
| 5 | +--- |
| 6 | + |
| 7 | +## 1. Overview |
| 8 | + |
| 9 | +Google Cloud Java client libraries built on [GAX (Google API Extensions)](https://github.com/googleapis/google-cloud-java/tree/main/sdk-platform-java/gax-java) provide built-in support for observability: |
| 10 | +- **Tracing**: Powered by [OpenTelemetry](https://opentelemetry.io/). Client calls generate spans representing both high-level logical client operations and individual RPC attempts. |
| 11 | +- **Logging**: Client libraries emit structured diagnostic logs using [SLF4J](https://www.slf4j.org/). When OpenTelemetry is configured, logging output automatically correlates with active trace and span IDs. |
| 12 | + |
| 13 | +--- |
| 14 | + |
| 15 | +## 2. Distributed Tracing with OpenTelemetry |
| 16 | + |
| 17 | +### 2.1 Dependencies |
| 18 | + |
| 19 | +Add the OpenTelemetry SDK and exporters to your project. |
| 20 | + |
| 21 | +#### Maven |
| 22 | +```xml |
| 23 | +<dependencyManagement> |
| 24 | + <dependencies> |
| 25 | + <dependency> |
| 26 | + <groupId>io.opentelemetry</groupId> |
| 27 | + <artifactId>opentelemetry-bom</artifactId> |
| 28 | + <version>1.44.1</version> |
| 29 | + <type>pom</type> |
| 30 | + <scope>import</scope> |
| 31 | + </dependency> |
| 32 | + </dependencies> |
| 33 | +</dependencyManagement> |
| 34 | + |
| 35 | +<dependencies> |
| 36 | + <!-- OpenTelemetry SDK --> |
| 37 | + <dependency> |
| 38 | + <groupId>io.opentelemetry</groupId> |
| 39 | + <artifactId>opentelemetry-sdk</artifactId> |
| 40 | + </dependency> |
| 41 | + <!-- Google Cloud Trace Exporter (optional, for Cloud Trace) --> |
| 42 | + <dependency> |
| 43 | + <groupId>com.google.cloud.opentelemetry</groupId> |
| 44 | + <artifactId>exporter-trace</artifactId> |
| 45 | + <version>0.33.0</version> |
| 46 | + </dependency> |
| 47 | +</dependencies> |
| 48 | +``` |
| 49 | + |
| 50 | +### 2.2 Initializing OpenTelemetry |
| 51 | + |
| 52 | +Initialize the OpenTelemetry SDK and register it globally, or pass it directly to the client settings: |
| 53 | + |
| 54 | +```java |
| 55 | +import com.google.cloud.opentelemetry.trace.TraceExporter; |
| 56 | +import io.opentelemetry.sdk.OpenTelemetrySdk; |
| 57 | +import io.opentelemetry.sdk.trace.SdkTracerProvider; |
| 58 | +import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; |
| 59 | +import java.io.IOException; |
| 60 | + |
| 61 | +public static OpenTelemetrySdk initializeOpenTelemetry() throws IOException { |
| 62 | + // Initialize TracerProvider with Cloud Trace exporter |
| 63 | + SdkTracerProvider tracerProvider = SdkTracerProvider.builder() |
| 64 | + .addSpanProcessor(BatchSpanProcessor.builder(TraceExporter.createWithDefaultConfiguration()).build()) |
| 65 | + .build(); |
| 66 | + |
| 67 | + return OpenTelemetrySdk.builder() |
| 68 | + .setTracerProvider(tracerProvider) |
| 69 | + .buildAndRegisterGlobal(); |
| 70 | +} |
| 71 | +``` |
| 72 | + |
| 73 | +### 2.3 Span Hierarchy |
| 74 | + |
| 75 | +When tracing is enabled, GAX instruments client calls with a hierarchy of spans: |
| 76 | +1. **Operation Span (Logical / Client Request Span)**: Represents the entire client call from invocation until the final response or failure, spanning across any retries. |
| 77 | +2. **Attempt Span (RPC Attempt Span)**: Represents each individual network RPC attempt made by the client. If retries occur, each attempt produces its own attempt span parented under the operation span. |
| 78 | + |
| 79 | +--- |
| 80 | + |
| 81 | +## 3. Structured Logging & Trace Correlation |
| 82 | + |
| 83 | +### 3.1 SLF4J Binding |
| 84 | + |
| 85 | +GAX and Google Cloud Java libraries use SLF4J for logging. Include an SLF4J implementation such as Logback: |
| 86 | + |
| 87 | +```xml |
| 88 | +<dependency> |
| 89 | + <groupId>ch.qos.logback</groupId> |
| 90 | + <artifactId>logback-classic</artifactId> |
| 91 | + <version>1.5.16</version> |
| 92 | +</dependency> |
| 93 | +``` |
| 94 | + |
| 95 | +### 3.2 Correlating Logs with Cloud Trace |
| 96 | + |
| 97 | +Google Cloud Java client libraries provide two complementary ways to correlate logs with Cloud Trace: |
| 98 | + |
| 99 | +1. **Automatic Context Extraction in Cloud Logging**: |
| 100 | + When writing logs via `google-cloud-logging` (including via the Google Cloud Logging Logback appender), the client library automatically inspects the active thread's OpenTelemetry context (`Span.current()`). If a valid span is active, the `trace`, `spanId`, and `traceSampled` fields are automatically populated on the written `LogEntry`, linking the log directly to Cloud Trace in the Google Cloud Console. |
| 101 | + |
| 102 | +2. **SLF4J Mapped Diagnostic Context (MDC) Propagation**: |
| 103 | + To also include `trace_id` and `span_id` in formatted log messages (such as console or file pattern layouts via `%X{trace_id}`) and attach them as labels in Logback, propagate the OpenTelemetry context to SLF4J MDC: |
| 104 | + - **OpenTelemetry Javaagent**: Use the [OpenTelemetry Javaagent](https://opentelemetry.io/docs/zero-code/java/agent/), which automatically instruments logging frameworks. |
| 105 | + - **Logback MDC Dependency**: Or add the Logback MDC instrumentation dependency to your project: |
| 106 | + ```xml |
| 107 | + <dependency> |
| 108 | + <groupId>io.opentelemetry.instrumentation</groupId> |
| 109 | + <artifactId>opentelemetry-logback-mdc-1.0</artifactId> |
| 110 | + <version>2.10.0-alpha</version> |
| 111 | + </dependency> |
| 112 | + ``` |
| 113 | + |
| 114 | +--- |
| 115 | + |
| 116 | +## 4. Disabling or Customizing Tracing |
| 117 | + |
| 118 | +If you need to disable tracing or provide a custom `ApiTracerFactory`, configure your client stub settings: |
| 119 | + |
| 120 | +```java |
| 121 | +import com.google.api.gax.tracing.NoopApiTracerFactory; |
| 122 | + |
| 123 | +// Example disabling tracing via ServiceSettings builder |
| 124 | +MyServiceSettings.Builder settingsBuilder = MyServiceSettings.newBuilder(); |
| 125 | +settingsBuilder.getStubSettingsBuilder().setTracerFactory(NoopApiTracerFactory.getInstance()); |
| 126 | +MyServiceSettings settings = settingsBuilder.build(); |
| 127 | +``` |
0 commit comments