Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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 @@ -9,6 +9,8 @@ OpenTelemetry.Instrumentation.SqlClient.SqlClientTraceInstrumentationOptions.Rec
OpenTelemetry.Instrumentation.SqlClient.SqlClientTraceInstrumentationOptions.SetDbStatementForText.get -> bool
OpenTelemetry.Instrumentation.SqlClient.SqlClientTraceInstrumentationOptions.SetDbStatementForText.set -> void
OpenTelemetry.Instrumentation.SqlClient.SqlClientTraceInstrumentationOptions.SqlClientTraceInstrumentationOptions() -> void
OpenTelemetry.Instrumentation.SqlClient.SqlClientTraceInstrumentationOptions.ContextPropagationLevel.get -> string!
OpenTelemetry.Instrumentation.SqlClient.SqlClientTraceInstrumentationOptions.ContextPropagationLevel.set -> void
OpenTelemetry.Metrics.SqlClientMeterProviderBuilderExtensions
OpenTelemetry.Trace.TracerProviderBuilderExtensions
static OpenTelemetry.Metrics.SqlClientMeterProviderBuilderExtensions.AddSqlClientInstrumentation(this OpenTelemetry.Metrics.MeterProviderBuilder! builder) -> OpenTelemetry.Metrics.MeterProviderBuilder!
Expand Down
8 changes: 8 additions & 0 deletions src/OpenTelemetry.Instrumentation.SqlClient/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@
the new conventions.
([#2811](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/2811))

* Added `ContextPropagationLevel` option to propagate trace context to
SQL Server database.
([#2709](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/2709))

Valid options:
* `trace`: Propagate traceparent info to SQL Server database (see [SET CONTEXT_INFO](https://learn.microsoft.com/en-us/sql/t-sql/statements/set-context-info-transact-sql?view=sql-server-ver16))
* `disabled`: Default value

## 1.12.0-beta.1

Released 2025-May-06
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Diagnostics.CodeAnalysis;
#endif
using System.Globalization;
using System.Text;
using OpenTelemetry.Trace;

namespace OpenTelemetry.Instrumentation.SqlClient.Implementation;
Expand All @@ -26,6 +27,9 @@ internal sealed class SqlClientDiagnosticListener : ListenerHandler
public const string SqlDataWriteCommandError = "System.Data.SqlClient.WriteCommandError";
public const string SqlMicrosoftWriteCommandError = "Microsoft.Data.SqlClient.WriteCommandError";

private const string ContextInfoParameterName = "@opentelemetry_traceparent";
private const string SetContextSql = $"set context_info {ContextInfoParameterName}";

private readonly PropertyFetcher<object> commandFetcher = new("Command");
private readonly PropertyFetcher<object> connectionFetcher = new("Connection");
private readonly PropertyFetcher<string> dataSourceFetcher = new("DataSource");
Expand Down Expand Up @@ -64,6 +68,13 @@ public override void OnEventWritten(string name, object? payload)
return;
}

// skip if this is an injected query
if (options.ContextPropagationLevel == SqlClientTraceInstrumentationOptions.ContextPropagationLevelTrace &&
command is IDbCommand { CommandType: CommandType.Text, CommandText: SetContextSql })
{
return;
}

_ = this.connectionFetcher.TryFetch(command, out var connection);
_ = this.databaseFetcher.TryFetch(connection, out var databaseName);
_ = this.dataSourceFetcher.TryFetch(connection, out var dataSource);
Expand All @@ -82,6 +93,25 @@ public override void OnEventWritten(string name, object? payload)
return;
}

if (options.ContextPropagationLevel == SqlClientTraceInstrumentationOptions.ContextPropagationLevelTrace &&
command is IDbCommand { CommandType: CommandType.Text, Connection.State: ConnectionState.Open } iDbCommand)
{
var setContextCommand = iDbCommand.Connection.CreateCommand();
setContextCommand.CommandText = SetContextSql;
setContextCommand.CommandType = CommandType.Text;
var parameter = setContextCommand.CreateParameter();
parameter.ParameterName = ContextInfoParameterName;

var tracedflags = (activity.ActivityTraceFlags & ActivityTraceFlags.Recorded) != 0 ? "01" : "00";
var traceparent = $"00-{activity.TraceId.ToHexString()}-{activity.SpanId.ToHexString()}-{tracedflags}";

parameter.DbType = DbType.Binary;
parameter.Value = Encoding.UTF8.GetBytes(traceparent);
setContextCommand.Parameters.Add(parameter);

setContextCommand.ExecuteNonQuery();
}

if (activity.IsAllDataRequested)
{
try
Expand Down Expand Up @@ -168,6 +198,15 @@ public override void OnEventWritten(string name, object? payload)
case SqlDataAfterExecuteCommand:
case SqlMicrosoftAfterExecuteCommand:
{
_ = this.commandFetcher.TryFetch(payload, out var command);

// skip if this is an injected query
if (options.ContextPropagationLevel == SqlClientTraceInstrumentationOptions.ContextPropagationLevelTrace &&
command is IDbCommand { CommandType: CommandType.Text, CommandText: SetContextSql })
{
return;
}

if (activity == null)
{
SqlClientInstrumentationEventSource.Log.NullActivity(name);
Expand All @@ -189,6 +228,15 @@ public override void OnEventWritten(string name, object? payload)
case SqlDataWriteCommandError:
case SqlMicrosoftWriteCommandError:
{
_ = this.commandFetcher.TryFetch(payload, out var command);

// skip if this is an injected query
if (options.ContextPropagationLevel == SqlClientTraceInstrumentationOptions.ContextPropagationLevelTrace &&
command is IDbCommand { CommandType: CommandType.Text, CommandText: SetContextSql })
{
return;
}

if (activity == null)
{
SqlClientInstrumentationEventSource.Log.NullActivity(name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ namespace OpenTelemetry.Instrumentation.SqlClient;
/// </remarks>
public class SqlClientTraceInstrumentationOptions
{
/// <summary>
/// Flag to send traceparent information to SQL Server.
/// </summary>
internal const string ContextPropagationLevelTrace = "trace";

/// <summary>
/// Flag to disable sending trace information to SQL Server.
/// </summary>
internal const string ContextPropagationDisabled = "disabled";

/// <summary>
/// Initializes a new instance of the <see cref="SqlClientTraceInstrumentationOptions"/> class.
/// </summary>
Expand All @@ -30,6 +40,7 @@ internal SqlClientTraceInstrumentationOptions(IConfiguration configuration)
var databaseSemanticConvention = GetSemanticConventionOptIn(configuration);
this.EmitOldAttributes = databaseSemanticConvention.HasFlag(DatabaseSemanticConvention.Old);
this.EmitNewAttributes = databaseSemanticConvention.HasFlag(DatabaseSemanticConvention.New);
this.ContextPropagationLevel = ContextPropagationDisabled;
}

/// <summary>
Expand Down Expand Up @@ -63,6 +74,17 @@ internal SqlClientTraceInstrumentationOptions(IConfiguration configuration)
/// </remarks>
public bool SetDbStatementForText { get; set; }

/// <summary>
/// Gets or sets a value indicating whether to send trace information to SQL Server database.
/// Optional values:
/// <see langword="trace"/>:
/// Send traceparent information to SQL Server.
/// <see langword="disabled"/>:
/// Disable sending trace information to SQL Server.
/// Default value: <see landword="disabled"/>.
/// </summary>
public string ContextPropagationLevel { get; set; }

/// <summary>
/// Gets or sets an action to enrich an <see cref="Activity"/> with the
/// raw <c>SqlCommand</c> object.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public void SuccessfulCommandTest(
{
options.SetDbStatementForText = captureTextCommandContent;
options.RecordException = recordException;
options.ContextPropagationLevel = SqlClientTraceInstrumentationOptions.ContextPropagationLevelTrace;
})
.Build();

Expand Down
Loading