feat(bigquery-jdbc): add TelemetryManager singleton foundation and exception safeguards - #14047
feat(bigquery-jdbc): add TelemetryManager singleton foundation and exception safeguards#14047Neenu1995 wants to merge 18 commits into
Conversation
…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.
…-cloud-java into jdbc-telemetry-feature
## 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.
…ception safeguards
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
The class TelemetryConfiguration does not have a builder() method. It defines newBuilder() instead. This will cause a compilation error.
| 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); |
There was a problem hiding this comment.
| @Test | ||
| public void testInit_withEnabledConfig_initializesCustomInstance() { | ||
| TelemetryConfiguration config = TelemetryConfiguration.builder().setEnabled(true).build(); | ||
| ClearcutTransport transport = new ClearcutTransport(config); |
There was a problem hiding this comment.
| 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); | ||
| } | ||
| } |
There was a problem hiding this comment.
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.
| 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; |
No description provided.