Skip to content

feat(bigquery-jdbc): add TelemetryManager singleton foundation and exception safeguards - #14047

Closed
Neenu1995 wants to merge 18 commits into
mainfrom
jdbc-telemetry-pr7-manager-core
Closed

feat(bigquery-jdbc): add TelemetryManager singleton foundation and exception safeguards#14047
Neenu1995 wants to merge 18 commits into
mainfrom
jdbc-telemetry-pr7-manager-core

Conversation

@Neenu1995

Copy link
Copy Markdown
Contributor

No description provided.

Neenu1995 and others added 18 commits July 2, 2026 09:47
…s.proto (#13527)

b/527947900

* **Build Configuration (`java-bigquery-jdbc/pom.xml`)**:
* Configured `os-maven-plugin` to detect platform-specific system
variables (e.g. `${os.detected.classifier}`).
* Added `protobuf-maven-plugin` bound to the compilation lifecycle,
utilizing `protoc:3.25.5` for generating Java classes from protobuf
sources.
* **Telemetry Schema
(`google/cloud/bigquery/jdbc/telemetry/v1/clientanalytics.proto`)**:
* Defined proto3 schema wrapper messages (`LogRequest`, `ClientInfo`,
`LogEvent`, `LogResponse`) for recording and reporting client-side
telemetry events to the backend log collector.
## Summary
Introduces the internal `TelemetryConfiguration` class and builder to
manage client-side telemetry settings for the BigQuery JDBC driver.

This is **PR 3** of the multi-phase client-side telemetry implementation
plan.

## Changes Introduced
- **`TelemetryConfiguration`**: Immutable configuration class holding
upload intervals, batch size thresholds, log source ID, target endpoint,
and environment metadata (`DriverEnvironment`).
- **`TelemetryConfiguration.Builder`**: Fluent builder pattern for
constructing configuration instances.
- **`TelemetryConfigurationTest`**: Unit test suite covering default
property initialization, custom property overrides, and
`equals`/`hashCode` contracts.
- **Visibility Scoping**: Restricted all classes, builders, getters, and
constants to package-private
(`com.google.cloud.bigquery.jdbc.telemetry.v1`) to prevent exposing
internal telemetry implementation details outside the driver package.

## Default Configuration Parameters
| Parameter | Default Value | Description |
| :--- | :--- | :--- |
| `enabled` | `true` | Telemetry is enabled by default per open-source
telemetry guidelines (`go/telemetry-oss`). |
| `logSource` | `-1` | Placeholder until Clearcut log source ID
registration is assigned for BigQuery JDBC. |
| `endpointUrl` | `https://play.googleapis.com/log` | Default Clearcut
HTTPS log ingestion endpoint. |
| `uploadIntervalMs` | `300000` (5 mins) | Periodic background flush
interval. |
| `batchSizeThreshold` | `100` | Maximum buffered events before
triggering an immediate flush. |
b/527947900

This is PR4 of multi-part telemetry client implementation. This PR
implements `DriverEnvironmentBuilder` and its corresponding unit tests
(`DriverEnvironmentBuilderTest`) as part of the BigQuery JDBC telemetry
client infrastructure.

It provides a package-private utility for constructing
`DriverEnvironment` protocol buffer payloads by inspecting client
runtime properties and managing a persistent installation-scoped UUID.

#### Key Changes
- **Environment Detection**:
- Extracts major Java version (supporting both legacy `1.8.x` and modern
`11+`/`17+` formats).
- Maps OS names to standard `DriverEnvironment.OsType` enums (Windows,
macOS/Darwin, Linux, Solaris, BSDs, AIX).
- Extracts major OS version and sanitizes driver version strings (to
`major.minor`).
- **Telemetry Tag Management**:
  - Manages a persistent UUID in `~/.bigquery-jdbc/telemetry-tag`.
- Includes defensive fallback logic: handles missing `user.home`
(serverless/container runtimes), read-only file systems,
`SecurityException`s, and automatically overwrites corrupted/invalid
file contents with a fresh UUID.
…patcher (#13772)

Finalizes the `TelemetryBatcher` infrastructure for high-performance,
non-blocking telemetry collection and dispatching in the BigQuery JDBC
driver.

### Key Functionality Added:
* **Non-Blocking Telemetry Ingestion**: Buffers connection attempts,
statement executions, error metrics, and feature usage events in
capacity-bounded `LinkedBlockingQueue` storage (max 10,000 items per
queue).
* **Fine-Grained Concurrency Control**: Uses an explicit `ReentrantLock`
(`flushLock`) for thread-safe flush operations, task rescheduling, and
shutdown without locking producer threads.
* **Efficient Payload Sizing**: Implements single-pass bulk payload
trimming to strictly enforce the 512 KB payload threshold before
transport transmission.
* **Optimized Batch Draining**: Leverages `BlockingQueue.drainTo()` to
drain telemetry batches in a single operation, minimizing lock
acquisition overhead.
* **Conditional Resource Allocation**: Lazily allocates the
`ScheduledExecutorService` and background dispatcher thread only when
telemetry is explicitly enabled.
@Neenu1995
Neenu1995 requested review from a team as code owners August 11, 2026 22:20
@Neenu1995 Neenu1995 closed this Aug 11, 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 introduces a client-side telemetry framework for the BigQuery JDBC driver, including protobuf definitions, configuration management, HTTP transport to Clearcut, an event batcher, and a singleton manager. Review feedback identifies critical compilation errors in TelemetryManager and its tests due to referencing a non-existent builder() method instead of newBuilder(). Additionally, a logical bug was found in TelemetryManager.init() where a disabled configuration fails to persist, causing subsequent calls to re-initialize telemetry with default enabled settings. Finally, updating TelemetryManagerTest from JUnit 4 to JUnit 5 is recommended for consistency with the other new test suites.

synchronized (TelemetryManager.class) {
localRef = instance;
if (localRef == null) {
TelemetryConfiguration config = TelemetryConfiguration.builder().build();

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.

critical

The class TelemetryConfiguration does not have a builder() method. It defines newBuilder() instead. This will cause a compilation error.

Suggested change
TelemetryConfiguration config = TelemetryConfiguration.builder().build();
TelemetryConfiguration config = TelemetryConfiguration.newBuilder().build();

@Test
public void testInit_withDisabledConfig_doesNotInitializeInstance() {
TelemetryConfiguration config = TelemetryConfiguration.builder().setEnabled(false).build();
ClearcutTransport transport = new ClearcutTransport(config);

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.

critical

Use TelemetryConfiguration.newBuilder() instead of builder() to avoid compilation errors.

Suggested change
ClearcutTransport transport = new ClearcutTransport(config);
TelemetryConfiguration config = TelemetryConfiguration.newBuilder().setEnabled(false).build();

@Test
public void testInit_withEnabledConfig_initializesCustomInstance() {
TelemetryConfiguration config = TelemetryConfiguration.builder().setEnabled(true).build();
ClearcutTransport transport = new ClearcutTransport(config);

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.

critical

Use TelemetryConfiguration.newBuilder() instead of builder() to avoid compilation errors.

Suggested change
ClearcutTransport transport = new ClearcutTransport(config);
TelemetryConfiguration config = TelemetryConfiguration.newBuilder().setEnabled(true).build();

Comment on lines +66 to +72
static synchronized void init(TelemetryConfiguration config, ClearcutTransport transport) {
closeInstance();
if (config != null && config.isEnabled() && transport != null) {
TelemetryBatcher batcher = new TelemetryBatcher(config, transport);
instance = new TelemetryManager(batcher);
}
}

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.

high

If init is called with a disabled configuration (i.e., config.isEnabled() is false), the instance field is left as null. Consequently, any subsequent call to TelemetryManager.getInstance() will see that instance is null and will re-initialize it using the default configuration (which is enabled by default). This completely bypasses the explicit disabling of telemetry.

To fix this, we should allow TelemetryManager to be initialized with a disabled configuration so that instance is non-null, or use another mechanism to prevent re-initialization when explicitly disabled.

Comment on lines +19 to +29
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;

import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

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.

medium

This test file uses JUnit 4 imports and annotations (org.junit.Test, @Before, @After), whereas all other new test files in this PR use JUnit 5 (Jupiter). For consistency and modern testing practices, please migrate this test file to JUnit 5.

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.

1 participant