This is an automated email from the ASF dual-hosted git repository.
lidavidm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-adbc.git
The following commit(s) were added to refs/heads/main by this push:
new a727830d57 fix(go/adbc/driver): corrects 'none' trace exporter
handling (#4822)
a727830d57 is described below
commit a727830d5722262fc7c3e24b6f8edb982c7b9b29
Author: Bruce Irschick <[email protected]>
AuthorDate: Wed Sep 30 17:24:00 2026 -0700
fix(go/adbc/driver): corrects 'none' trace exporter handling (#4822)
This pull request enhances the tracing functionality and its test
coverage for the FlightSQL ADBC driver. The main changes include
refactoring the tracing test logic for better reusability, adding
comprehensive tests for tracing exporter configuration (including
default and override folder handling), and ensuring that explicitly
disabling tracing uses the global tracer provider.
**Tracing test improvements:**
* Refactored tracing test logic by extracting common functionality into
helper functions: `executeFlightSQLTraceQuery`, `traceFiles`, and
`setDefaultTracingFolder` in `flightsql_adbc_test.go`. This improves
test readability and maintainability.
[[1]](diffhunk://#diff-1147cdf8ab7a5dcb1d84bcb2b7a2185cf2fc3802b7eb3718bffadfe990ecdf56L320-L336)
[[2]](diffhunk://#diff-1147cdf8ab7a5dcb1d84bcb2b7a2185cf2fc3802b7eb3718bffadfe990ecdf56L357-R396)
* Added new tests to verify tracing exporter behavior:
- Test that enabling and disabling the ADBC file exporter produces or
omits trace files as expected.
- Test that the default tracing folder is used when no folder is
specified.
- Test that specifying a tracing folder option overrides the default
folder and prevents traces from being written to the default location.
**Tracing exporter configuration:**
* Updated the tracing initialization logic in `DatabaseImplBase` so that
both an empty exporter name and an explicit `TelemetryExporterNone`
value result in using the global tracer provider, ensuring tracing is
effectively disabled in these cases.
* Added a unit test to verify that setting the exporter to
`TelemetryExporterNone` uses the global tracer provider, ensuring
correct behavior when tracing is disabled.
**Test infrastructure:**
* Imported the OpenTelemetry package in `driver_test.go` to support the
new tracer provider assertions.
Developed with assistance from GitHub Copilot (Copilot SDK in VS Code).
Co-authored-by: Bruce Irschick (Bit Quill Technologies Inc)
<[email protected]>
---
go/adbc/driver/flightsql/flightsql_adbc_test.go | 137 ++++++++++++++++------
go/adbc/driver/internal/driverbase/database.go | 4 +-
go/adbc/driver/internal/driverbase/driver_test.go | 14 +++
3 files changed, 120 insertions(+), 35 deletions(-)
diff --git a/go/adbc/driver/flightsql/flightsql_adbc_test.go
b/go/adbc/driver/flightsql/flightsql_adbc_test.go
index d7dc28c3f4..0a73eabcc7 100644
--- a/go/adbc/driver/flightsql/flightsql_adbc_test.go
+++ b/go/adbc/driver/flightsql/flightsql_adbc_test.go
@@ -340,10 +340,12 @@ func TestADBCFlightSQL(t *testing.T) {
suite.Run(t, &DomainSocketTests{db: db})
}
-func TestFlightSQLTracingProducesTraceFiles(t *testing.T) {
+func executeFlightSQLTraceQuery(t *testing.T, tracingOpts map[string]string) {
+ t.Helper()
+
// TODO: Reuse example.CreateDB() here after apache/arrow-go#916
isolates
// the shared in-memory SQLite database per call.
- db, err := sql.Open("sqlite",
fmt.Sprintf("file:%s-%d?mode=memory&cache=private", strings.ToLower(t.Name()),
time.Now().UnixNano()))
+ db, err := sql.Open("sqlite",
fmt.Sprintf("file:trace-%d?mode=memory&cache=private", time.Now().UnixNano()))
require.NoError(t, err)
defer validation.CheckedClose(t, db)
@@ -351,49 +353,118 @@ func TestFlightSQLTracingProducesTraceFiles(t
*testing.T) {
drv := q.SetupDriver(t)
defer q.TearDownDriver(t, drv)
- traceDir := t.TempDir()
opts := q.DatabaseOptions()
- opts[adbc.OptionKeyTelemetryTracesExporter] =
string(adbc.TelemetryExporterAdbcFile)
- opts[adbc.OptionKeyTelemetryTracesFolderPath] = traceDir
+ for key, value := range tracingOpts {
+ opts[key] = value
+ }
- func() {
- adbcDB, err := drv.NewDatabase(opts)
- require.NoError(t, err)
- defer validation.CheckedClose(t, adbcDB)
+ adbcDB, err := drv.NewDatabase(opts)
+ require.NoError(t, err)
+ defer validation.CheckedClose(t, adbcDB)
- cnxn, err := adbcDB.Open(context.Background())
- require.NoError(t, err)
- defer validation.CheckedClose(t, cnxn)
+ cnxn, err := adbcDB.Open(context.Background())
+ require.NoError(t, err)
+ defer validation.CheckedClose(t, cnxn)
- stmt, err := cnxn.NewStatement()
- require.NoError(t, err)
- defer validation.CheckedClose(t, stmt)
+ stmt, err := cnxn.NewStatement()
+ require.NoError(t, err)
+ defer validation.CheckedClose(t, stmt)
- require.NoError(t, stmt.SetSqlQuery("SELECT 1"))
- reader, _, err := stmt.ExecuteQuery(context.Background())
- require.NoError(t, err)
- defer reader.Release()
+ require.NoError(t, stmt.SetSqlQuery("SELECT 1"))
+ reader, _, err := stmt.ExecuteQuery(context.Background())
+ require.NoError(t, err)
+ defer reader.Release()
- for reader.Next() {
- }
- require.NoError(t, reader.Err())
- }()
+ for reader.Next() {
+ }
+ require.NoError(t, reader.Err())
+}
+
+func traceFiles(t *testing.T, traceDir string) []string {
+ t.Helper()
files, err := filepath.Glob(filepath.Join(traceDir, "*.jsonl"))
require.NoError(t, err)
- require.NotEmpty(t, files)
+ return files
+}
- var traceOutput strings.Builder
- for _, file := range files {
- data, err := os.ReadFile(file)
- require.NoError(t, err)
- traceOutput.Write(data)
+func setDefaultTracingFolder(t *testing.T) string {
+ t.Helper()
+
+ tempDir := t.TempDir()
+ switch runtime.GOOS {
+ case "windows":
+ localAppDataDir := filepath.Join(tempDir, "AppData", "Local")
+ t.Setenv("LocalAppData", localAppDataDir)
+ return filepath.Join(localAppDataDir, "ADBC", "Traces")
+ case "darwin":
+ t.Setenv("HOME", tempDir)
+ return filepath.Join(tempDir, "Library", "Application Support",
"ADBC", "Traces")
+ default:
+ stateDir := filepath.Join(tempDir, ".local", "state")
+ t.Setenv("XDG_STATE_HOME", stateDir)
+ t.Setenv("HOME", tempDir)
+ return filepath.Join(stateDir, "adbc", "traces")
}
+}
+
+func TestFlightSQLTracingAdbcFileExporterCanBeEnabledAndDisabled(t *testing.T)
{
+ t.Run("enabled", func(t *testing.T) {
+ traceDir := t.TempDir()
+ executeFlightSQLTraceQuery(t, map[string]string{
+ adbc.OptionKeyTelemetryTracesExporter:
string(adbc.TelemetryExporterAdbcFile),
+ adbc.OptionKeyTelemetryTracesFolderPath: traceDir,
+ })
+
+ files := traceFiles(t, traceDir)
+ require.NotEmpty(t, files)
+
+ var traceOutput strings.Builder
+ for _, file := range files {
+ data, err := os.ReadFile(file)
+ require.NoError(t, err)
+ traceOutput.Write(data)
+ }
+
+ output := traceOutput.String()
+ require.Contains(t, output, "FlightSQL.Database.Open")
+ require.Contains(t, output, "FlightSQL.Database.Close")
+ require.Contains(t, output, "FlightSQL.Statement.ExecuteQuery")
+ })
+
+ t.Run("disabled", func(t *testing.T) {
+ traceDir := t.TempDir()
+ executeFlightSQLTraceQuery(t, map[string]string{
+ adbc.OptionKeyTelemetryTracesExporter:
string(adbc.TelemetryExporterNone),
+ adbc.OptionKeyTelemetryTracesFolderPath: traceDir,
+ })
+
+ require.Empty(t, traceFiles(t, traceDir))
+ })
+}
+
+func TestFlightSQLTracingAdbcFileExporterUsesDefaultFolder(t *testing.T) {
+ defaultTraceDir := setDefaultTracingFolder(t)
+
+ executeFlightSQLTraceQuery(t, map[string]string{
+ adbc.OptionKeyTelemetryTracesExporter:
string(adbc.TelemetryExporterAdbcFile),
+ })
+
+ require.NotEmpty(t, traceFiles(t, defaultTraceDir))
+}
+
+func TestFlightSQLTracingFolderOptionOverridesDefaultFolder(t *testing.T) {
+ defaultTraceDir := setDefaultTracingFolder(t)
+ overrideTraceDir := t.TempDir()
+
+ executeFlightSQLTraceQuery(t, map[string]string{
+ adbc.OptionKeyTelemetryTracesExporter:
string(adbc.TelemetryExporterAdbcFile),
+ adbc.OptionKeyTelemetryTracesFolderPath: overrideTraceDir,
+ })
- output := traceOutput.String()
- require.Contains(t, output, "FlightSQL.Database.Open")
- require.Contains(t, output, "FlightSQL.Database.Close")
- require.Contains(t, output, "FlightSQL.Statement.ExecuteQuery")
+ require.NotEmpty(t, traceFiles(t, overrideTraceDir))
+ _, err := os.Stat(defaultTraceDir)
+ require.ErrorIs(t, err, os.ErrNotExist)
}
// TestFlightSQLTracingCleansUpAfterConstructionFailure verifies that failures
diff --git a/go/adbc/driver/internal/driverbase/database.go
b/go/adbc/driver/internal/driverbase/database.go
index fb664f7199..50693a66bd 100644
--- a/go/adbc/driver/internal/driverbase/database.go
+++ b/go/adbc/driver/internal/driverbase/database.go
@@ -277,8 +277,8 @@ func (base *DatabaseImplBase) InitTracing(
exporterName = getExporterName()
}
- // Empty exporter
- if exporterName == "" {
+ // Empty or explicitly disabled exporter
+ if exporterName == "" || exporterName ==
string(adbc.TelemetryExporterNone) {
base.tracerProvider = otel.GetTracerProvider()
base.Tracer = otel.Tracer(fullyQualifiedDriverName)
return
diff --git a/go/adbc/driver/internal/driverbase/driver_test.go
b/go/adbc/driver/internal/driverbase/driver_test.go
index 2084cd140c..808f581e31 100644
--- a/go/adbc/driver/internal/driverbase/driver_test.go
+++ b/go/adbc/driver/internal/driverbase/driver_test.go
@@ -36,6 +36,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
+ "go.opentelemetry.io/otel"
)
const (
@@ -460,6 +461,19 @@ func TestCustomizedDriver(t *testing.T) {
}
}
+func TestTracingExporterNoneUsesGlobalTracerProvider(t *testing.T) {
+ info := driverbase.DefaultDriverInfo("MockDriver")
+ drv := driverbase.NewDriverImplBase(info, memory.DefaultAllocator)
+
+ dbBase, err := driverbase.NewDatabaseImplBase(context.Background(),
&drv, driverbase.TracingOptions{
+ ExporterName: string(adbc.TelemetryExporterNone),
+ })
+ require.NoError(t, err)
+ require.Same(t, otel.GetTracerProvider(), dbBase.GetTracerProvider())
+ require.NoError(t, dbBase.ForceFlushTracing(context.Background()))
+ require.NoError(t, dbBase.Close())
+}
+
type driverImpl struct {
driverbase.DriverImplBase