Conversation
a169f36 to
0a27469
Compare
| **Mapping:** | ||
| | Auth Config | auth_type String | | ||
| |---|---| | ||
| | PAT | `"pat"` | |
There was a problem hiding this comment.
For this SEA/Thrift should be identical, we should have authMech and authFlow.
| EnableArrow = true, // Always true for ADBC driver | ||
| RowsFetchedPerBlock = GetBatchSize(), | ||
| SocketTimeout = GetSocketTimeout(), | ||
| EnableDirectResults = true, |
There was a problem hiding this comment.
Some parameters are not shared between Thrift and SEA, e.g. EnableDirectResults
| +GetInfo() QueryResult | ||
| } | ||
| class StatementTelemetryContext { | ||
| +OperationType OperationTypeEnum |
There was a problem hiding this comment.
What are OperationTypeEnum consist of?
| - No `TelemetrySessionContext` creation | ||
| - No `TelemetryClient` initialization | ||
| - `StatementExecutionStatement` has no telemetry context creation or `EmitTelemetry()` calls | ||
| - `DriverMode` is hardcoded to `THRIFT` in `DatabricksConnection.BuildDriverConnectionParams()` - there is no code path that ever sets `SEA` |
There was a problem hiding this comment.
User should be able to override this from adbc.databricks.protocol?
|
|
||
| | Field | Status | Notes | | ||
| |---|---|---| | ||
| | `WorkspaceId` | **NOT SET** | Declared in TelemetrySessionContext but never populated during InitializeTelemetry() | |
There was a problem hiding this comment.
How do we plan to populate this?
For non-spog it is usually resolvable from the host, I wonder if Thrift ever expose this information at all?
For spog it will be passed in as query parameter as part of httpPath
| - Would still need duplicated field declarations in each class | ||
| - Awkward pattern for C# compared to Java | ||
|
|
||
| **Option C: Composition via TelemetryHelper (chosen)** |
There was a problem hiding this comment.
Yes I agree with Composition is the right direction
There was a problem hiding this comment.
Pull request overview
Adds a design document that analyzes current telemetry coverage in the Databricks ADBC C# driver and proposes a phased plan to close identified gaps (notably SEA/Statement Execution having no telemetry today), including field-by-field proto alignment and E2E validation strategy.
Changes:
- Introduces a comprehensive telemetry gap analysis against the telemetry proto schema (including SEA vs Thrift coverage).
- Proposes a
TelemetryHelpercomposition approach to share telemetry logic across the divergent Thrift and SEA class hierarchies. - Defines an implementation plan (phased) including chunk-metrics (
ChunkDetails) wiring and E2E tests asserting proto field population.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| No new concurrency concerns. All changes follow existing patterns: | ||
| - `TelemetrySessionContext` is created once per connection (single-threaded) | ||
| - `StatementTelemetryContext` is created once per statement execution (single-threaded within statement) | ||
| - `TelemetryClient.Enqueue()` is already thread-safe |
There was a problem hiding this comment.
The Concurrency section claims “No new concurrency concerns,” but the proposed Phase 4 work aggregates per-chunk metrics inside CloudFetchDownloader, which downloads chunks concurrently. The design should call out that chunk-metric aggregation must be thread-safe (e.g., interlocked updates or locking) to avoid races when multiple download tasks complete in parallel.
| No new concurrency concerns. All changes follow existing patterns: | |
| - `TelemetrySessionContext` is created once per connection (single-threaded) | |
| - `StatementTelemetryContext` is created once per statement execution (single-threaded within statement) | |
| - `TelemetryClient.Enqueue()` is already thread-safe | |
| Most changes follow existing concurrency patterns, but Phase 4 introduces one new consideration: per-chunk metric aggregation inside `CloudFetchDownloader` must be thread-safe because chunks are downloaded concurrently. Implementations MUST use appropriate synchronization (e.g., interlocked updates, locks, or thread-safe data structures) when updating shared metric state from multiple download tasks. | |
| - `TelemetrySessionContext` is created once per connection (single-threaded) | |
| - `StatementTelemetryContext` is created once per statement execution (single-threaded within statement) | |
| - `TelemetryClient.Enqueue()` is already thread-safe, and `CloudFetchDownloader` must ensure all per-chunk metric updates are also thread-safe |
|
|
||
| ## Objective | ||
|
|
||
| Ensure the ADBC C# driver reports **all** proto-defined telemetry fields to the Databricks backend, matching the JDBC driver's coverage. Close gaps in field population, expand coverage to metadata operations, and add E2E tests verifying every proto field. |
There was a problem hiding this comment.
The Objective states the driver should report all proto-defined telemetry fields, but later sections explicitly list proto fields that are intentionally left unset (e.g., many DriverConnectionParameters fields). Consider tightening the Objective wording to “all applicable proto fields” or explicitly scope which fields are expected to be populated vs intentionally omitted, to avoid a contradictory goal statement.
| Ensure the ADBC C# driver reports **all** proto-defined telemetry fields to the Databricks backend, matching the JDBC driver's coverage. Close gaps in field population, expand coverage to metadata operations, and add E2E tests verifying every proto field. | |
| Ensure the ADBC C# driver reports **all applicable** proto-defined telemetry fields to the Databricks backend, matching the JDBC driver's coverage, while explicitly documenting any proto fields that are intentionally left unset. Close gaps in field population, expand coverage to metadata operations, and add E2E tests verifying every applicable proto field. |
| | Aspect | Thrift (DatabricksConnection) | SEA (StatementExecutionConnection) | | ||
| |---|---|---| | ||
| | Base class | SparkHttpConnection | TracingConnection | | ||
| | Session creation | `OpenSessionWithInitialNamespace()` Thrift RPC | `CreateSessionAsync()` REST API | |
There was a problem hiding this comment.
The Thrift session creation entry references OpenSessionWithInitialNamespace(), but that method name does not exist in the C# codebase (the Thrift path builds a TOpenSessionReq and handles TOpenSessionResp). Consider updating this row to reference the actual method(s)/RPCs used (e.g., OpenSession / CreateSessionRequest() / HandleOpenSessionResponse()), so the design doc stays aligned with current implementation.
| | Session creation | `OpenSessionWithInitialNamespace()` Thrift RPC | `CreateSessionAsync()` REST API | | |
| | Session creation | `OpenSession` Thrift RPC (`TOpenSessionReq` / `TOpenSessionResp`) | `CreateSessionAsync()` REST API | |
| No new configuration parameters are needed. All changes use existing connection properties and runtime information. | ||
|
|
There was a problem hiding this comment.
The Configuration section says no new configuration parameters are needed, but earlier the doc proposes reading adbc.databricks.client_app_name to populate client_app_name. That’s either a new optional connection property (should be documented here and added to DatabricksParameters in the implementation), or the design should be adjusted to derive the value from existing inputs (e.g., process name / User-Agent) without introducing a new key.
| No new configuration parameters are needed. All changes use existing connection properties and runtime information. | |
| This design introduces a single **optional** connection property to control telemetry: | |
| - `adbc.databricks.client_app_name` (string, optional): If set, this value is propagated to the `client_app_name` field in telemetry events. If not set, the driver derives `client_app_name` from existing inputs (for example, the process name and/or User-Agent), preserving current behavior. | |
| All other changes use existing connection properties and runtime information; no mandatory new configuration is required. |
Comprehensive gap analysis of telemetry proto field coverage including: - SEA connections have zero telemetry (highest priority) - ChunkDetails.SetChunkDetails() defined but never called - Missing fields: auth_type, WorkspaceId, runtime_vendor, client_app_name - Composition via TelemetryHelper chosen over abstract base class - E2E test strategy for all proto fields across both protocols Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…A second) Co-authored-by: Isaac
094dc6e to
425a554
Compare
🥞 Stacked PR
Use this link to review incremental changes.
Summary
ChunkDetails.SetChunkDetails()is defined but never called from CloudFetch pipelineauth_type,WorkspaceId,runtime_vendor,client_app_name, and moreTelemetryHelpercomposition pattern to share telemetry logic between Thrift and SEAKey decisions and alternatives considered
TelemetryHelperover abstract base class: Thrift has 4 intermediate inheritance layers (HiveServer2 → Spark → SparkHttp) that SEA doesn't share. C# single inheritance makes a shared base class infeasible without restructuring the Thrift chain. Static helper is the standard C# pattern for cross-hierarchy sharing.Areas needing specific review focus
TelemetryHelpercomposition approach acceptable, or should we consider restructuring the inheritance chain?🤖 Generated with Claude Code