Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
e68a56c
feat(csharp/src/Drivers/BigQuery): instrument OTel exporters for BigQ…
birschick-bq Aug 18, 2025
2e511ee
small improvement
birschick-bq Aug 18, 2025
d5e34d5
reworked static initialization. added REAME.md docs
birschick-bq Aug 19, 2025
c1cd4da
add unit test to ensure adbcfile exporter creates files in the expect…
birschick-bq Aug 19, 2025
a3f475b
modify test to be more reliable.
birschick-bq Aug 20, 2025
98ae2a0
Merge branch 'main' into dev/birschick-bq/bigquery-exporter
birschick-bq Aug 21, 2025
1e1cf4e
Fix a number of problems that cause tracing to fail. Added tests. Add…
birschick-bq Aug 21, 2025
c3b38aa
Merge branch 'main' into dev/birschick-bq/bigquery-exporter
birschick-bq Aug 28, 2025
ea5f0a5
Merge branch 'main' into dev/birschick-bq/bigquery-exporter
birschick-bq Sep 3, 2025
c4ae06e
feat(csharp/src/Telemetry/Traces/Exporters): refactor and improve per…
birschick-bq Sep 5, 2025
532f2c0
add automated unit tests
birschick-bq Sep 5, 2025
c97f97d
restore a previous default
birschick-bq Sep 5, 2025
c886b82
attempt test stability
birschick-bq Sep 5, 2025
48dbbad
attempt test stability #2
birschick-bq Sep 5, 2025
265de5d
attempt test stability - 3
birschick-bq Sep 5, 2025
c3ca343
attempt test stability - 4
birschick-bq Sep 5, 2025
f55bf3c
attempt test stability - 5
birschick-bq Sep 5, 2025
90bbc4a
Merge branch 'main' into dev/birschick-bq/improve-file-exporter
birschick-bq Sep 7, 2025
21173e6
Merge branch 'main' into dev/birschick-bq/bigquery-exporter
birschick-bq Sep 7, 2025
20bb6c2
Merge branch 'dev/birschick-bq/improve-file-exporter' into dev/birsch…
birschick-bq Sep 7, 2025
f829caa
Attempt test stability - 5
birschick-bq Sep 7, 2025
3fb86a4
Attempt test stability - 5
birschick-bq Sep 7, 2025
3886446
Improve error handling and reduce number of retries.
birschick-bq Sep 8, 2025
8881bcf
Improve file name to avoid file name clash
birschick-bq Sep 8, 2025
b0bae4e
Improve back-off for file create.
birschick-bq Sep 8, 2025
607355c
Improve error handling - 2.
birschick-bq Sep 8, 2025
b3c6c0c
Merge branch 'dev/birschick-bq/improve-file-exporter' into dev/birsch…
birschick-bq Sep 9, 2025
da686c6
Merge branch 'main' into dev/birschick-bq/bigquery-exporter
birschick-bq Sep 15, 2025
bc43c31
Merge branch 'main' into dev/birschick-bq/bigquery-exporter
birschick-bq Sep 18, 2025
0b8c510
remove unit test script update
birschick-bq Sep 18, 2025
ac66860
corrected formatting
birschick-bq Sep 18, 2025
429d8ae
Add light-weight Listeners
birschick-bq Sep 19, 2025
03236d6
remove unnecessary using statements
birschick-bq Sep 19, 2025
76cb74f
add explanitory comments
birschick-bq Sep 19, 2025
12ea879
add README updates
birschick-bq Sep 19, 2025
443b8df
add README updates - 2
birschick-bq Sep 19, 2025
260f8f0
minor changes
birschick-bq Sep 20, 2025
31aa647
code review changes - 1
birschick-bq Sep 23, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

<ItemGroup>
<ProjectReference Include="..\..\Apache.Arrow.Adbc\Apache.Arrow.Adbc.csproj" />
<ProjectReference Include="..\..\Telemetry\Traces\Exporters\Apache.Arrow.Adbc.Telemetry.Traces.Exporters.csproj" />
</ItemGroup>

</Project>
52 changes: 51 additions & 1 deletion csharp/src/Drivers/Apache/Hive2/HiveServer2Connection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@
using System.Threading.Tasks;
using Apache.Arrow.Adbc.Drivers.Apache.Thrift;
using Apache.Arrow.Adbc.Extensions;
using Apache.Arrow.Adbc.Telemetry.Traces.Exporters;
using Apache.Arrow.Adbc.Tracing;
using Apache.Arrow.Ipc;
using Apache.Arrow.Types;
using Apache.Hive.Service.Rpc.Thrift;
using OpenTelemetry.Trace;
using Thrift.Protocol;
using Thrift.Transport;

Expand All @@ -49,6 +51,9 @@ internal abstract class HiveServer2Connection : TracingConnection
private readonly Lazy<string> _vendorVersion;
private readonly Lazy<string> _vendorName;
private bool _isDisposed;
private static readonly object s_tracerProviderLock = new object();
private static TracerProvider? s_tracerProvider;
private static bool s_isFileExporterEnabled = false;

readonly AdbcInfoCode[] infoSupportedCodes = [
AdbcInfoCode.DriverName,
Expand Down Expand Up @@ -278,6 +283,8 @@ internal HiveServer2Connection(IReadOnlyDictionary<string, string> properties)
{
Properties = properties;

TryInitTracerProvider();

// 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.
Expand All @@ -294,6 +301,48 @@ internal HiveServer2Connection(IReadOnlyDictionary<string, string> properties)
}
}

private void TryInitTracerProvider()
{
// Avoid locking if the tracer provider is already set.
if (s_tracerProvider != null)
{
return;
}
// Avoid locking if the exporter option would not activate.
Properties.TryGetValue(ExportersOptions.Exporter, out string? exporterOption);
ExportersBuilder exportersBuilder = ExportersBuilder.Build(this.ActivitySourceName, addDefaultExporters: true).Build();
if (!exportersBuilder.WouldActivate(exporterOption))
{
return;
}

// Will likely activate the exporter, so we need to lock to ensure thread safety.
lock (s_tracerProviderLock)
{
// Due to race conditions, we need to check again if the tracer provider is already set.
if (s_tracerProvider != null)
{
return;
}

// Activates the exporter specified in the connection property (if exists) or environment variable (if is set).
if (exportersBuilder.TryActivate(exporterOption, out string? exporterName, out TracerProvider? tracerProvider, ExportersOptions.Environment.Exporter) && tracerProvider != null)
{
s_tracerProvider = tracerProvider;
s_isFileExporterEnabled = ExportersOptions.Exporters.AdbcFile.Equals(exporterName);
}
}
}

/// <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 => s_isFileExporterEnabled;

internal TCLIService.IAsync Client
{
get { return _client ?? throw new InvalidOperationException("connection not open"); }
Expand Down Expand Up @@ -733,6 +782,7 @@ protected override void Dispose(bool disposing)
{
DisposeClient();
_isDisposed = true;
s_tracerProvider?.ForceFlush();
}
base.Dispose(disposing);
}
Expand Down Expand Up @@ -1540,7 +1590,7 @@ public override IArrowArrayStream GetInfo(IReadOnlyList<AdbcInfoCode> codes)
nullCount++;
break;
}
ActivityExtensions.AddTag(activity, tagKey, tagValue);
Tracing.ActivityExtensions.AddTag(activity, tagKey, tagValue);
}

StructType entryType = new StructType(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Apache.Arrow.Adbc\Apache.Arrow.Adbc.csproj" />
<ProjectReference Include="..\..\Telemetry\Traces\Exporters\Apache.Arrow.Adbc.Telemetry.Traces.Exporters.csproj" />
</ItemGroup>
<ItemGroup>
<Content Include="readme.md">
Expand Down
52 changes: 51 additions & 1 deletion csharp/src/Drivers/BigQuery/BigQueryConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Apache.Arrow.Adbc.Extensions;
using Apache.Arrow.Adbc.Telemetry.Traces.Exporters;
using Apache.Arrow.Adbc.Tracing;
using Apache.Arrow.Ipc;
using Apache.Arrow.Types;
using Google.Api.Gax;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Bigquery.v2.Data;
using Google.Cloud.BigQuery.V2;
using OpenTelemetry.Trace;

namespace Apache.Arrow.Adbc.Drivers.BigQuery
{
Expand All @@ -45,6 +47,9 @@ public class BigQueryConnection : TracingConnection, ITokenProtectedResource
bool includePublicProjectIds = false;
const string infoDriverName = "ADBC BigQuery Driver";
const string infoVendorName = "BigQuery";
private static readonly object s_tracerProviderLock = new();
private static TracerProvider? s_tracerProvider;
private static bool s_isFileExporterEnabled;

private readonly string infoDriverArrowVersion = BigQueryUtils.GetAssemblyVersion(typeof(IArrowArray));

Expand All @@ -66,6 +71,8 @@ public BigQueryConnection(IReadOnlyDictionary<string, string> properties) : base
this.properties = properties.ToDictionary(k => k.Key, v => v.Value);
}

TryInitTracerProvider();

// 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();
Expand All @@ -85,6 +92,48 @@ public BigQueryConnection(IReadOnlyDictionary<string, string> properties) : base
}
}

private void TryInitTracerProvider()
{
// Avoid locking if the tracer provider is already set.
if (s_tracerProvider != null)
{
return;
}
// Avoid locking if the exporter option would not activate.
this.properties.TryGetValue(ExportersOptions.Exporter, out string? exporterOption);
ExportersBuilder exportersBuilder = ExportersBuilder.Build(this.ActivitySourceName, addDefaultExporters: true).Build();
if (!exportersBuilder.WouldActivate(exporterOption))
{
return;
}

// Will likely activate the exporter, so we need to lock to ensure thread safety.
lock (s_tracerProviderLock)
{
// Due to race conditions, we need to check again if the tracer provider is already set.
if (s_tracerProvider != null)
{
return;
}

// Activates the exporter specified in the connection property (if exists) or environment variable (if is set).
if (exportersBuilder.TryActivate(exporterOption, out string? exporterName, out TracerProvider? tracerProvider, ExportersOptions.Environment.Exporter) && tracerProvider != null)
{
s_tracerProvider = tracerProvider;
s_isFileExporterEnabled = ExportersOptions.Exporters.AdbcFile.Equals(exporterName);
}
}
}

/// <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 => s_isFileExporterEnabled;

/// <summary>
/// The function to call when updating the token.
/// </summary>
Expand Down Expand Up @@ -470,7 +519,7 @@ internal void UpdateClientToken()

return this.TraceActivity(activity =>
{
activity?.AddConditionalTag(SemanticConventions.Db.Query.Text, sql, BigQueryUtils.IsSafeToTrace());
activity?.AddConditionalTag(SemanticConventions.Db.Query.Text, sql, BigQueryConnection.IsSafeToTrace);

Func<Task<BigQueryResults?>> func = () => Client.ExecuteQueryAsync(sql, parameters ?? Enumerable.Empty<BigQueryParameter>(), queryOptions, resultsOptions);
BigQueryResults? result = ExecuteWithRetriesAsync<BigQueryResults?>(func, activity).GetAwaiter().GetResult();
Expand Down Expand Up @@ -1273,6 +1322,7 @@ public override void Dispose()
Client?.Dispose();
Client = null;
this.httpClient?.Dispose();
s_tracerProvider?.ForceFlush();
}

private static Regex sanitizedInputRegex = new Regex("^[a-zA-Z0-9_-]+");
Expand Down
6 changes: 3 additions & 3 deletions csharp/src/Drivers/BigQuery/BigQueryStatement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ private async Task<QueryResult> ExecuteQueryInternalAsync()
{
QueryOptions queryOptions = ValidateOptions(activity);

activity?.AddConditionalTag(SemanticConventions.Db.Query.Text, SqlQuery, BigQueryUtils.IsSafeToTrace());
activity?.AddConditionalTag(SemanticConventions.Db.Query.Text, SqlQuery, BigQueryConnection.IsSafeToTrace);

BigQueryJob job = await Client.CreateQueryJobAsync(SqlQuery, null, queryOptions);

Expand Down Expand Up @@ -231,7 +231,7 @@ private async Task<UpdateResult> ExecuteUpdateInternalAsync()
activity?.AddBigQueryParameterTag(BigQueryParameters.GetQueryResultsOptionsTimeout, seconds);
}

activity?.AddConditionalTag(SemanticConventions.Db.Query.Text, SqlQuery, BigQueryUtils.IsSafeToTrace());
activity?.AddConditionalTag(SemanticConventions.Db.Query.Text, SqlQuery, 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);
Expand Down Expand Up @@ -344,7 +344,7 @@ private IArrowType GetType(TableFieldSchema field, IArrowType type)
{
// 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, BigQueryConnection.IsSafeToTrace);
BigQueryReadClient.ReadRowsStream readRowsStream = client.ReadRows(new ReadRowsRequest { ReadStream = streamName });
IAsyncEnumerator<ReadRowsResponse> enumerator = readRowsStream.GetResponseStream().GetAsyncEnumerator();

Expand Down
13 changes: 0 additions & 13 deletions csharp/src/Drivers/BigQuery/BigQueryUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,5 @@ public static bool TokenRequiresUpdate(Exception ex)
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;
}
}
}
33 changes: 33 additions & 0 deletions csharp/src/Drivers/BigQuery/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,36 @@ 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 following exporters are supported:

| Exporter | Description |
| --- | --- |
| `otlp` | Exports traces to an OpenTelemetry Collector or directly to an Open Telemetry Line Protocol (OTLP) endpoint. |
| `adbcfile` | Exports traces to rotating files in a folder. |
| `console` | Exports traces to the console output. |
| `none` | Disables trace exporting. |

Note: _The first connection to activate tracing will enable tracing for
any later connections that are created in that process._ (This behavior may change in future implementations.)

#### 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` |
Loading
Loading