This is an automated email from the ASF dual-hosted git repository.

curth 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 95fff2a3d feat(csharp/src/Drivers): instrument tracing exporters for 
BigQuery/Apache drivers (#3315)
95fff2a3d is described below

commit 95fff2a3d58a1e343d717243e76f9e99a14bb355
Author: Bruce Irschick <[email protected]>
AuthorDate: Wed Sep 24 12:26:30 2025 -0700

    feat(csharp/src/Drivers): instrument tracing exporters for BigQuery/Apache 
drivers (#3315)
    
    Adds instrumentation to support tracing exporters
    
    # Traces Listeners
    
    ## FileActivityListener
    
    Provides an ActivityListener to write telemetry traces to
    rotating files in folder. File names are created with the following
    pattern:
    `<trace-source>-<YYYY-MM-DD-HH-mm-ss-fff>-<process-id>.log`.
    
    For example:
    `apache.arrow.adbc.drivers.databricks-2025-08-15-10-35-56-012345-99999.log`.
    
    The default folder used is:
    
    | Platform | Folder |
    | --- | --- |
    | Windows | `%LOCALAPPDATA%/Apache.Arrow.Adbc/Traces` |
    | macOS | `$HOME/Library/Application Support/Apache.Arrow.Adbc/Traces` |
    | Linux   | `$HOME/.local/share/Apache.Arrow.Adbc/Traces` |
    
    By default, up to 999 files of maximum size 1024 KB are written to
    the trace folder.
    
    The environment variable `OTEL_TRACES_EXPORTER` can be used to select
    one of the
    available exporters. Or the database parameter `adbc.traces.exporter`
    can be used,
    which has precedence over the environment variable.
    
    The following listeners are supported:
    
    | Listener | Description |
    | --- | --- |
    | `adbcfile` | Exports traces to rotating files in a folder. |
    
    The `FileActivityListener` is designed to allow an instance to be
    associated with and have the same lifespan as a `Connection` instance.
---
 csharp/Apache.Arrow.Adbc.sln                       |  20 +++
 .../Apache/Apache.Arrow.Adbc.Drivers.Apache.csproj |   1 +
 .../Drivers/Apache/Hive2/HiveServer2Connection.cs  |  35 ++++-
 csharp/src/Drivers/Apache/Hive2/README.md          |  31 ++++
 csharp/src/Drivers/Apache/Impala/README.md         |  31 ++++
 csharp/src/Drivers/Apache/Spark/README.md          |  31 ++++
 .../Apache.Arrow.Adbc.Drivers.BigQuery.csproj      |   1 +
 csharp/src/Drivers/BigQuery/BigQueryConnection.cs  |  35 ++++-
 csharp/src/Drivers/BigQuery/BigQueryStatement.cs   |  10 +-
 csharp/src/Drivers/BigQuery/BigQueryUtils.cs       |  13 --
 csharp/src/Drivers/BigQuery/readme.md              |  31 ++++
 csharp/src/Drivers/Databricks/readme.md            |  31 ++++
 ...he.Arrow.Adbc.Telemetry.Traces.Exporters.csproj |   1 +
 .../Telemetry/Traces/Exporters/ExportersBuilder.cs |  63 +++++++--
 .../Telemetry/Traces/Exporters/ExportersOptions.cs |  10 +-
 .../Traces/Exporters/FileExporter/FileExporter.cs  |   1 +
 .../FileExporter/FileExporterExtensions.cs         |   2 +-
 csharp/src/Telemetry/Traces/Exporters/readme.md    |   4 +-
 ...he.Arrow.Adbc.Telemetry.Traces.Listeners.csproj |  18 +++
 .../Listeners/FileListener/ActivityProcessor.cs    | 118 ++++++++++++++++
 .../Listeners/FileListener/FileActivityListener.cs | 154 ++++++++++++++++++++
 .../FileListener}/SerializableActivity.cs          |   2 +-
 .../FileListener}/TracingFile.cs                   |  22 +--
 .../ListenersOptions.cs}                           |  25 ++--
 .../Traces/Listeners/Properties/AssemblyInfo.cs    |  19 +++
 .../Traces/{Exporters => Listeners}/readme.md      |  23 ++-
 .../test/Drivers/Apache/Common/TelemetryTests.cs   | 110 +++++++++++++++
 csharp/test/Drivers/Apache/Hive2/TelemetryTests.cs |  29 ++++
 .../test/Drivers/Apache/Impala/TelemetryTests.cs   |  30 ++++
 csharp/test/Drivers/Apache/Spark/TelemetryTests.cs |  30 ++++
 csharp/test/Drivers/BigQuery/TelemetryTests.cs     | 120 ++++++++++++++++
 .../test/Drivers/Databricks/E2E/TelemetryTests.cs  |  30 ++++
 .../Exporters/FileExporter/FileExporterTests.cs    |   7 +-
 ...ow.Adbc.Tests.Telemetry.Traces.Listeners.csproj |  29 ++++
 .../FileListener/FileActivityListenerTests.cs      | 157 +++++++++++++++++++++
 .../FileExporter => Listeners}/TracingFileTests.cs |  25 ++--
 36 files changed, 1205 insertions(+), 94 deletions(-)

diff --git a/csharp/Apache.Arrow.Adbc.sln b/csharp/Apache.Arrow.Adbc.sln
index e79981db6..a0ab271af 100644
--- a/csharp/Apache.Arrow.Adbc.sln
+++ b/csharp/Apache.Arrow.Adbc.sln
@@ -58,6 +58,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = 
"Exporters", "Exporters", "{
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = 
"Apache.Arrow.Adbc.Tests.Telemetry.Traces.Exporters", 
"test\Telemetry\Traces\Exporters\Apache.Arrow.Adbc.Tests.Telemetry.Traces.Exporters.csproj",
 "{1558BC4B-6E76-434B-8877-6C49B1460544}"
 EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Listeners", "Listeners", 
"{53C45FD3-7277-49FA-AEEB-DF8F2386ECAA}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Listeners", "Listeners", 
"{1C530561-1008-4F39-B437-15B2FD59EAC9}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = 
"Apache.Arrow.Adbc.Tests.Telemetry.Traces.Listeners", 
"test\Telemetry\Traces\Listeners\Apache.Arrow.Adbc.Tests.Telemetry.Traces.Listeners.csproj",
 "{9CE9106B-ACBB-54C1-DE57-370E5CF09363}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = 
"Apache.Arrow.Adbc.Telemetry.Traces.Listeners", 
"src\Telemetry\Traces\Listeners\Apache.Arrow.Adbc.Telemetry.Traces.Listeners.csproj",
 "{4D5ADA1A-2DEE-5860-2351-221090CF4442}"
+EndProject
 Global
        GlobalSection(SolutionConfigurationPlatforms) = preSolution
                Debug|Any CPU = Debug|Any CPU
@@ -136,6 +144,14 @@ Global
                {1558BC4B-6E76-434B-8877-6C49B1460544}.Debug|Any CPU.Build.0 = 
Debug|Any CPU
                {1558BC4B-6E76-434B-8877-6C49B1460544}.Release|Any 
CPU.ActiveCfg = Release|Any CPU
                {1558BC4B-6E76-434B-8877-6C49B1460544}.Release|Any CPU.Build.0 
= Release|Any CPU
+               {9CE9106B-ACBB-54C1-DE57-370E5CF09363}.Debug|Any CPU.ActiveCfg 
= Debug|Any CPU
+               {9CE9106B-ACBB-54C1-DE57-370E5CF09363}.Debug|Any CPU.Build.0 = 
Debug|Any CPU
+               {9CE9106B-ACBB-54C1-DE57-370E5CF09363}.Release|Any 
CPU.ActiveCfg = Release|Any CPU
+               {9CE9106B-ACBB-54C1-DE57-370E5CF09363}.Release|Any CPU.Build.0 
= Release|Any CPU
+               {4D5ADA1A-2DEE-5860-2351-221090CF4442}.Debug|Any CPU.ActiveCfg 
= Debug|Any CPU
+               {4D5ADA1A-2DEE-5860-2351-221090CF4442}.Debug|Any CPU.Build.0 = 
Debug|Any CPU
+               {4D5ADA1A-2DEE-5860-2351-221090CF4442}.Release|Any 
CPU.ActiveCfg = Release|Any CPU
+               {4D5ADA1A-2DEE-5860-2351-221090CF4442}.Release|Any CPU.Build.0 
= Release|Any CPU
        EndGlobalSection
        GlobalSection(SolutionProperties) = preSolution
                HideSolutionNode = FALSE
@@ -164,6 +180,10 @@ Global
                {B74532A7-8A78-4AD9-9B2E-584765491E48} = 
{9FE39661-2A39-4E9F-A5F2-11FB0D54CB42}
                {43910445-FEC4-4AEC-A698-6A48327600C3} = 
{B74532A7-8A78-4AD9-9B2E-584765491E48}
                {1558BC4B-6E76-434B-8877-6C49B1460544} = 
{43910445-FEC4-4AEC-A698-6A48327600C3}
+               {53C45FD3-7277-49FA-AEEB-DF8F2386ECAA} = 
{B74532A7-8A78-4AD9-9B2E-584765491E48}
+               {1C530561-1008-4F39-B437-15B2FD59EAC9} = 
{22EF23A3-1566-446F-B696-9323F3B6F56C}
+               {9CE9106B-ACBB-54C1-DE57-370E5CF09363} = 
{53C45FD3-7277-49FA-AEEB-DF8F2386ECAA}
+               {4D5ADA1A-2DEE-5860-2351-221090CF4442} = 
{1C530561-1008-4F39-B437-15B2FD59EAC9}
        EndGlobalSection
        GlobalSection(ExtensibilityGlobals) = postSolution
                SolutionGuid = {4795CF16-0FDB-4BE0-9768-5CF31564DC03}
diff --git a/csharp/src/Drivers/Apache/Apache.Arrow.Adbc.Drivers.Apache.csproj 
b/csharp/src/Drivers/Apache/Apache.Arrow.Adbc.Drivers.Apache.csproj
index f4c11907d..8e68c63f3 100644
--- a/csharp/src/Drivers/Apache/Apache.Arrow.Adbc.Drivers.Apache.csproj
+++ b/csharp/src/Drivers/Apache/Apache.Arrow.Adbc.Drivers.Apache.csproj
@@ -14,6 +14,7 @@
 
   <ItemGroup>
     <ProjectReference 
Include="..\..\Apache.Arrow.Adbc\Apache.Arrow.Adbc.csproj" />
+    <ProjectReference 
Include="..\..\Telemetry\Traces\Listeners\Apache.Arrow.Adbc.Telemetry.Traces.Listeners.csproj"
 />
   </ItemGroup>
 
 </Project>
diff --git a/csharp/src/Drivers/Apache/Hive2/HiveServer2Connection.cs 
b/csharp/src/Drivers/Apache/Hive2/HiveServer2Connection.cs
index 766bec961..193cec722 100644
--- a/csharp/src/Drivers/Apache/Hive2/HiveServer2Connection.cs
+++ b/csharp/src/Drivers/Apache/Hive2/HiveServer2Connection.cs
@@ -27,6 +27,8 @@ using System.Threading;
 using System.Threading.Tasks;
 using Apache.Arrow.Adbc.Drivers.Apache.Thrift;
 using Apache.Arrow.Adbc.Extensions;
+using Apache.Arrow.Adbc.Telemetry.Traces.Listeners;
+using Apache.Arrow.Adbc.Telemetry.Traces.Listeners.FileListener;
 using Apache.Arrow.Adbc.Tracing;
 using Apache.Arrow.Ipc;
 using Apache.Arrow.Types;
@@ -49,6 +51,9 @@ namespace Apache.Arrow.Adbc.Drivers.Apache.Hive2
         private readonly Lazy<string> _vendorVersion;
         private readonly Lazy<string> _vendorName;
         private bool _isDisposed;
+        // Note: this needs to be set before the constructor runs
+        private readonly string _traceInstanceId = 
Guid.NewGuid().ToString("N");
+        private readonly FileActivityListener? _fileActivityListener;
 
         readonly AdbcInfoCode[] infoSupportedCodes = [
             AdbcInfoCode.DriverName,
@@ -278,6 +283,8 @@ namespace Apache.Arrow.Adbc.Drivers.Apache.Hive2
         {
             Properties = properties;
 
+            TryInitTracerProvider(out _fileActivityListener);
+
             // Note: "LazyThreadSafetyMode.PublicationOnly" is thread-safe 
initialization where
             // the first successful thread sets the value. If an exception is 
thrown, initialization
             // will retry until it successfully returns a value without an 
exception.
@@ -294,6 +301,31 @@ namespace Apache.Arrow.Adbc.Drivers.Apache.Hive2
             }
         }
 
+        private bool TryInitTracerProvider(out FileActivityListener? 
fileActivityListener)
+        {
+            Properties.TryGetValue(ListenersOptions.Exporter, out string? 
exporterOption);
+            // This listener will only listen for activity from this specific 
connection instance.
+            bool shouldListenTo(ActivitySource source) => source.Tags?.Any(t 
=> ReferenceEquals(t.Key, _traceInstanceId)) == true;
+            return FileActivityListener.TryActivateFileListener(AssemblyName, 
exporterOption, out fileActivityListener, shouldListenTo: shouldListenTo);
+        }
+
+        public override IEnumerable<KeyValuePair<string, object?>>? 
GetActivitySourceTags(IReadOnlyDictionary<string, string> properties)
+        {
+            IEnumerable<KeyValuePair<string, object?>>? tags = 
base.GetActivitySourceTags(properties);
+            tags ??= [];
+            tags = tags.Concat([new(_traceInstanceId, null)]);
+            return tags;
+        }
+
+        /// <summary>
+        /// Conditional used to determines if it is safe to trace
+        /// </summary>
+        /// <remarks>
+        /// It is safe to write to some output types (ie, files) but not 
others (ie, a shared resource).
+        /// </remarks>
+        /// <returns></returns>
+        internal bool IsSafeToTrace => _fileActivityListener != null;
+
         internal TCLIService.IAsync Client
         {
             get { return _client ?? throw new 
InvalidOperationException("connection not open"); }
@@ -732,6 +764,7 @@ namespace Apache.Arrow.Adbc.Drivers.Apache.Hive2
             if (!_isDisposed && disposing)
             {
                 DisposeClient();
+                _fileActivityListener?.Dispose();
                 _isDisposed = true;
             }
             base.Dispose(disposing);
@@ -1540,7 +1573,7 @@ namespace Apache.Arrow.Adbc.Drivers.Apache.Hive2
                             nullCount++;
                             break;
                     }
-                    ActivityExtensions.AddTag(activity, tagKey, tagValue);
+                    Tracing.ActivityExtensions.AddTag(activity, tagKey, 
tagValue);
                 }
 
                 StructType entryType = new StructType(
diff --git a/csharp/src/Drivers/Apache/Hive2/README.md 
b/csharp/src/Drivers/Apache/Hive2/README.md
index cde81ecd6..9404cdf88 100644
--- a/csharp/src/Drivers/Apache/Hive2/README.md
+++ b/csharp/src/Drivers/Apache/Hive2/README.md
@@ -149,3 +149,34 @@ The Collector can be configure to receive trace messages 
from the driver and exp
 Ensure to set the [environment 
variable](https://opentelemetry.io/docs/specs/otel/protocol/exporter/) 
`OTEL_EXPORTER_OTLP_INSECURE` to `true`, in this scenario.
 
 Ensure to follow [Collector configuration best 
practices](https://opentelemetry.io/docs/security/config-best-practices/).
+
+## Tracing
+
+### Tracing Exporters
+
+To enable tracing messages to be observed, a tracing exporter needs to be 
activated.
+Use either the environment variable `OTEL_TRACES_EXPORTER` or the parameter 
`adbc.traces.exporter` to select one of the
+supported exporters. The parameter has precedence over the environment 
variable. The parameter must be set before
+the connection is initialized.
+
+The following exporters are supported:
+
+| Exporter | Description |
+| --- | --- |
+| `adbcfile` | Exports traces to rotating files in a folder. |
+
+#### File Exporter (adbcfile)
+
+Rotating trace files are written to a folder. The file names are created with 
the following pattern:
+`apache.arrow.adbc.drivers.bigquery-<YYYY-MM-DD-HH-mm-ss-fff>-<process-id>.log`.
+
+The folder used depends on the platform.
+
+| Platform | Folder |
+| --- | --- |
+| Windows | `%LOCALAPPDATA%/Apache.Arrow.Adbc/Traces` |
+| macOS   | `$HOME/Library/Application Support/Apache.Arrow.Adbc/Traces` |
+| Linux   | `$HOME/.local/share/Apache.Arrow.Adbc/Traces` |
+
+By default, up to 999 files of maximum size 1024 KB are written to
+the trace folder.
diff --git a/csharp/src/Drivers/Apache/Impala/README.md 
b/csharp/src/Drivers/Apache/Impala/README.md
index 6313c83b3..f2567f56f 100644
--- a/csharp/src/Drivers/Apache/Impala/README.md
+++ b/csharp/src/Drivers/Apache/Impala/README.md
@@ -139,3 +139,34 @@ The Collector can be configure to receive trace messages 
from the driver and exp
 Ensure to set the [environment 
variable](https://opentelemetry.io/docs/specs/otel/protocol/exporter/) 
`OTEL_EXPORTER_OTLP_INSECURE` to `true`, in this scenario.
 
 Ensure to follow [Collector configuration best 
practices](https://opentelemetry.io/docs/security/config-best-practices/).
+
+## Tracing
+
+### Tracing Exporters
+
+To enable tracing messages to be observed, a tracing exporter needs to be 
activated.
+Use either the environment variable `OTEL_TRACES_EXPORTER` or the parameter 
`adbc.traces.exporter` to select one of the
+supported exporters. The parameter has precedence over the environment 
variable. The parameter must be set before
+the connection is initialized.
+
+The following exporters are supported:
+
+| Exporter | Description |
+| --- | --- |
+| `adbcfile` | Exports traces to rotating files in a folder. |
+
+#### File Exporter (adbcfile)
+
+Rotating trace files are written to a folder. The file names are created with 
the following pattern:
+`apache.arrow.adbc.drivers.bigquery-<YYYY-MM-DD-HH-mm-ss-fff>-<process-id>.log`.
+
+The folder used depends on the platform.
+
+| Platform | Folder |
+| --- | --- |
+| Windows | `%LOCALAPPDATA%/Apache.Arrow.Adbc/Traces` |
+| macOS   | `$HOME/Library/Application Support/Apache.Arrow.Adbc/Traces` |
+| Linux   | `$HOME/.local/share/Apache.Arrow.Adbc/Traces` |
+
+By default, up to 999 files of maximum size 1024 KB are written to
+the trace folder.
diff --git a/csharp/src/Drivers/Apache/Spark/README.md 
b/csharp/src/Drivers/Apache/Spark/README.md
index 6c44c8523..bb3872024 100644
--- a/csharp/src/Drivers/Apache/Spark/README.md
+++ b/csharp/src/Drivers/Apache/Spark/README.md
@@ -149,3 +149,34 @@ The Collector can be configure to receive trace messages 
from the driver and exp
 Ensure to set the [environment 
variable](https://opentelemetry.io/docs/specs/otel/protocol/exporter/) 
`OTEL_EXPORTER_OTLP_INSECURE` to `true`, in this scenario.
 
 Ensure to follow [Collector configuration best 
practices](https://opentelemetry.io/docs/security/config-best-practices/).
+
+## Tracing
+
+### Tracing Exporters
+
+To enable tracing messages to be observed, a tracing exporter needs to be 
activated.
+Use either the environment variable `OTEL_TRACES_EXPORTER` or the parameter 
`adbc.traces.exporter` to select one of the
+supported exporters. The parameter has precedence over the environment 
variable. The parameter must be set before
+the connection is initialized.
+
+The following exporters are supported:
+
+| Exporter | Description |
+| --- | --- |
+| `adbcfile` | Exports traces to rotating files in a folder. |
+
+#### File Exporter (adbcfile)
+
+Rotating trace files are written to a folder. The file names are created with 
the following pattern:
+`apache.arrow.adbc.drivers.bigquery-<YYYY-MM-DD-HH-mm-ss-fff>-<process-id>.log`.
+
+The folder used depends on the platform.
+
+| Platform | Folder |
+| --- | --- |
+| Windows | `%LOCALAPPDATA%/Apache.Arrow.Adbc/Traces` |
+| macOS   | `$HOME/Library/Application Support/Apache.Arrow.Adbc/Traces` |
+| Linux   | `$HOME/.local/share/Apache.Arrow.Adbc/Traces` |
+
+By default, up to 999 files of maximum size 1024 KB are written to
+the trace folder.
diff --git 
a/csharp/src/Drivers/BigQuery/Apache.Arrow.Adbc.Drivers.BigQuery.csproj 
b/csharp/src/Drivers/BigQuery/Apache.Arrow.Adbc.Drivers.BigQuery.csproj
index b20d938f3..16316d301 100644
--- a/csharp/src/Drivers/BigQuery/Apache.Arrow.Adbc.Drivers.BigQuery.csproj
+++ b/csharp/src/Drivers/BigQuery/Apache.Arrow.Adbc.Drivers.BigQuery.csproj
@@ -13,6 +13,7 @@
   </ItemGroup>
   <ItemGroup>
     <ProjectReference 
Include="..\..\Apache.Arrow.Adbc\Apache.Arrow.Adbc.csproj" />
+    <ProjectReference 
Include="..\..\Telemetry\Traces\Listeners\Apache.Arrow.Adbc.Telemetry.Traces.Listeners.csproj"
 />
   </ItemGroup>
   <ItemGroup>
     <Content Include="readme.md">
diff --git a/csharp/src/Drivers/BigQuery/BigQueryConnection.cs 
b/csharp/src/Drivers/BigQuery/BigQueryConnection.cs
index 9855e76be..ffb562d78 100644
--- a/csharp/src/Drivers/BigQuery/BigQueryConnection.cs
+++ b/csharp/src/Drivers/BigQuery/BigQueryConnection.cs
@@ -25,6 +25,8 @@ using System.Text.Json;
 using System.Text.RegularExpressions;
 using System.Threading.Tasks;
 using Apache.Arrow.Adbc.Extensions;
+using Apache.Arrow.Adbc.Telemetry.Traces.Listeners;
+using Apache.Arrow.Adbc.Telemetry.Traces.Listeners.FileListener;
 using Apache.Arrow.Adbc.Tracing;
 using Apache.Arrow.Ipc;
 using Apache.Arrow.Types;
@@ -45,6 +47,9 @@ namespace Apache.Arrow.Adbc.Drivers.BigQuery
         bool includePublicProjectIds = false;
         const string infoDriverName = "ADBC BigQuery Driver";
         const string infoVendorName = "BigQuery";
+        // Note: this needs to be set before the constructor runs
+        private readonly string _traceInstanceId = 
Guid.NewGuid().ToString("N");
+        private readonly FileActivityListener? _fileActivityListener;
 
         private readonly string infoDriverArrowVersion = 
BigQueryUtils.GetAssemblyVersion(typeof(IArrowArray));
 
@@ -66,6 +71,8 @@ namespace Apache.Arrow.Adbc.Drivers.BigQuery
                 this.properties = properties.ToDictionary(k => k.Key, v => 
v.Value);
             }
 
+            TryInitTracerProvider(out _fileActivityListener);
+
             // add the default value for now and set to true until C# has a 
BigDecimal
             this.properties[BigQueryParameters.LargeDecimalsAsString] = 
BigQueryConstants.TreatLargeDecimalAsString;
             this.httpClient = new HttpClient();
@@ -85,6 +92,31 @@ namespace Apache.Arrow.Adbc.Drivers.BigQuery
             }
         }
 
+        private bool TryInitTracerProvider(out FileActivityListener? 
fileActivityListener)
+        {
+            properties.TryGetValue(ListenersOptions.Exporter, out string? 
exporterOption);
+            // This listener will only listen for activity from this specific 
connection instance.
+            bool shouldListenTo(ActivitySource source) => source.Tags?.Any(t 
=> ReferenceEquals(t.Key, _traceInstanceId)) == true;
+            return FileActivityListener.TryActivateFileListener(AssemblyName, 
exporterOption, out fileActivityListener, shouldListenTo: shouldListenTo);
+        }
+
+        public override IEnumerable<KeyValuePair<string, object?>>? 
GetActivitySourceTags(IReadOnlyDictionary<string, string> properties)
+        {
+            IEnumerable<KeyValuePair<string, object?>>? tags = 
base.GetActivitySourceTags(properties);
+            tags ??= [];
+            tags = tags.Concat([new(_traceInstanceId, null)]);
+            return tags;
+        }
+
+        /// <summary>
+        /// Conditional used to determines if it is safe to trace
+        /// </summary>
+        /// <remarks>
+        /// It is safe to write to some output types (ie, files) but not 
others (ie, a shared resource).
+        /// </remarks>
+        /// <returns></returns>
+        internal bool IsSafeToTrace => _fileActivityListener != null;
+
         /// <summary>
         /// The function to call when updating the token.
         /// </summary>
@@ -470,7 +502,7 @@ namespace Apache.Arrow.Adbc.Drivers.BigQuery
 
             return this.TraceActivity(activity =>
             {
-                activity?.AddConditionalTag(SemanticConventions.Db.Query.Text, 
sql, BigQueryUtils.IsSafeToTrace());
+                activity?.AddConditionalTag(SemanticConventions.Db.Query.Text, 
sql, IsSafeToTrace);
 
                 Func<Task<BigQueryResults?>> func = () => 
Client.ExecuteQueryAsync(sql, parameters ?? 
Enumerable.Empty<BigQueryParameter>(), queryOptions, resultsOptions);
                 BigQueryResults? result = 
ExecuteWithRetriesAsync<BigQueryResults?>(func, 
activity).GetAwaiter().GetResult();
@@ -1273,6 +1305,7 @@ namespace Apache.Arrow.Adbc.Drivers.BigQuery
             Client?.Dispose();
             Client = null;
             this.httpClient?.Dispose();
+            this._fileActivityListener?.Dispose();
         }
 
         private static Regex sanitizedInputRegex = new 
Regex("^[a-zA-Z0-9_-]+");
diff --git a/csharp/src/Drivers/BigQuery/BigQueryStatement.cs 
b/csharp/src/Drivers/BigQuery/BigQueryStatement.cs
index e8b89f18a..eabdcc4da 100644
--- a/csharp/src/Drivers/BigQuery/BigQueryStatement.cs
+++ b/csharp/src/Drivers/BigQuery/BigQueryStatement.cs
@@ -91,7 +91,7 @@ namespace Apache.Arrow.Adbc.Drivers.BigQuery
             {
                 QueryOptions queryOptions = ValidateOptions(activity);
 
-                activity?.AddConditionalTag(SemanticConventions.Db.Query.Text, 
SqlQuery, BigQueryUtils.IsSafeToTrace());
+                activity?.AddConditionalTag(SemanticConventions.Db.Query.Text, 
SqlQuery, this.bigQueryConnection.IsSafeToTrace);
 
                 BigQueryJob job = await Client.CreateQueryJobAsync(SqlQuery, 
null, queryOptions);
 
@@ -216,7 +216,7 @@ namespace Apache.Arrow.Adbc.Drivers.BigQuery
             ReadSession rrs = await 
bigQueryReadClient.CreateReadSessionAsync("projects/" + projectId, rs, 
maxStreamCount);
 
             var readers = rrs.Streams
-                             .Select(s => ReadChunk(bigQueryReadClient, 
s.Name, activity))
+                             .Select(s => ReadChunk(bigQueryReadClient, 
s.Name, activity, this.bigQueryConnection.IsSafeToTrace))
                              .Where(chunk => chunk != null)
                              .Cast<IArrowReader>();
 
@@ -242,7 +242,7 @@ namespace Apache.Arrow.Adbc.Drivers.BigQuery
                     
activity?.AddBigQueryParameterTag(BigQueryParameters.GetQueryResultsOptionsTimeout,
 seconds);
                 }
 
-                activity?.AddConditionalTag(SemanticConventions.Db.Query.Text, 
SqlQuery, BigQueryUtils.IsSafeToTrace());
+                activity?.AddConditionalTag(SemanticConventions.Db.Query.Text, 
SqlQuery, this.bigQueryConnection.IsSafeToTrace);
 
                 // Cannot set destination table in jobs with DDL statements, 
otherwise an error will be prompted
                 Func<Task<BigQueryResults?>> func = () => 
Client.ExecuteQueryAsync(SqlQuery, null, null, getQueryResultsOptions);
@@ -340,11 +340,11 @@ namespace Apache.Arrow.Adbc.Drivers.BigQuery
             return type;
         }
 
-        private static IArrowReader? ReadChunk(BigQueryReadClient client, 
string streamName, Activity? activity)
+        private static IArrowReader? ReadChunk(BigQueryReadClient client, 
string streamName, Activity? activity, bool isSafeToTrace)
         {
             // Ideally we wouldn't need to indirect through a stream, but the 
necessary APIs in Arrow
             // are internal. (TODO: consider changing Arrow).
-            activity?.AddConditionalBigQueryTag("read_stream", streamName, 
BigQueryUtils.IsSafeToTrace());
+            activity?.AddConditionalBigQueryTag("read_stream", streamName, 
isSafeToTrace);
             BigQueryReadClient.ReadRowsStream readRowsStream = 
client.ReadRows(new ReadRowsRequest { ReadStream = streamName });
             IAsyncEnumerator<ReadRowsResponse> enumerator = 
readRowsStream.GetResponseStream().GetAsyncEnumerator();
 
diff --git a/csharp/src/Drivers/BigQuery/BigQueryUtils.cs 
b/csharp/src/Drivers/BigQuery/BigQueryUtils.cs
index b8fca804f..956486d2a 100644
--- a/csharp/src/Drivers/BigQuery/BigQueryUtils.cs
+++ b/csharp/src/Drivers/BigQuery/BigQueryUtils.cs
@@ -42,18 +42,5 @@ namespace Apache.Arrow.Adbc.Drivers.BigQuery
         internal static string GetAssemblyName(Type type) => 
type.Assembly.GetName().Name!;
 
         internal static string GetAssemblyVersion(Type type) => 
FileVersionInfo.GetVersionInfo(type.Assembly.Location).ProductVersion ?? 
string.Empty;
-
-        /// <summary>
-        /// Conditional used to determines if it is safe to trace
-        /// </summary>
-        /// <remarks>
-        /// It is safe to write to some output types (ie, files) but not 
others (ie, a shared resource).
-        /// </remarks>
-        /// <returns></returns>
-        internal static bool IsSafeToTrace()
-        {
-            // TODO: Add logic to determine if a file writer is listening
-            return false;
-        }
     }
 }
diff --git a/csharp/src/Drivers/BigQuery/readme.md 
b/csharp/src/Drivers/BigQuery/readme.md
index 96605a9c2..1d98d055e 100644
--- a/csharp/src/Drivers/BigQuery/readme.md
+++ b/csharp/src/Drivers/BigQuery/readme.md
@@ -204,3 +204,34 @@ Some environments may also require:
 - [Running jobs programmatically | BigQuery | Google 
Cloud](https://cloud.google.com/bigquery/docs/running-jobs)
 - [Create datasets | BigQuery | Google 
Cloud](https://cloud.google.com/bigquery/docs/datasets#required_permissions)
 - [Use the BigQuery Storage Read API to read table data |  Google 
Cloud](https://cloud.google.com/bigquery/docs/reference/storage/#permissions)
+
+## Tracing
+
+### Tracing Exporters
+
+To enable tracing messages to be observed, a tracing exporter needs to be 
activated.
+Use either the environment variable `OTEL_TRACES_EXPORTER` or the parameter 
`adbc.traces.exporter` to select one of the
+supported exporters. The parameter has precedence over the environment 
variable. The parameter must be set before
+the connection is initialized.
+
+The following exporters are supported:
+
+| Exporter | Description |
+| --- | --- |
+| `adbcfile` | Exports traces to rotating files in a folder. |
+
+#### File Exporter (adbcfile)
+
+Rotating trace files are written to a folder. The file names are created with 
the following pattern:
+`apache.arrow.adbc.drivers.bigquery-<YYYY-MM-DD-HH-mm-ss-fff>-<process-id>.log`.
+
+The folder used depends on the platform.
+
+| Platform | Folder |
+| --- | --- |
+| Windows | `%LOCALAPPDATA%/Apache.Arrow.Adbc/Traces` |
+| macOS   | `$HOME/Library/Application Support/Apache.Arrow.Adbc/Traces` |
+| Linux   | `$HOME/.local/share/Apache.Arrow.Adbc/Traces` |
+
+By default, up to 999 files of maximum size 1024 KB are written to
+the trace folder.
diff --git a/csharp/src/Drivers/Databricks/readme.md 
b/csharp/src/Drivers/Databricks/readme.md
index 49bf2d9d5..3250ef8e4 100644
--- a/csharp/src/Drivers/Databricks/readme.md
+++ b/csharp/src/Drivers/Databricks/readme.md
@@ -178,3 +178,34 @@ The following table depicts how the Databricks ADBC driver 
converts a Databricks
 | UNION                | String     | string |
 | USER_DEFINED         | String     | string |
 | VARCHAR              | String     | string |
+
+## Tracing
+
+### Tracing Exporters
+
+To enable tracing messages to be observed, a tracing exporter needs to be 
activated.
+Use either the environment variable `OTEL_TRACES_EXPORTER` or the parameter 
`adbc.traces.exporter` to select one of the
+supported exporters. The parameter has precedence over the environment 
variable. The parameter must be set before
+the connection is initialized.
+
+The following exporters are supported:
+
+| Exporter | Description |
+| --- | --- |
+| `adbcfile` | Exports traces to rotating files in a folder. |
+
+#### File Exporter (adbcfile)
+
+Rotating trace files are written to a folder. The file names are created with 
the following pattern:
+`apache.arrow.adbc.drivers.bigquery-<YYYY-MM-DD-HH-mm-ss-fff>-<process-id>.log`.
+
+The folder used depends on the platform.
+
+| Platform | Folder |
+| --- | --- |
+| Windows | `%LOCALAPPDATA%/Apache.Arrow.Adbc/Traces` |
+| macOS   | `$HOME/Library/Application Support/Apache.Arrow.Adbc/Traces` |
+| Linux   | `$HOME/.local/share/Apache.Arrow.Adbc/Traces` |
+
+By default, up to 999 files of maximum size 1024 KB are written to
+the trace folder.
diff --git 
a/csharp/src/Telemetry/Traces/Exporters/Apache.Arrow.Adbc.Telemetry.Traces.Exporters.csproj
 
b/csharp/src/Telemetry/Traces/Exporters/Apache.Arrow.Adbc.Telemetry.Traces.Exporters.csproj
index 4dec891d1..51deb03a6 100644
--- 
a/csharp/src/Telemetry/Traces/Exporters/Apache.Arrow.Adbc.Telemetry.Traces.Exporters.csproj
+++ 
b/csharp/src/Telemetry/Traces/Exporters/Apache.Arrow.Adbc.Telemetry.Traces.Exporters.csproj
@@ -21,6 +21,7 @@
 
   <ItemGroup>
     <ProjectReference 
Include="..\..\..\Apache.Arrow.Adbc\Apache.Arrow.Adbc.csproj" />
+    <ProjectReference 
Include="..\Listeners\Apache.Arrow.Adbc.Telemetry.Traces.Listeners.csproj" />
   </ItemGroup>
 
 </Project>
diff --git a/csharp/src/Telemetry/Traces/Exporters/ExportersBuilder.cs 
b/csharp/src/Telemetry/Traces/Exporters/ExportersBuilder.cs
index 1c232448c..3544cf0e8 100644
--- a/csharp/src/Telemetry/Traces/Exporters/ExportersBuilder.cs
+++ b/csharp/src/Telemetry/Traces/Exporters/ExportersBuilder.cs
@@ -94,32 +94,48 @@ namespace Apache.Arrow.Adbc.Telemetry.Traces.Exporters
             out string? exporterName,
             string environmentName = ExportersOptions.Environment.Exporter)
         {
-            TracerProvider? tracerProvider = null;
-            exporterName = null;
-
-            if (string.IsNullOrWhiteSpace(exporterOption))
+            if (TryActivate(exporterOption, out exporterName, out 
TracerProvider? tracerProvider, environmentName))
             {
-                // Fall back to check the environment variable
-                exporterOption = 
Environment.GetEnvironmentVariable(environmentName);
+                return tracerProvider;
             }
-            if (string.IsNullOrWhiteSpace(exporterOption))
+            if (!string.IsNullOrEmpty(exporterName) && exporterName != 
ExportersOptions.Exporters.None)
             {
-                // Neither option or environment variable is set - no tracer 
provider will be activated.
-                return null;
+                // Requested option has not been added via the builder
+                throw AdbcException.NotImplemented($"Exporter option 
'{exporterName}' is not implemented.");
             }
+            return null;
+        }
+
+        /// <summary>
+        /// Tries to activate an exporter based on the dictionary of <see 
cref="TracerProvider"/> factories.
+        /// </summary>
+        /// <param name="exporterOption">The value (name) of the exporter 
option, typically passed as option <see 
cref="ExportersOptions.Exporter"/>.</param>
+        /// <param name="exporterName">The actual exporter name when 
successfully activated.</param>
+        /// <param name="tracerProvider">A non-null <see 
cref="TracerProvider"/> when successfully activated. Returns null if not 
successful. Note: this object must be explicitly disposed when no longer 
necessary.</param>
+        /// <param name="environmentName">The (optional) name of the 
environment variable to test for the exporter name. Default: <see 
cref="ExportersOptions.Environment.Exporter"/></param>
+        /// <returns>Returns true if the exporter was successfully activated. 
Returns false, otherwise.</returns>
+        public bool TryActivate(
+            string? exporterOption,
+            out string? exporterName,
+            out TracerProvider? tracerProvider,
+            string environmentName = ExportersOptions.Environment.Exporter)
+        {
+            tracerProvider = null;
+            exporterName = null;
 
-            if (!_tracerProviderFactories.TryGetValue(exporterOption!, out 
Func<string, string?, TracerProvider?>? factory))
+            if (!TryGetExporterName(exporterOption, environmentName, out 
exporterName)
+                || !_tracerProviderFactories.TryGetValue(exporterName!, out 
Func<string, string?, TracerProvider?>? factory))
             {
-                // Requested option has not been added via the builder
-                throw AdbcException.NotImplemented($"Exporter option 
'{exporterOption}' is not implemented.");
+                return false;
             }
 
             tracerProvider = factory.Invoke(_sourceName, _sourceVersion);
-            if (tracerProvider != null)
+            if (tracerProvider == null)
             {
-                exporterName = exporterOption;
+                return false;
             }
-            return tracerProvider;
+
+            return true;
         }
 
         public static TracerProvider NewAdbcFileTracerProvider(string 
sourceName, string? sourceVersion) =>
@@ -155,6 +171,23 @@ namespace Apache.Arrow.Adbc.Telemetry.Traces.Exporters
         public static TracerProvider? NewNoopTracerProvider(string sourceName, 
string? sourceVersion) =>
             null;
 
+        private static bool TryGetExporterName(string? exporterOption, string 
environmentName, out string? exporterName)
+        {
+            if (string.IsNullOrWhiteSpace(exporterOption))
+            {
+                // Fall back to check the environment variable
+                exporterOption = 
Environment.GetEnvironmentVariable(environmentName);
+            }
+            if (string.IsNullOrWhiteSpace(exporterOption))
+            {
+                // Neither option or environment variable is set - no tracer 
provider will be activated.
+                exporterName = null;
+                return false;
+            }
+            exporterName = exporterOption!;
+            return true;
+        }
+
         public class Builder
         {
             private readonly string _sourceName;
diff --git a/csharp/src/Telemetry/Traces/Exporters/ExportersOptions.cs 
b/csharp/src/Telemetry/Traces/Exporters/ExportersOptions.cs
index 8cd631ac2..40c2199cd 100644
--- a/csharp/src/Telemetry/Traces/Exporters/ExportersOptions.cs
+++ b/csharp/src/Telemetry/Traces/Exporters/ExportersOptions.cs
@@ -15,23 +15,25 @@
  * limitations under the License.
  */
 
+using Apache.Arrow.Adbc.Telemetry.Traces.Listeners;
+
 namespace Apache.Arrow.Adbc.Telemetry.Traces.Exporters
 {
     public class ExportersOptions
     {
-        public const string Exporter = "adbc.traces.exporter";
+        public const string Exporter = ListenersOptions.Exporter;
 
         public static class Environment
         {
-            public const string Exporter = "OTEL_TRACES_EXPORTER";
+            public const string Exporter = 
ListenersOptions.Environment.Exporter;
         }
 
         public static class Exporters
         {
-            public const string None = "none";
+            public const string None = ListenersOptions.Exporters.None;
             public const string Otlp = "otlp";
             public const string Console = "console";
-            public const string AdbcFile = "adbcfile";
+            public const string AdbcFile = ListenersOptions.Exporters.AdbcFile;
         }
     }
 }
diff --git a/csharp/src/Telemetry/Traces/Exporters/FileExporter/FileExporter.cs 
b/csharp/src/Telemetry/Traces/Exporters/FileExporter/FileExporter.cs
index a1251a8d7..08d4336ab 100644
--- a/csharp/src/Telemetry/Traces/Exporters/FileExporter/FileExporter.cs
+++ b/csharp/src/Telemetry/Traces/Exporters/FileExporter/FileExporter.cs
@@ -24,6 +24,7 @@ using System.Text.Json;
 using System.Threading;
 using System.Threading.Channels;
 using System.Threading.Tasks;
+using Apache.Arrow.Adbc.Telemetry.Traces.Listeners.FileListener;
 using OpenTelemetry;
 
 namespace Apache.Arrow.Adbc.Telemetry.Traces.Exporters.FileExporter
diff --git 
a/csharp/src/Telemetry/Traces/Exporters/FileExporter/FileExporterExtensions.cs 
b/csharp/src/Telemetry/Traces/Exporters/FileExporter/FileExporterExtensions.cs
index b35ca43f3..2f5a495eb 100644
--- 
a/csharp/src/Telemetry/Traces/Exporters/FileExporter/FileExporterExtensions.cs
+++ 
b/csharp/src/Telemetry/Traces/Exporters/FileExporter/FileExporterExtensions.cs
@@ -129,7 +129,7 @@ namespace 
Apache.Arrow.Adbc.Telemetry.Traces.Exporters.FileExporter
             if (FileExporter.TryCreate(fileBaseName, traceLocation, 
maxTraceFileSizeKb.Value, maxTraceFiles.Value, out FileExporter? fileExporter))
             {
                 // Only add a new processor if there isn't already one 
listening for the source/location.
-                return builder.AddProcessor(_ => new 
BatchActivityExportProcessor(fileExporter!));
+                return builder.AddProcessor(_ => new 
SimpleActivityExportProcessor(fileExporter!));
             }
             return builder;
         }
diff --git a/csharp/src/Telemetry/Traces/Exporters/readme.md 
b/csharp/src/Telemetry/Traces/Exporters/readme.md
index 8b743c7e7..6bd2e9444 100644
--- a/csharp/src/Telemetry/Traces/Exporters/readme.md
+++ b/csharp/src/Telemetry/Traces/Exporters/readme.md
@@ -33,7 +33,7 @@ The default folder used is:
 | macOS   | `$HOME/Library/Application Support/Apache.Arrow.Adbc/Traces` |
 | Linux   | `$HOME/.local/share/Apache.Arrow.Adbc/Traces` |
 
-By default, up to 100 files of maximum size 1024 KB are written to
+By default, up to 999 files of maximum size 1024 KB are written to
 the trace folder.
 
 ## ExportersBuilder
@@ -49,6 +49,6 @@ The following exporters are supported:
 | Exporter | Description |
 | --- | --- |
 | `otlp` | Exports traces to an OpenTelemetry Collector or directly to an Open 
Telemetry Line Protocol (OTLP) endpoint. |
-| `file` | Exports traces to rotating files in a folder. |
+| `adbcfile` | Exports traces to rotating files in a folder. |
 | `console` | Exports traces to the console output. |
 | `none` | Disables trace exporting. |
diff --git 
a/csharp/src/Telemetry/Traces/Listeners/Apache.Arrow.Adbc.Telemetry.Traces.Listeners.csproj
 
b/csharp/src/Telemetry/Traces/Listeners/Apache.Arrow.Adbc.Telemetry.Traces.Listeners.csproj
new file mode 100644
index 000000000..a688ba3fa
--- /dev/null
+++ 
b/csharp/src/Telemetry/Traces/Listeners/Apache.Arrow.Adbc.Telemetry.Traces.Listeners.csproj
@@ -0,0 +1,18 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFrameworks>netstandard2.0;net8.0</TargetFrameworks>
+    <Nullable>enable</Nullable>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="System.Diagnostics.DiagnosticSource" 
Version="9.0.6" />
+    <PackageReference Include="System.Text.Json" Version="8.0.5" />
+    <PackageReference Include="System.Threading.Channels" Version="9.0.8" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Folder Include="Properties\" />
+  </ItemGroup>
+
+</Project>
diff --git 
a/csharp/src/Telemetry/Traces/Listeners/FileListener/ActivityProcessor.cs 
b/csharp/src/Telemetry/Traces/Listeners/FileListener/ActivityProcessor.cs
new file mode 100644
index 000000000..20fff5840
--- /dev/null
+++ b/csharp/src/Telemetry/Traces/Listeners/FileListener/ActivityProcessor.cs
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+using System.Text.Json;
+using System.Threading;
+using System.Threading.Channels;
+using System.Threading.Tasks;
+
+namespace Apache.Arrow.Adbc.Telemetry.Traces.Listeners.FileListener
+{
+    internal sealed class ActivityProcessor : IDisposable
+    {
+        private static readonly byte[] s_newLine = 
Encoding.UTF8.GetBytes(Environment.NewLine);
+        private Task? _processingTask;
+        private readonly Channel<Activity> _channel;
+        private readonly Func<Stream, CancellationToken, Task> 
_streamWriterFunc;
+        private CancellationTokenSource? _cancellationTokenSource;
+
+        public ActivityProcessor(Func<Stream, CancellationToken, Task> 
streamWriterFunc)
+        {
+            _channel = Channel.CreateUnbounded<Activity>();
+            _streamWriterFunc = streamWriterFunc;
+        }
+
+        public bool TryWrite(Activity activity) => 
_channel.Writer.TryWrite(activity);
+
+        public async Task<bool> TryStartAsync()
+        {
+            if (_processingTask != null)
+            {
+                if (!_processingTask.IsCompleted)
+                {
+                    // Already running
+                    return false;
+                }
+                await StopAsync().ConfigureAwait(false);
+            }
+            _cancellationTokenSource = new CancellationTokenSource();
+            _processingTask = Task.Run(() => 
ProcessActivitiesAsync(_cancellationTokenSource.Token));
+            return true;
+        }
+
+        public async Task StopAsync(int timeout = 5000)
+        {
+            // Try to gracefully stop to allow processing of all queued items.
+            _channel.Writer.TryComplete();
+            if (_processingTask != null)
+            {
+                if (await Task.WhenAny(_processingTask, 
Task.Delay(timeout)).ConfigureAwait(false) != _processingTask)
+                {
+                    // Timeout - cancel
+                    _cancellationTokenSource?.Cancel();
+                    // Assume it will NOT throw any exceptions
+                    await _processingTask.ConfigureAwait(false);
+                }
+                _processingTask.Dispose();
+            }
+            _processingTask = null;
+            _cancellationTokenSource?.Dispose();
+            _cancellationTokenSource = null;
+        }
+
+        private async Task ProcessActivitiesAsync(CancellationToken 
cancellationToken)
+        {
+            try
+            {
+                using MemoryStream stream = new();
+                await foreach (Activity activity in 
_channel.Reader.ReadAllAsync(cancellationToken).ConfigureAwait(false))
+                {
+                    if (cancellationToken.IsCancellationRequested) break;
+
+                    stream.SetLength(0);
+                    SerializableActivity serializableActivity = new(activity);
+                    await JsonSerializer.SerializeAsync(
+                        stream,
+                        serializableActivity, cancellationToken: 
cancellationToken).ConfigureAwait(false);
+                    stream.Write(s_newLine, 0, s_newLine.Length);
+                    stream.Position = 0;
+
+                    await _streamWriterFunc(stream, 
cancellationToken).ConfigureAwait(false);
+                }
+            }
+            catch (OperationCanceledException ex)
+            {
+                // Expected when cancellationToken is cancelled.
+                Trace.TraceError(ex.ToString());
+            }
+            catch (Exception ex)
+            {
+                // Since this will be called on an independent thread, we need 
to avoid uncaught exceptions.
+                Trace.TraceError(ex.ToString());
+            }
+        }
+
+        public void Dispose()
+        {
+            StopAsync().ConfigureAwait(false).GetAwaiter().GetResult();
+        }
+    }
+}
diff --git 
a/csharp/src/Telemetry/Traces/Listeners/FileListener/FileActivityListener.cs 
b/csharp/src/Telemetry/Traces/Listeners/FileListener/FileActivityListener.cs
new file mode 100644
index 000000000..c170bf636
--- /dev/null
+++ b/csharp/src/Telemetry/Traces/Listeners/FileListener/FileActivityListener.cs
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Diagnostics;
+using System.IO;
+
+namespace Apache.Arrow.Adbc.Telemetry.Traces.Listeners.FileListener
+{
+    public sealed class FileActivityListener : IDisposable
+    {
+        public const long MaxFileSizeKbDefault = 1024;
+        public const int MaxTraceFilesDefault = 999;
+        internal const string ApacheArrowAdbcNamespace = "Apache.Arrow.Adbc";
+        private const string TracesFolderName = "Traces";
+
+        private readonly ActivityListener _listener;
+        private readonly TracingFile _tracingFile;
+        private readonly ActivityProcessor _activityProcessor;
+
+        public static bool TryActivateFileListener(
+            string activitySourceName,
+            string? exporterOption,
+            out FileActivityListener? listener,
+            Func<ActivitySource, bool>? shouldListenTo = default,
+            string environmentName = ListenersOptions.Environment.Exporter,
+            string? tracesLocation = null,
+            long maxTraceFileSizeKb = MaxFileSizeKbDefault,
+            int maxTraceFiles = MaxTraceFilesDefault)
+        {
+            listener = null;
+            if (string.IsNullOrWhiteSpace(exporterOption))
+            {
+                // Fall back to check the environment variable
+                exporterOption = 
Environment.GetEnvironmentVariable(environmentName);
+            }
+            if (string.IsNullOrWhiteSpace(exporterOption))
+            {
+                // Neither option or environment variable is set - no tracer 
provider will be activated.
+                return false;
+            }
+
+            if (string.Equals(exporterOption, 
ListenersOptions.Exporters.AdbcFile, StringComparison.OrdinalIgnoreCase))
+            {
+                try
+                {
+                    listener = new FileActivityListener(
+                        activitySourceName,
+                        tracesLocation,
+                        maxTraceFileSizeKb,
+                        maxTraceFiles,
+                        shouldListenTo);
+                    return true;
+                }
+                catch (Exception ex)
+                {
+                    // Swallow any exceptions to avoid impacting application 
behavior
+                    Trace.WriteLine(ex.Message);
+                    listener = null;
+                    return false;
+                }
+            }
+            return false;
+        }
+
+        public FileActivityListener(string fileBaseName, string? 
tracesLocation = null, long maxTraceFileSizeKb = MaxFileSizeKbDefault, int 
maxTraceFiles = MaxTraceFilesDefault, Func<ActivitySource, bool>? 
shouldListenTo = default)
+        {
+            tracesLocation = string.IsNullOrWhiteSpace(tracesLocation) ? 
TracingLocationDefault : tracesLocation;
+            ValidateParameters(fileBaseName, tracesLocation!, 
maxTraceFileSizeKb, maxTraceFiles);
+            DirectoryInfo tracesDirectory = new(tracesLocation); // Ensured to 
be valid by ValidateParameters
+            Func<ActivitySource, bool> shouldListenToAll = (source) => 
source.Name == fileBaseName;
+            _listener = new ActivityListener()
+            {
+                ShouldListenTo = shouldListenTo ?? shouldListenToAll,
+                Sample = (ref ActivityCreationOptions<ActivityContext> 
options) => ActivitySamplingResult.AllDataAndRecorded,
+            };
+
+            _tracingFile = new TracingFile(fileBaseName, 
tracesDirectory.FullName, maxTraceFileSizeKb, maxTraceFiles);
+            _activityProcessor = new 
ActivityProcessor(_tracingFile.WriteLineAsync);
+            _listener.ActivityStopped = OnActivityStopped;
+            ActivitySource.AddActivityListener(_listener);
+
+            
_activityProcessor.TryStartAsync().ConfigureAwait(false).GetAwaiter().GetResult();
+        }
+
+        public void Dispose()
+        {
+            _listener.Dispose();
+            _activityProcessor.Dispose();
+            _tracingFile.Dispose();
+        }
+
+        private void OnActivityStopped(Activity activity)
+        {
+            // Write activity to file or other storage
+            _activityProcessor.TryWrite(activity);
+        }
+
+        internal static void ValidateParameters(string fileBaseName, string 
traceLocation, long maxTraceFileSizeKb, int maxTraceFiles)
+        {
+            if (string.IsNullOrWhiteSpace(fileBaseName))
+                throw new ArgumentNullException(nameof(fileBaseName));
+            if (fileBaseName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
+                throw new ArgumentException("Invalid or unsupported file 
name", nameof(fileBaseName));
+            if (string.IsNullOrWhiteSpace(traceLocation) || 
traceLocation.IndexOfAny(Path.GetInvalidPathChars()) >= 0)
+                throw new ArgumentException("Invalid or unsupported folder 
name", nameof(traceLocation));
+            if (maxTraceFileSizeKb < 1)
+                throw new ArgumentException("maxTraceFileSizeKb must be 
greater than zero", nameof(maxTraceFileSizeKb));
+            if (maxTraceFiles < 1)
+                throw new ArgumentException("maxTraceFiles must be greater 
than zero.", nameof(maxTraceFiles));
+
+            IsDirectoryWritable(traceLocation, throwIfFails: true);
+        }
+
+        private static bool IsDirectoryWritable(string traceLocation, bool 
throwIfFails = false)
+        {
+            try
+            {
+                if (!Directory.Exists(traceLocation))
+                {
+                    Directory.CreateDirectory(traceLocation);
+                }
+                string tempFilePath = Path.Combine(traceLocation, 
Path.GetRandomFileName());
+                using FileStream fs = File.Create(tempFilePath, 1, 
FileOptions.DeleteOnClose);
+                return true;
+            }
+            catch when (!throwIfFails)
+            {
+                return false;
+            }
+        }
+
+        internal static string TracingLocationDefault { get; } =
+            new DirectoryInfo(
+                Path.Combine(
+                    
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
+                    ApacheArrowAdbcNamespace,
+                    TracesFolderName)).FullName;
+    }
+}
diff --git 
a/csharp/src/Telemetry/Traces/Exporters/FileExporter/SerializableActivity.cs 
b/csharp/src/Telemetry/Traces/Listeners/FileListener/SerializableActivity.cs
similarity index 99%
rename from 
csharp/src/Telemetry/Traces/Exporters/FileExporter/SerializableActivity.cs
rename to 
csharp/src/Telemetry/Traces/Listeners/FileListener/SerializableActivity.cs
index aff03a868..2af071a68 100644
--- a/csharp/src/Telemetry/Traces/Exporters/FileExporter/SerializableActivity.cs
+++ b/csharp/src/Telemetry/Traces/Listeners/FileListener/SerializableActivity.cs
@@ -21,7 +21,7 @@ using System.Diagnostics;
 using System.Linq;
 using System.Text.Json.Serialization;
 
-namespace Apache.Arrow.Adbc.Telemetry.Traces.Exporters.FileExporter
+namespace Apache.Arrow.Adbc.Telemetry.Traces.Listeners.FileListener
 {
     /// <summary>
     /// Simplified version of <see cref="Activity"/> that excludes some 
properties, etc.
diff --git a/csharp/src/Telemetry/Traces/Exporters/FileExporter/TracingFile.cs 
b/csharp/src/Telemetry/Traces/Listeners/FileListener/TracingFile.cs
similarity index 92%
rename from csharp/src/Telemetry/Traces/Exporters/FileExporter/TracingFile.cs
rename to csharp/src/Telemetry/Traces/Listeners/FileListener/TracingFile.cs
index 3bb0a4cfc..a6679bf4d 100644
--- a/csharp/src/Telemetry/Traces/Exporters/FileExporter/TracingFile.cs
+++ b/csharp/src/Telemetry/Traces/Listeners/FileListener/TracingFile.cs
@@ -23,7 +23,7 @@ using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 
-namespace Apache.Arrow.Adbc.Telemetry.Traces.Exporters.FileExporter
+namespace Apache.Arrow.Adbc.Telemetry.Traces.Listeners.FileListener
 {
     /// <summary>
     /// Provides access to writing trace files, limiting the
@@ -32,10 +32,14 @@ namespace 
Apache.Arrow.Adbc.Telemetry.Traces.Exporters.FileExporter
     internal class TracingFile : IDisposable
     {
         private const int KbInByes = 1024;
-        private static readonly string s_defaultTracePath = 
FileExporter.TracingLocationDefault;
+        private static readonly string s_defaultTracePath = 
FileActivityListener.TracingLocationDefault;
         private static readonly Random s_globalRandom = new();
         private static readonly ThreadLocal<Random> s_threadLocalRandom = 
new(NewRandom);
-        private static readonly Lazy<string> s_processId = new(() => 
Process.GetCurrentProcess().Id.ToString(), isThreadSafe: true);
+#if NET5_0_OR_GREATER
+        private static readonly Lazy<string> s_processId = new(static () => 
Environment.ProcessId.ToString(), isThreadSafe: true);
+#else
+        private static readonly Lazy<string> s_processId = new(static () => 
Process.GetCurrentProcess().Id.ToString(), isThreadSafe: true);
+#endif
         private readonly string _fileBaseName;
         private readonly DirectoryInfo _tracingDirectory;
         private FileInfo? _currentTraceFileInfo;
@@ -43,7 +47,7 @@ namespace 
Apache.Arrow.Adbc.Telemetry.Traces.Exporters.FileExporter
         private readonly long _maxFileSizeKb;
         private readonly int _maxTraceFiles;
 
-        internal TracingFile(string fileBaseName, string? traceDirectoryPath = 
default, long maxFileSizeKb = FileExporter.MaxFileSizeKbDefault, int 
maxTraceFiles = FileExporter.MaxTraceFilesDefault) :
+        internal TracingFile(string fileBaseName, string? traceDirectoryPath = 
default, long maxFileSizeKb = FileActivityListener.MaxFileSizeKbDefault, int 
maxTraceFiles = FileActivityListener.MaxTraceFilesDefault) :
             this(fileBaseName, ResolveTraceDirectory(traceDirectoryPath), 
maxFileSizeKb, maxTraceFiles)
         { }
 
@@ -79,9 +83,9 @@ namespace 
Apache.Arrow.Adbc.Telemetry.Traces.Exporters.FileExporter
             }
             catch (Exception ex)
             {
-                this._currentTraceFileInfo = null;
-                this._currentFileStream?.Dispose();
-                this._currentFileStream = null;
+                _currentTraceFileInfo = null;
+                _currentFileStream?.Dispose();
+                _currentFileStream = null;
                 Trace.TraceError(ex.ToString());
             }
 
@@ -96,7 +100,7 @@ namespace 
Apache.Arrow.Adbc.Telemetry.Traces.Exporters.FileExporter
                 string deleteSearchPattern = _fileBaseName + $"-trace-*.log";
                 IOrderedEnumerable<FileInfo> orderedFiles = await 
GetTracingFilesAsync(_tracingDirectory, 
deleteSearchPattern).ConfigureAwait(false);
                 // Avoid accidentally trying to delete the current file.
-                FileInfo[] tracingFiles = orderedFiles.Where(f => 
!f.FullName.Equals(_currentTraceFileInfo?.FullName))?.ToArray() ?? new 
FileInfo[0];
+                FileInfo[] tracingFiles = orderedFiles.Where(f => 
!f.FullName.Equals(_currentTraceFileInfo?.FullName))?.ToArray() ?? [];
                 if (tracingFiles.Length >= _maxTraceFiles)
                 {
                     int lastIndex = Math.Max(0, _maxTraceFiles - 1);
@@ -122,6 +126,8 @@ namespace 
Apache.Arrow.Adbc.Telemetry.Traces.Exporters.FileExporter
                 await OpenNewTracingFileAsync().ConfigureAwait(false);
             }
             await stream.CopyToAsync(_currentFileStream).ConfigureAwait(false);
+            // Flush for robustness to crashing
+            await stream.FlushAsync().ConfigureAwait(false);
         }
 
         private async Task OpenNewTracingFileAsync()
diff --git 
a/csharp/src/Telemetry/Traces/Exporters/FileExporter/SerializableActivityJsonContext.cs
 b/csharp/src/Telemetry/Traces/Listeners/ListenersOptions.cs
similarity index 56%
rename from 
csharp/src/Telemetry/Traces/Exporters/FileExporter/SerializableActivityJsonContext.cs
rename to csharp/src/Telemetry/Traces/Listeners/ListenersOptions.cs
index b5cec25f6..ad59d7499 100644
--- 
a/csharp/src/Telemetry/Traces/Exporters/FileExporter/SerializableActivityJsonContext.cs
+++ b/csharp/src/Telemetry/Traces/Listeners/ListenersOptions.cs
@@ -15,18 +15,21 @@
  * limitations under the License.
  */
 
-using System.Text.Json.Serialization;
-
-namespace Apache.Arrow.Adbc.Telemetry.Traces.Exporters.FileExporter
+namespace Apache.Arrow.Adbc.Telemetry.Traces.Listeners
 {
-    /// <summary>
-    /// Provides a source-generated JSON serialization context for the <see 
cref="SerializableActivity"/> type.
-    /// </summary>
-    /// <remarks>This context is used to optimize JSON serialization and 
deserialization of <see
-    /// cref="SerializableActivity"/> objects by leveraging source generation. 
It is intended for internal use within
-    /// the application.</remarks>
-    [JsonSerializable(typeof(SerializableActivity))]
-    internal partial class SerializableActivityJsonContext : 
JsonSerializerContext
+    public class ListenersOptions
     {
+        public const string Exporter = "adbc.traces.exporter";
+
+        public static class Environment
+        {
+            public const string Exporter = "OTEL_TRACES_EXPORTER";
+        }
+
+        public static class Exporters
+        {
+            public const string None = "none";
+            public const string AdbcFile = "adbcfile";
+        }
     }
 }
diff --git a/csharp/src/Telemetry/Traces/Listeners/Properties/AssemblyInfo.cs 
b/csharp/src/Telemetry/Traces/Listeners/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..bfb6f1353
--- /dev/null
+++ b/csharp/src/Telemetry/Traces/Listeners/Properties/AssemblyInfo.cs
@@ -0,0 +1,19 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("Apache.Arrow.Adbc.Telemetry.Traces.Exporters, 
PublicKey=0024000004800000940000000602000000240000525341310004000001000100e504183f6d470d6b67b6d19212be3e1f598f70c246a120194bc38130101d0c1853e4a0f2232cb12e37a7a90e707aabd38511dac4f25fcb0d691b2aa265900bf42de7f70468fc997551a40e1e0679b605aa2088a4a69e07c117e988f5b1738c570ee66997fba02485e7856a49eca5fd0706d09899b8312577cbb9034599fc92d4")]
+[assembly: 
InternalsVisibleTo("Apache.Arrow.Adbc.Tests.Telemetry.Traces.Listeners, 
PublicKey=0024000004800000940000000602000000240000525341310004000001000100e504183f6d470d6b67b6d19212be3e1f598f70c246a120194bc38130101d0c1853e4a0f2232cb12e37a7a90e707aabd38511dac4f25fcb0d691b2aa265900bf42de7f70468fc997551a40e1e0679b605aa2088a4a69e07c117e988f5b1738c570ee66997fba02485e7856a49eca5fd0706d09899b8312577cbb9034599fc92d4")]
diff --git a/csharp/src/Telemetry/Traces/Exporters/readme.md 
b/csharp/src/Telemetry/Traces/Listeners/readme.md
similarity index 72%
copy from csharp/src/Telemetry/Traces/Exporters/readme.md
copy to csharp/src/Telemetry/Traces/Listeners/readme.md
index 8b743c7e7..1328d87bd 100644
--- a/csharp/src/Telemetry/Traces/Exporters/readme.md
+++ b/csharp/src/Telemetry/Traces/Listeners/readme.md
@@ -17,14 +17,16 @@
 
 -->
 
-# Traces Exporters
+# Traces Listeners
 
-## FileExporter
+## FileActivityListener
 
-Provides an OpenTelemetry (OTel) exporter to write telemetry traces to
+Provides an ActivityListener to write telemetry traces to
 rotating files in folder. File names are created with the following pattern:
 `<trace-source>-<YYYY-MM-DD-HH-mm-ss-fff>-<process-id>.log`.
+
 For example: 
`apache.arrow.adbc.drivers.databricks-2025-08-15-10-35-56-012345-99999.log`.
+
 The default folder used is:
 
 | Platform | Folder |
@@ -33,22 +35,15 @@ The default folder used is:
 | macOS   | `$HOME/Library/Application Support/Apache.Arrow.Adbc/Traces` |
 | Linux   | `$HOME/.local/share/Apache.Arrow.Adbc/Traces` |
 
-By default, up to 100 files of maximum size 1024 KB are written to
+By default, up to 999 files of maximum size 1024 KB are written to
 the trace folder.
 
-## ExportersBuilder
-
-Helps activate one of a dictionary of supported exporters.
-
 The environment variable `OTEL_TRACES_EXPORTER` can be used to select one of 
the
 available exporters. Or the database parameter `adbc.traces.exporter` can be 
used,
 which has precedence over the environment variable.
 
-The following exporters are supported:
+The following listeners are supported:
 
-| Exporter | Description |
+| Listener | Description |
 | --- | --- |
-| `otlp` | Exports traces to an OpenTelemetry Collector or directly to an Open 
Telemetry Line Protocol (OTLP) endpoint. |
-| `file` | Exports traces to rotating files in a folder. |
-| `console` | Exports traces to the console output. |
-| `none` | Disables trace exporting. |
+| `adbcfile` | Exports traces to rotating files in a folder. |
diff --git a/csharp/test/Drivers/Apache/Common/TelemetryTests.cs 
b/csharp/test/Drivers/Apache/Common/TelemetryTests.cs
new file mode 100644
index 000000000..12be91cf9
--- /dev/null
+++ b/csharp/test/Drivers/Apache/Common/TelemetryTests.cs
@@ -0,0 +1,110 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*    http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using Apache.Arrow.Adbc.Telemetry.Traces.Listeners;
+using Apache.Arrow.Adbc.Tracing;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Apache.Arrow.Adbc.Tests.Drivers.Apache.Common
+{
+    public abstract class TelemetryTests<TConfig, TEnv> : TestBase<TConfig, 
TEnv>
+        where TConfig : TestConfiguration
+        where TEnv : CommonTestEnvironment<TConfig>
+    {
+        public TelemetryTests(ITestOutputHelper output, 
TestEnvironment<TConfig>.Factory<TEnv> testEnvFactory)
+            : base(output, testEnvFactory) { }
+
+        [SkippableTheory]
+        [InlineData(ListenersOptions.Exporters.AdbcFile)]
+        [InlineData(null)]
+        [InlineData(ListenersOptions.Exporters.None)]
+        public void CanEnableFileTracingExporterViaEnvVariable(string? 
exporterName)
+        {
+            
Environment.SetEnvironmentVariable(ListenersOptions.Environment.Exporter, 
exporterName);
+
+            DirectoryInfo directoryInfo = GetTracesDirectoryInfo();
+            ResetTraceDirectory(directoryInfo);
+
+            directoryInfo.Refresh();
+            IEnumerable<FileInfo> files = directoryInfo.EnumerateFiles();
+            Assert.Empty(files);
+            string activitySourceName = string.Empty;
+
+            try
+            {
+                Dictionary<string, string> parameters = 
GetDriverParameters(TestConfiguration);
+                using (AdbcDatabase database = NewDriver.Open(parameters))
+                {
+                    try
+                    {
+                        using AdbcConnection connection = database.Connect(new 
Dictionary<string, string>());
+                        TracingConnection? tc = connection as 
TracingConnection;
+                        Assert.NotNull(tc);
+                        
Assert.True(string.IsNullOrEmpty(tc.ActivitySourceName), "expecting non-empty 
ActivitySourceName");
+                        activitySourceName = tc.ActivitySourceName;
+                    }
+                    catch (Exception ex)
+                    {
+                        // We don't really need the connection to succeed for 
this test,
+                        OutputHelper?.WriteLine(ex.Message);
+                    }
+                }
+
+                directoryInfo.Refresh();
+                files = directoryInfo.EnumerateFiles();
+                switch (exporterName)
+                {
+                    case ListenersOptions.Exporters.AdbcFile:
+                        Assert.NotEmpty(files);
+                        Assert.NotEqual(0, files.First().Length);
+                        Assert.StartsWith(activitySourceName, 
files.First().Name);
+                        break;
+                    default:
+                        Assert.Empty(files);
+                        break;
+                }
+            }
+            finally
+            {
+                ResetTraceDirectory(directoryInfo, create: false);
+            }
+        }
+
+        private static void ResetTraceDirectory(DirectoryInfo directoryInfo, 
bool create = true)
+        {
+            if (directoryInfo.Exists)
+            {
+                directoryInfo.Delete(recursive: true);
+            }
+            if (create)
+            {
+                directoryInfo.Create();
+            }
+        }
+
+        private static DirectoryInfo GetTracesDirectoryInfo() =>
+            new DirectoryInfo(Path.Combine(
+                
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
+                "Apache.Arrow.Adbc",
+                "Traces"));
+    }
+}
diff --git a/csharp/test/Drivers/Apache/Hive2/TelemetryTests.cs 
b/csharp/test/Drivers/Apache/Hive2/TelemetryTests.cs
new file mode 100644
index 000000000..6082a49bf
--- /dev/null
+++ b/csharp/test/Drivers/Apache/Hive2/TelemetryTests.cs
@@ -0,0 +1,29 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*    http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using Apache.Arrow.Adbc.Tests.Drivers.Apache.Common;
+using Xunit.Abstractions;
+
+namespace Apache.Arrow.Adbc.Tests.Drivers.Apache.Hive2;
+
+public class TelemetryTests : TelemetryTests<ApacheTestConfiguration, 
HiveServer2TestEnvironment>
+{
+    public TelemetryTests(ITestOutputHelper outputHelper)
+        : base(outputHelper, new HiveServer2TestEnvironment.Factory())
+    {
+    }
+}
diff --git a/csharp/test/Drivers/Apache/Impala/TelemetryTests.cs 
b/csharp/test/Drivers/Apache/Impala/TelemetryTests.cs
new file mode 100644
index 000000000..94ab33cdd
--- /dev/null
+++ b/csharp/test/Drivers/Apache/Impala/TelemetryTests.cs
@@ -0,0 +1,30 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*    http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using Apache.Arrow.Adbc.Tests.Drivers.Apache.Common;
+using Xunit.Abstractions;
+
+namespace Apache.Arrow.Adbc.Tests.Drivers.Apache.Impala
+{
+    public class TelemetryTests : TelemetryTests<ApacheTestConfiguration, 
ImpalaTestEnvironment>
+    {
+        public TelemetryTests(ITestOutputHelper outputHelper)
+            : base(outputHelper, new ImpalaTestEnvironment.Factory())
+        {
+        }
+    }
+}
diff --git a/csharp/test/Drivers/Apache/Spark/TelemetryTests.cs 
b/csharp/test/Drivers/Apache/Spark/TelemetryTests.cs
new file mode 100644
index 000000000..aacdb1f3d
--- /dev/null
+++ b/csharp/test/Drivers/Apache/Spark/TelemetryTests.cs
@@ -0,0 +1,30 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*    http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using Apache.Arrow.Adbc.Tests.Drivers.Apache.Common;
+using Xunit.Abstractions;
+
+namespace Apache.Arrow.Adbc.Tests.Drivers.Apache.Spark
+{
+    public class TelemetryTests : TelemetryTests<SparkTestConfiguration, 
SparkTestEnvironment>
+    {
+        public TelemetryTests(ITestOutputHelper outputHelper)
+            : base(outputHelper, new SparkTestEnvironment.Factory())
+        {
+        }
+    }
+}
diff --git a/csharp/test/Drivers/BigQuery/TelemetryTests.cs 
b/csharp/test/Drivers/BigQuery/TelemetryTests.cs
new file mode 100644
index 000000000..ba30eddad
--- /dev/null
+++ b/csharp/test/Drivers/BigQuery/TelemetryTests.cs
@@ -0,0 +1,120 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*    http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using Apache.Arrow.Adbc.Drivers.BigQuery;
+using Apache.Arrow.Adbc.Telemetry.Traces.Listeners;
+using Apache.Arrow.Adbc.Tracing;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Apache.Arrow.Adbc.Tests.Drivers.BigQuery
+{
+    public class TelemetryTests
+    {
+        readonly BigQueryTestConfiguration _testConfiguration;
+        readonly List<BigQueryTestEnvironment> _environments;
+        readonly ITestOutputHelper _outputHelper;
+
+        public TelemetryTests(ITestOutputHelper outputHelper)
+        {
+            _testConfiguration = 
MultiEnvironmentTestUtils.LoadMultiEnvironmentTestConfiguration<BigQueryTestConfiguration>(BigQueryTestingUtils.BIGQUERY_TEST_CONFIG_VARIABLE);
+            _environments = 
MultiEnvironmentTestUtils.GetTestEnvironments<BigQueryTestEnvironment>(_testConfiguration);
+            _outputHelper = outputHelper;
+        }
+
+        [SkippableTheory]
+        [InlineData(ListenersOptions.Exporters.AdbcFile)]
+        [InlineData(null)]
+        [InlineData(ListenersOptions.Exporters.None)]
+        public void CanEnableFileTracingExporterViaEnvVariable(string? 
exporterName)
+        {
+            
Environment.SetEnvironmentVariable(ListenersOptions.Environment.Exporter, 
exporterName);
+
+            foreach (BigQueryTestEnvironment environment in _environments)
+            {
+                DirectoryInfo directoryInfo = GetTracesDirectoryInfo();
+                ResetTraceDirectory(directoryInfo);
+
+                directoryInfo.Refresh();
+                IEnumerable<FileInfo> files = directoryInfo.EnumerateFiles();
+                Assert.Empty(files);
+                string activitySourceName = string.Empty;
+
+                try
+                {
+                    Dictionary<string, string> parameters = 
BigQueryTestingUtils.GetBigQueryParameters(environment);
+                    using (AdbcDatabase database = new 
BigQueryDriver().Open(parameters))
+                    {
+                        try
+                        {
+                            using AdbcConnection connection = 
database.Connect(new Dictionary<string, string>());
+                            TracingConnection? tc = connection as 
TracingConnection;
+                            Assert.NotNull(tc);
+                            Assert.True(tc.ActivitySourceName.Length > 0, 
"Activity source name should not be empty");
+                            activitySourceName = tc.ActivitySourceName;
+                        }
+                        catch (Exception ex)
+                        {
+                            // We don't really need the connection to succeed 
for this test,
+                            _outputHelper?.WriteLine(ex.Message);
+                        }
+                    }
+
+                    directoryInfo.Refresh();
+                    files = directoryInfo.EnumerateFiles();
+                    switch (exporterName)
+                    {
+                        case ListenersOptions.Exporters.AdbcFile:
+                            Assert.NotEmpty(files);
+                            Assert.NotEqual(0, files.First().Length);
+                            Assert.StartsWith(activitySourceName, 
files.First().Name, StringComparison.OrdinalIgnoreCase);
+                            break;
+                        default:
+                            Assert.Empty(files);
+                            break;
+                    }
+                }
+                finally
+                {
+                    ResetTraceDirectory(directoryInfo, create: false);
+                }
+            }
+        }
+
+        private static void ResetTraceDirectory(DirectoryInfo directoryInfo, 
bool create = true)
+        {
+            if (directoryInfo.Exists)
+            {
+                directoryInfo.Delete(recursive: true);
+            }
+            if (create)
+            {
+                directoryInfo.Create();
+            }
+        }
+
+        private static DirectoryInfo GetTracesDirectoryInfo() =>
+            new DirectoryInfo(Path.Combine(
+                
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
+                "Apache.Arrow.Adbc",
+                "Traces"));
+    }
+}
diff --git a/csharp/test/Drivers/Databricks/E2E/TelemetryTests.cs 
b/csharp/test/Drivers/Databricks/E2E/TelemetryTests.cs
new file mode 100644
index 000000000..0b257b3ee
--- /dev/null
+++ b/csharp/test/Drivers/Databricks/E2E/TelemetryTests.cs
@@ -0,0 +1,30 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*    http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using Apache.Arrow.Adbc.Tests.Drivers.Apache.Common;
+using Xunit.Abstractions;
+
+namespace Apache.Arrow.Adbc.Tests.Drivers.Databricks
+{
+    public class TelemetryTests : TelemetryTests<DatabricksTestConfiguration, 
DatabricksTestEnvironment>
+    {
+        public TelemetryTests(ITestOutputHelper outputHelper)
+            : base(outputHelper, new DatabricksTestEnvironment.Factory())
+        {
+        }
+    }
+}
diff --git 
a/csharp/test/Telemetry/Traces/Exporters/FileExporter/FileExporterTests.cs 
b/csharp/test/Telemetry/Traces/Exporters/FileExporter/FileExporterTests.cs
index 2eaf7dc72..4e62ea67b 100644
--- a/csharp/test/Telemetry/Traces/Exporters/FileExporter/FileExporterTests.cs
+++ b/csharp/test/Telemetry/Traces/Exporters/FileExporter/FileExporterTests.cs
@@ -193,7 +193,6 @@ namespace 
Apache.Arrow.Adbc.Tests.Telemetry.Traces.Exporters.FileExporter
         {
             const long maxTraceFileSizeKb = 5;
             const int maxTraceFiles = 1;
-            var delay = TimeSpan.FromSeconds(8);
             string customFolderName = ExportersBuilderTests.NewName();
             string traceFolder = 
Path.Combine(s_localApplicationDataFolderPath, customFolderName);
 
@@ -265,8 +264,8 @@ namespace 
Apache.Arrow.Adbc.Tests.Telemetry.Traces.Exporters.FileExporter
                     .Build();
                 var tasks = new Task[]
                 {
-                    Task.Run(async () => await TraceActivities(traceFolder, 
"activity1", writeCount, provider1)),
-                    Task.Run(async () => await TraceActivities(traceFolder, 
"activity2", writeCount, provider2)),
+                    Task.Run(async () => await TraceActivities("activity1", 
writeCount, provider1)),
+                    Task.Run(async () => await TraceActivities("activity2", 
writeCount, provider2)),
                 };
                 await Task.WhenAll(tasks);
                 await Task.Delay(500);
@@ -301,7 +300,7 @@ namespace 
Apache.Arrow.Adbc.Tests.Telemetry.Traces.Exporters.FileExporter
             }
         }
 
-        private async Task TraceActivities(string traceFolder, string 
activityName, int writeCount, TracerProvider provider)
+        private async Task TraceActivities(string activityName, int 
writeCount, TracerProvider provider)
         {
             for (int i = 0; i < writeCount; i++)
             {
diff --git 
a/csharp/test/Telemetry/Traces/Listeners/Apache.Arrow.Adbc.Tests.Telemetry.Traces.Listeners.csproj
 
b/csharp/test/Telemetry/Traces/Listeners/Apache.Arrow.Adbc.Tests.Telemetry.Traces.Listeners.csproj
new file mode 100644
index 000000000..935cbfb7a
--- /dev/null
+++ 
b/csharp/test/Telemetry/Traces/Listeners/Apache.Arrow.Adbc.Tests.Telemetry.Traces.Listeners.csproj
@@ -0,0 +1,29 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFrameworks 
Condition="'$(IsWindows)'=='true'">net8.0;net472</TargetFrameworks>
+    <TargetFrameworks 
Condition="'$(TargetFrameworks)'==''">net8.0</TargetFrameworks>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+
+    <IsPackable>false</IsPackable>
+    <IsTestProject>true</IsTestProject>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="coverlet.collector" Version="6.0.0" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
+    <PackageReference Include="xunit" Version="2.5.3" />
+    <PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference 
Include="..\..\..\..\src\Apache.Arrow.Adbc\Apache.Arrow.Adbc.csproj" />
+    <ProjectReference 
Include="..\..\..\..\src\Telemetry\Traces\Listeners\Apache.Arrow.Adbc.Telemetry.Traces.Listeners.csproj"
 />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Using Include="Xunit" />
+  </ItemGroup>
+
+</Project>
diff --git 
a/csharp/test/Telemetry/Traces/Listeners/FileListener/FileActivityListenerTests.cs
 
b/csharp/test/Telemetry/Traces/Listeners/FileListener/FileActivityListenerTests.cs
new file mode 100644
index 000000000..ad33ee809
--- /dev/null
+++ 
b/csharp/test/Telemetry/Traces/Listeners/FileListener/FileActivityListenerTests.cs
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System.Diagnostics;
+using Apache.Arrow.Adbc.Telemetry.Traces.Listeners;
+using Apache.Arrow.Adbc.Telemetry.Traces.Listeners.FileListener;
+using Apache.Arrow.Adbc.Tracing;
+using Apache.Arrow.Ipc;
+
+namespace Apache.Arrow.Adbc.Tests.Telemetry.Traces.Listeners.FileListener
+{
+    public class FileActivityListenerTests
+    {
+        private const string TraceLocation = "adbc.trace.location";
+
+        [Theory]
+        [InlineData(null, false)]
+        [InlineData("", false)]
+        [InlineData(" ", false)]
+        [InlineData(ListenersOptions.Exporters.None, false)]
+        [InlineData(ListenersOptions.Exporters.AdbcFile, true)]
+        public void TestTryActivateFileListener(string? exporterOption, bool 
expected)
+        {
+            Assert.Equal(expected, 
FileActivityListener.TryActivateFileListener("TestSource", exporterOption, out 
FileActivityListener? listener));
+            Assert.True(expected == (listener != null));
+            listener?.Dispose();
+        }
+
+        [Fact]
+        public async Task CanTraceConcurrentConnections()
+        {
+            const int numConnections = 5;
+            const int numActivitiesPerConnection = 1000;
+            string folderLocation = 
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
 TracingFileTests.NewName());
+
+            try
+            {
+                TestConnection[] connections = new 
TestConnection[numConnections];
+                for (int i = 0; i < numConnections; i++)
+                {
+                    connections[i] = new TestConnection(new Dictionary<string, 
string>
+                    {
+                        { ListenersOptions.Exporter, 
ListenersOptions.Exporters.AdbcFile },
+                        { TraceLocation, folderLocation },
+                    });
+                }
+
+                Task[] tasks = new Task[numConnections];
+                for (int i = 0; i < numConnections; i++)
+                {
+                    TestConnection testConnection = connections[i];
+                    int connectionId = i;
+                    tasks[i] = Task.Run(async () =>
+                    {
+                        for (int j = 0; j < numActivitiesPerConnection; j++)
+                        {
+                            await testConnection.EmulateWorkAsync("Key", 
$"Value-{connectionId}-{j}");
+                        }
+                    });
+                }
+                for (int i = 0; i < numConnections; i++)
+                {
+                    await tasks[i];
+                    tasks[i].Dispose();
+                }
+                for (int i = 0; i < numConnections; i++)
+                {
+                    var testConnection = (TestConnection)connections[i];
+                    testConnection.Dispose();
+                }
+
+                Assert.True(Directory.Exists(folderLocation));
+                DirectoryInfo dirInfo = new(folderLocation);
+                FileInfo[] files = dirInfo.GetFiles();
+                Assert.True(files.Length > 0, "No trace files were created.");
+                int totalLines = 0;
+                foreach (FileInfo file in files)
+                {
+                    totalLines += File.ReadAllLines(file.FullName).Length;
+                }
+                Assert.Equal(numConnections * numActivitiesPerConnection, 
totalLines);
+            }
+            finally
+            {
+                if (Directory.Exists(folderLocation))
+                {
+                    Directory.Delete(folderLocation, recursive: true);
+                }
+            }
+        }
+
+        private class TestConnection : TracingConnection
+        {
+            private static readonly string s_assemblyName = 
typeof(TestConnection).Assembly.GetName().Name!;
+            private static readonly string s_assemblyVersion = 
typeof(TestConnection).Assembly.GetName().Version!.ToString();
+
+            private readonly string _traceId = Guid.NewGuid().ToString("N");
+            private readonly FileActivityListener? _fileListener;
+
+            public TestConnection(IReadOnlyDictionary<string, string> 
properties)
+                : base(properties)
+            {
+                properties.TryGetValue(TraceLocation, out string? 
tracesLocation);
+                properties.TryGetValue(ListenersOptions.Exporter, out string? 
exporterOption);
+                bool shouldListenTo(ActivitySource source) => 
source.Tags?.Any(t => ReferenceEquals(t.Key, _traceId)) == true;
+                
FileActivityListener.TryActivateFileListener(ActivitySourceName, 
exporterOption, out _fileListener, shouldListenTo, tracesLocation: 
tracesLocation);
+            }
+
+            public async Task EmulateWorkAsync(string key, string value)
+            {
+                await this.TraceActivityAsync(async (activity) =>
+                {
+                    activity?.SetTag(key, value);
+                    // Simulate some work
+                    await Task.Yield();
+                });
+            }
+
+            public override IEnumerable<KeyValuePair<string, object?>>? 
GetActivitySourceTags(IReadOnlyDictionary<string, string> properties)
+            {
+                IEnumerable<KeyValuePair<string, object?>>? tags = 
base.GetActivitySourceTags(properties);
+                tags ??= [];
+                tags = tags.Concat([new(_traceId, null)]);
+                return tags;
+            }
+
+            public override string AssemblyVersion => s_assemblyVersion;
+
+            public override string AssemblyName => s_assemblyName;
+
+            public override AdbcStatement CreateStatement() => throw new 
NotImplementedException();
+            public override IArrowArrayStream GetObjects(GetObjectsDepth 
depth, string? catalogPattern, string? dbSchemaPattern, string? 
tableNamePattern, IReadOnlyList<string>? tableTypes, string? columnNamePattern) 
=> throw new NotImplementedException();
+            public override Schema GetTableSchema(string? catalog, string? 
dbSchema, string tableName) => throw new NotImplementedException();
+            public override IArrowArrayStream GetTableTypes() => throw new 
NotImplementedException();
+
+            protected override void Dispose(bool disposing)
+            {
+                _fileListener?.Dispose();
+                base.Dispose(disposing);
+            }
+        }
+    }
+}
diff --git 
a/csharp/test/Telemetry/Traces/Exporters/FileExporter/TracingFileTests.cs 
b/csharp/test/Telemetry/Traces/Listeners/TracingFileTests.cs
similarity index 82%
rename from 
csharp/test/Telemetry/Traces/Exporters/FileExporter/TracingFileTests.cs
rename to csharp/test/Telemetry/Traces/Listeners/TracingFileTests.cs
index 3392ea031..54504a729 100644
--- a/csharp/test/Telemetry/Traces/Exporters/FileExporter/TracingFileTests.cs
+++ b/csharp/test/Telemetry/Traces/Listeners/TracingFileTests.cs
@@ -15,15 +15,10 @@
  * limitations under the License.
  */
 
-using System;
-using System.Collections.Generic;
-using System.IO;
 using System.Runtime.CompilerServices;
-using System.Threading;
-using System.Threading.Tasks;
-using Apache.Arrow.Adbc.Telemetry.Traces.Exporters.FileExporter;
+using Apache.Arrow.Adbc.Telemetry.Traces.Listeners.FileListener;
 
-namespace Apache.Arrow.Adbc.Tests.Telemetry.Traces.Exporters.FileExporter
+namespace Apache.Arrow.Adbc.Tests.Telemetry.Traces.Listeners.FileListener
 {
     public class TracingFileTests
     {
@@ -40,12 +35,12 @@ namespace 
Apache.Arrow.Adbc.Tests.Telemetry.Traces.Exporters.FileExporter
         [Fact]
         internal async Task TestMultipleConcurrentTracingFiles()
         {
-            CancellationTokenSource tokenSource = new 
CancellationTokenSource();
+            CancellationTokenSource tokenSource = new();
             int concurrentCount = 50;
             Task[] tasks = new Task[concurrentCount];
             int[] lineCounts = new int[concurrentCount];
-            string sourceName = ExportersBuilderTests.NewName();
-            string customFolderName = ExportersBuilderTests.NewName();
+            string sourceName = NewName();
+            string customFolderName = NewName();
             string traceFolder = 
Path.Combine(s_localApplicationDataFolderPath, customFolderName);
             if (Directory.Exists(traceFolder)) Directory.Delete(traceFolder, 
true);
             try
@@ -56,7 +51,7 @@ namespace 
Apache.Arrow.Adbc.Tests.Telemetry.Traces.Exporters.FileExporter
                 }
                 await Task.WhenAll(tasks);
 
-                foreach (var file in Directory.GetFiles(traceFolder))
+                foreach (string file in Directory.GetFiles(traceFolder))
                 {
                     foreach (string line in File.ReadLines(file))
                     {
@@ -80,8 +75,8 @@ namespace 
Apache.Arrow.Adbc.Tests.Telemetry.Traces.Exporters.FileExporter
         private async Task Run(string sourceName, string traceFolder, 
CancellationToken cancellationToken)
         {
             int instanceNumber = Interlocked.Increment(ref _testInstance) - 1;
-            using TracingFile tracingFile = new TracingFile(sourceName, 
traceFolder);
-            await foreach (var stream in GetLinesAsync(instanceNumber, 100, 
cancellationToken))
+            using TracingFile tracingFile = new(sourceName, traceFolder);
+            await foreach (Stream stream in GetLinesAsync(instanceNumber, 100, 
cancellationToken))
             {
                 await tracingFile.WriteLineAsync(stream, cancellationToken);
             }
@@ -93,8 +88,10 @@ namespace 
Apache.Arrow.Adbc.Tests.Telemetry.Traces.Exporters.FileExporter
             {
                 if (cancellationToken.IsCancellationRequested) yield break;
                 yield return new 
MemoryStream(System.Text.Encoding.UTF8.GetBytes($"line{instanceNumber}" + 
Environment.NewLine));
-                await Task.Delay(10); // Simulate some delay
+                await Task.Delay(10, cancellationToken); // Simulate some delay
             }
         }
+
+        internal static string NewName() => Guid.NewGuid().ToString("N");
     }
 }


Reply via email to