Skip to content

feat(bigquery-jdbc): OpenTelemetry integration in BQ JDBC - #12902

Merged
keshavdandeva merged 48 commits into
mainfrom
jdbc/feature-branch-otel
Jul 24, 2026
Merged

feat(bigquery-jdbc): OpenTelemetry integration in BQ JDBC#12902
keshavdandeva merged 48 commits into
mainfrom
jdbc/feature-branch-otel

Conversation

@keshavdandeva

@keshavdandeva keshavdandeva commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

b/342411096

… Statement (#12124)

b/491239772
b/491239773

### Changes

- New connection properties: `enableGcpTraceExporter` (Boolean, default:
false) and `enableGcpLogExporter` (Boolean, default: false)

- `customOpenTelemetry` (Instance): Programmatic injection of a custom
SDK (User Application-Managed setup) via
`BigQueryDataSource.setCustomOpenTelemetry()`

- Added the core initialization logic for `OpenTelemetry`. During
connection setup, it evaluates whether tracing is enabled and constructs
an OpenTelemetry Tracer instance. Then, it passes this newly minted
tracer strictly downward into the core `BigQueryOptions.Builder` via
`.setOpenTelemetryTracer()`

- Intercepted the execution functions (`execute`, `executeQuery`,
`executeLargeUpdate`, `executeBatch`) to spawn child spans wrapping each
database call.
@keshavdandeva keshavdandeva added the do not merge Indicates a pull request not ready for merge, due to either quality or timing. label Apr 23, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request integrates OpenTelemetry into the BigQuery JDBC driver, enabling tracing for core operations such as query execution, batch updates, and background data processing tasks like pagination and Arrow stream processing. It adds support for custom OpenTelemetry instances and introduces configuration flags for GCP trace and log exporters. The review feedback recommends performance optimizations by using static tracer constants, better adherence to OpenTelemetry semantic conventions for database spans (e.g., setting db.system and SpanKind), and improving user feedback when certain exporter features are still under development.

keshavdandeva and others added 19 commits April 28, 2026 15:31
…agination (#12918)

b/491245568

### Key Changes

#### Core Instrumentation Logic
* **Database Metadata Tracing**: Added OTel spans to key methods in
`BigQueryDatabaseMetaData.java` (`getCatalogs`, `getSchemas`,
`getTables`, `getColumns`) to capture underlying API calls.
* **Pagination Span Links**: Captured the parent span context at the
start of `fetchNextPages` in `BigQueryStatement.java` and linked
background pagination spans back to it, avoiding timeline anomalies.
* **Cross-Thread Context Propagation**: Stored the `SpanContext` in
`BigQueryBaseResultSet.java` at creation time and made it current during
`next()` in `BigQueryJsonResultSet.java` and
`BigQueryArrowResultSet.java` to survive thread hops.
* **Tracer Reuse**: Extracted `getSafeTracer` to
`BigQueryJdbcOpenTelemetry.java` as a static utility to ensure
consistent fallback behavior across the driver.
* **Lambda Extraction**: Extracted the large lambda function in
`populateArrowBufferedQueue` in `BigQueryStatement.java` to its own
private method `processArrowStream` to improve readability and
maintainability.
b/491245568

### Changes

#### Enhanced Unit Testing Infrastructure
- `OpenTelemetryTestUtility`: Introduced a shared utility to simplify
complex OTel assertions
- `BigQueryStatementTest`: Added comprehensive parameterised tracing
tests for all execution paths, including attribute validation for
queries and batch operations.
- `BigQueryDatabaseMetaDataTest`: Instrumented all metadata discovery
methods and added corresponding unit tests to verify span generation
using parameterised tests
b/496678357

This PR implements the **Correlated GCP Logging Bridge** for the
OpenTelemetry integration in the BigQuery JDBC driver. It enables
bridging standard Java logs (`java.util.logging`) to the OpenTelemetry
Logs API, allowing users to correlate logs with distributed traces and
isolate them by connection session.

### Changes

- `BigQueryDriver.java`: Implemented Cloud-Only Mode matrix logic to
suppress local file creation when `enableGcpLogExporter=true` and
`LogPath` is omitted.
- `BigQueryJdbcRootLogger.java`: Updated `setLevel` to handle
`Level.OFF` properly and skip file handler creation if path is null.
- `BigQueryConnection.java`: Attached `OpenTelemetryJulHandler` to the
`"com.google.cloud.bigquery"` namespace during initialization.
- `OpenTelemetryJulHandler.java`: Created a new handler that bridges JUL
logs to OTel Logs API with context harvesting and connection ID
filtering.
- `pom.xml`: Added `google-cloud-logging` dependency with version
`3.33.0-SNAPSHOT` and auto-update marker.
- `OpenTelemetryJulHandlerTest.java`: Created unit tests using
`OpenTelemetryExtension` to verify log emission and filtering.
…#13039)

b/491238299
b/511147053

This PR completes the implementation of the OpenTelemetry SDK lifecycle
and cross-project authentication for the BigQuery JDBC driver. It
introduces thread-safe caching of heavy OTel SDK instances to support
multi-project tracing without global side effects.

### Changes

#### `BigQueryJdbcOpenTelemetry.java`
- A `ConcurrentHashMap` caches `OpenTelemetrySdk` instances, keyed by a
concatenated string of `ProjectId` and `Credentials`
- The `getOpenTelemetry()` method lazily loads and initializes the SDK
only when requested and not present in the cache.
- A JVM shutdown hook closes each cached SDK to ensure pending traces
are flushed on application exit.

#### `BigQueryJdbcUrlUtility.java`
- `gcpTelemetryCredentials` and `gcpTelemetryProjectId` are added to
connection properties.

#### `BigQueryJdbcOAuthUtility.java`
- The `isJson()` helper method is changed from private to
package-private to allow reuse in `BigQueryJdbcOpenTelemetry.`

#### `BigQueryConnection.java`
- Added new connection properties to be used
- Uses `Boolean.TRUE.equals()` when checking `enableGcpLogExporter` and
`enableGcpTraceExporter` to safely handle cases where these properties
are not specified `null` and avoid `NullPointerException` during
auto-unboxing.

#### `BigQueryJdbcOpenTelemetryTest.java`
- New unit tests verify that SDK instances are correctly cached for
identical keys and isolated for different keys.

#### `BigQueryArrowStructTest.java`
- A fix is applied to avoid varargs ambiguity in array creation,
resolving a specific coercion failure in the structOfArrays test.
…agation (#13187)

b/496720140

## Changes

### Context Propagation & Session Tracking
* **Baggage Injection**: Injected the generated Connection UUID into
OpenTelemetry Baggage upon `BigQueryConnection` initialization to enable
reliable log correlation.
* **Log Handler Update**: Updated `OpenTelemetryJulHandler` to rely on
Baggage for retrieving the connection ID, removing the legacy MDC
fallback.
* **Thread Pool Audit**: Wrapped tasks submitted to background executors
in `BigQueryDatabaseMetaData` with `Context.current().wrap()`, ensuring
trace context is not lost during parallel metadata fetching.

### Span Enrichment & Semantic Conventions
* **Attributes**: Enriched JDBC spans with standard attributes:
`db.system = "bigquery"`, `db.connection_id`, and `db.application`
(derived from `partnerToken` or falling back to
`"Google-BigQuery-JDBC-Driver"`).
* **Scope Separation**: Implemented separate tracers for the JDBC driver
(`com.google.cloud.bigquery.jdbc`) and the SDK
(`com.google.cloud.bigquery`) to allow clean filtering in tracing UIs
while maintaining correlation.

### Instrumentation
* **PreparedStatement**: Added missing instrumentation for
`BigQueryPreparedStatement` execution methods (`execute`,
`executeQuery`, `executeLargeUpdate`) to generate spans.

### Refactoring & Cleanups
* **Centralized Tracing**: Created a centralized `withTracing` helper in
`BigQueryJdbcOpenTelemetry.java` to eliminate duplicated tracing logic
in `BigQueryStatement` and `BigQueryDatabaseMetaData`.
* **Constants**: Defined all semantic convention keys as constants in
`BigQueryJdbcOpenTelemetry.java` to eliminate magic strings from method
bodies.
* **Simplifications**: Simplified redundant boolean checks in
`BigQueryConnection.java`.
# Conflicts:
#	java-bigquery/google-cloud-bigquery-jdbc/pom.xml
#	java-bigquery/google-cloud-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryConnection.java
#	java-bigquery/google-cloud-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaData.java
#	java-bigquery/google-cloud-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDriver.java
#	java-bigquery/google-cloud-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryPreparedStatement.java
#	java-bigquery/google-cloud-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryStatement.java
#	java-bigquery/google-cloud-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaDataTest.java
# Conflicts:
#	java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcOpenTelemetry.java
#	java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/OpenTelemetryJulHandler.java
#	java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcOpenTelemetryTest.java
#	java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/OpenTelemetryJulHandlerTest.java
#	java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/OpenTelemetryTestUtility.java
@logachev
logachev force-pushed the jdbc/feature-branch-otel branch from 7bebb0f to 6176a4a Compare May 22, 2026 05:02
keshavdandeva and others added 6 commits May 22, 2026 13:24
b/499079838

### Changes

#### 1. BigQueryJdbcOpenTelemetry.java
* **Feature**: Added safe, generous default attribute value length
limits of **`60KB (61,440 characters)`** to the autoconfigured
OpenTelemetry instance properties.
* **Why**: Prevents GCP Cloud Trace from silently rejecting and dropping
span batches when we log massive `BigQueryException` stack traces or
Arrow schema payloads exceeding the hard 64KB Cloud Trace backend
limits.
* **Design**: If the user explicitly configures their own limits the
driver automatically skips the defaults and respects their overrides.

#### 2. OpenTelemetryJulHandler.java
* **Fix**: Configured the handler level to `Level.ALL` in the
constructor.
* **Why**: Bypasses a standard Java Logging (JUL) constraint where
handlers default to `Level.INFO` and silently drop `FINE`/`DEBUG`
queries. Delegates log filtering exclusively to the Connection loggers.

#### 3. BigQueryConnection.java
* **Visibility**: Exposed the visibility of the connection session
identifier by changing `getConnectionId()` from package-private to
`public`.
* **Why**: Allows automated E2E tests to retrieve the UUID and harvest
specific logs/traces accurately.

#### 4. ITOpenTelemetryTest.java
* **Feature**: Implemented a new standalone E2E integration test suite
verifying the live GCP OTel egress.
* **Test 1 (`testExecute_withOpenTelemetryGcpExporter`)**: Natively
resolves target project via `ServiceOptions.getDefaultProjectId()`. Runs
an optimized in-memory array query and iterates results to trigger
small-page JSON pagination. Queries Cloud Trace E2E to strictly assert
that async pagination child spans are parented perfectly under the root
JDBC span.
* **Test 2 (`testExecute_withErrorCorrelation`)**: Triggers database
failures, captures `SQLException`, harvests Trace IDs from standard
logs, and verifies failed span ingestion in Cloud Trace.

#### 5. BigQueryConnectionTest.java
* **Feature**: Added a new unit test
(`testConnect_withCustomOpenTelemetry_usesCustomInstance`) verifying the
custom OTel injection pipeline.
* **What it does**: Leverages `OpenTelemetryExtension` to mock an OTel
provider locally. Injecting the custom SDK via properties, it validates
that `BigQueryConnection` resolves the instance and routes spans
exclusively to the custom provider

#### 6. pom.xml
* **Dependencies**: Added `google-cloud-trace` test-scoped dependency to
query Cloud Trace v1 API programmatically during E2E validation.

---------

Co-authored-by: cloud-java-bot <cloud-java-bot@google.com>
Co-authored-by: Kirill Logachev <kirl@google.com>
…ing SDK (#13293)

b/517588332

This PR completes the linkage between the JDBC driver's OpenTelemetry
instrumentation and the underlying BigQuery SDK to ensure full
end-to-end traces.

## Key Changes
- **Dependency**: Added `io.grpc:grpc-opentelemetry` to intercept
low-level gRPC network spans for the Storage API.
- **REST API**: Enabled `setEnableOpenTelemetryTracing(true)` in
`BigQueryOptions` to unlock SDK-level tracing for standard queries.
- **HTAPI (Storage API)**: Enabled `setEnableOpenTelemetryTracing(true)`
in `BigQueryReadSettings` and wired the `GrpcOpenTelemetry` interceptor
to the channel builder.
- **Global OTel**: Ensured the `useGlobalOpenTelemetry` flag is
respected when configuring the Storage API client.
b/517498094

This PR fixes dependency analysis failures and flaky test issues
identified in the OpenTelemetry integration feature branch.
…13515)

b/524234554

This PR fixes two issues in the OpenTelemetry implementation within the
BigQuery JDBC driver:
1. **Shading/Relocation namespace exclusions**: Corrects the API shading
rules to recursively exclude nested OpenTelemetry API subpackages. This
resolves dependency conflicts and `AbstractMethodError` crashes when
client applications inject custom OTel SDK instances.
2. **Telemetry Credentials Resolution bug**: Fixes an
`IllegalArgumentException` thrown when parsing OAuth authentication
types during zero-config credentials initialization.
@keshavdandeva keshavdandeva removed the do not merge Indicates a pull request not ready for merge, due to either quality or timing. label Jul 21, 2026
@keshavdandeva
keshavdandeva marked this pull request as ready for review July 22, 2026 22:34
@keshavdandeva
keshavdandeva requested review from a team as code owners July 22, 2026 22:34
…el (#13866)

b/537284101

This PR fixes multiple OpenTelemetry resource leaks.

### Key Changes
1. **Fix Thread Leaks (Reference Counting):** Wrapped `OpenTelemetrySdk`
in a `CachedSdk` to track usage. The SDK and its background threads are
now explicitly closed when the last JDBC `Connection` using them is
closed.
2. **Fix Classloader Leaks:** Removed the redundant
`Runtime.addShutdownHook` in `BigQueryJdbcOpenTelemetry`. This prevents
severe `Metaspace` memory leaks when the driver is undeployed in
Application Servers (like Tomcat/JBoss).
3. **Fix Service Account Path Fallback:** Updated
`resolveEffectiveCredentials()` to properly detect
`OAUTH_PVT_KEY_PATH_PROPERTY_NAME` (key file paths), preventing
erroneous fallbacks to Application Default Credentials.
4. **Fix Test Quota Limits:** Increased the polling delay in
`ITOpenTelemetryTest` from 500ms to 3000ms. This prevents the GCP
Logging API from rejecting the test with `RESOURCE_EXHAUSTED` (Status
429) errors due to exceeding the 60 requests/minute quota limit.
5. **Fix ADC support**
@keshavdandeva
keshavdandeva enabled auto-merge (squash) July 24, 2026 15:23
import java.util.logging.Handler;
import java.util.logging.Logger;

public class BigQueryJdbcOpenTelemetry {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Typically the JDBC specific files are package private.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

LogEntry.Builder builder =
LogEntry.newBuilder(Payload.StringPayload.of(formatMessage(record)))
.setSeverity(mapGcpSeverity(record.getLevel()))
.setTimestamp(record.getMillis())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method maybe deprecated in the Logging Library. Please double check.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it was deprecated. Fixed it

@@ -151,15 +151,17 @@ public static Logger getRootLogger() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Future PR: Add the trace and span IDs to the log file Formatter

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created b/538631816

Baggage.fromContext(Context.current())
.getEntryValue(BigQueryJdbcOpenTelemetry.CONNECTION_ID_BAGGAGE_KEY);

if (connectionId == null) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is dropping the logs when the connection id is available from BigQueryJdbcMdc.getConnectionId();. It can even fallback to LogRecord for the connection ID. Only drop logs if, connection ID is not available from anywhere.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, added the connectionId = BigQueryJdbcMdc.getConnectionId(); check as well

gcpTelemetryProjectId,
getCredentialsIdentifier(gcpTelemetryCredentials),
enableGcpTraceExporter);
return sdkCache.compute(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may be an edge case, but it might be a good idea to pre-compute the heavy work in this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I moved the heavy work out of the synchronized sdkCache.compute() block to prevent it from blocking other threads during a cache miss

@keshavdandeva
keshavdandeva requested a review from Neenu1995 July 24, 2026 18:55
@keshavdandeva
keshavdandeva merged commit af18f65 into main Jul 24, 2026
206 checks passed
@keshavdandeva
keshavdandeva deleted the jdbc/feature-branch-otel branch July 24, 2026 19:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants