Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[sqlclient] Make SqlClientInstrumentation a singleton #2305

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
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 @@ -34,18 +34,22 @@ internal sealed class SqlClientDiagnosticListener : ListenerHandler
private readonly PropertyFetcher<object> commandTextFetcher = new("CommandText");
private readonly PropertyFetcher<Exception> exceptionFetcher = new("Exception");
private readonly PropertyFetcher<int> exceptionNumberFetcher = new("Number");
private readonly SqlClientTraceInstrumentationOptions options;

public SqlClientDiagnosticListener(string sourceName, SqlClientTraceInstrumentationOptions? options)
public SqlClientDiagnosticListener(string sourceName)
: base(sourceName)
{
this.options = options ?? new SqlClientTraceInstrumentationOptions();
}

public override bool SupportsNullActivity => true;

public override void OnEventWritten(string name, object? payload)
{
if (SqlClientInstrumentation.TracingHandles == 0)
{
return;
}

var options = SqlClientInstrumentation.TracingOptions;
var activity = Activity.Current;
switch (name)
{
Expand All @@ -63,7 +67,7 @@ public override void OnEventWritten(string name, object? payload)
_ = this.databaseFetcher.TryFetch(connection, out var databaseName);
_ = this.dataSourceFetcher.TryFetch(connection, out var dataSource);

var startTags = SqlActivitySourceHelper.GetTagListFromConnectionInfo(dataSource, databaseName, this.options, out var activityName);
var startTags = SqlActivitySourceHelper.GetTagListFromConnectionInfo(dataSource, databaseName, options, out var activityName);
activity = SqlActivitySourceHelper.ActivitySource.StartActivity(
activityName,
ActivityKind.Client,
Expand All @@ -80,7 +84,7 @@ public override void OnEventWritten(string name, object? payload)
{
try
{
if (this.options.Filter?.Invoke(command) == false)
if (options.Filter?.Invoke(command) == false)
{
SqlClientInstrumentationEventSource.Log.CommandIsFilteredOut(activity.OperationName);
activity.IsAllDataRequested = false;
Expand All @@ -103,12 +107,12 @@ public override void OnEventWritten(string name, object? payload)
switch (commandType)
{
case CommandType.StoredProcedure:
if (this.options.EmitOldAttributes)
if (options.EmitOldAttributes)
{
activity.SetTag(SemanticConventions.AttributeDbStatement, commandText);
}

if (this.options.EmitNewAttributes)
if (options.EmitNewAttributes)
{
activity.SetTag(SemanticConventions.AttributeDbOperationName, "EXECUTE");
activity.SetTag(SemanticConventions.AttributeDbCollectionName, commandText);
Expand All @@ -118,14 +122,14 @@ public override void OnEventWritten(string name, object? payload)
break;

case CommandType.Text:
if (this.options.SetDbStatementForText)
if (options.SetDbStatementForText)
{
if (this.options.EmitOldAttributes)
if (options.EmitOldAttributes)
{
activity.SetTag(SemanticConventions.AttributeDbStatement, commandText);
}

if (this.options.EmitNewAttributes)
if (options.EmitNewAttributes)
{
activity.SetTag(SemanticConventions.AttributeDbQueryText, commandText);
}
Expand All @@ -142,7 +146,7 @@ public override void OnEventWritten(string name, object? payload)

try
{
this.options.Enrich?.Invoke(activity, "OnCustom", command);
options.Enrich?.Invoke(activity, "OnCustom", command);
}
catch (Exception ex)
{
Expand Down Expand Up @@ -199,7 +203,7 @@ public override void OnEventWritten(string name, object? payload)

activity.SetStatus(ActivityStatusCode.Error, exception.Message);

if (this.options.RecordException)
if (options.RecordException)
{
activity.RecordException(exception);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,9 @@ internal sealed class SqlEventSourceListener : EventListener
internal const int BeginExecuteEventId = 1;
internal const int EndExecuteEventId = 2;

private readonly SqlClientTraceInstrumentationOptions options;
private EventSource? adoNetEventSource;
private EventSource? mdsEventSource;

public SqlEventSourceListener(SqlClientTraceInstrumentationOptions? options = null)
{
this.options = options ?? new SqlClientTraceInstrumentationOptions();
}

public override void Dispose()
{
if (this.adoNetEventSource != null)
Expand Down Expand Up @@ -106,6 +100,13 @@ private void OnBeginExecute(EventWrittenEventArgs eventData)
(https://github.com/dotnet/SqlClient/blob/f4568ce68da21db3fe88c0e72e1287368aaa1dc8/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs#L6641)
*/

if (SqlClientInstrumentation.TracingHandles == 0)
{
return;
}

var options = SqlClientInstrumentation.TracingOptions;

if (eventData.Payload.Count < 4)
{
SqlClientInstrumentationEventSource.Log.InvalidPayload(nameof(SqlEventSourceListener), nameof(this.OnBeginExecute));
Expand All @@ -114,7 +115,7 @@ private void OnBeginExecute(EventWrittenEventArgs eventData)

var dataSource = (string)eventData.Payload[1];
var databaseName = (string)eventData.Payload[2];
var startTags = SqlActivitySourceHelper.GetTagListFromConnectionInfo(dataSource, databaseName, this.options, out var activityName);
var startTags = SqlActivitySourceHelper.GetTagListFromConnectionInfo(dataSource, databaseName, options, out var activityName);
var activity = SqlActivitySourceHelper.ActivitySource.StartActivity(
activityName,
ActivityKind.Client,
Expand All @@ -130,14 +131,14 @@ private void OnBeginExecute(EventWrittenEventArgs eventData)
if (activity.IsAllDataRequested)
{
var commandText = (string)eventData.Payload[3];
if (!string.IsNullOrEmpty(commandText) && this.options.SetDbStatementForText)
if (!string.IsNullOrEmpty(commandText) && options.SetDbStatementForText)
{
if (this.options.EmitOldAttributes)
if (options.EmitOldAttributes)
{
activity.SetTag(SemanticConventions.AttributeDbStatement, commandText);
}

if (this.options.EmitNewAttributes)
if (options.EmitNewAttributes)
{
activity.SetTag(SemanticConventions.AttributeDbQueryText, commandText);
}
Expand All @@ -154,6 +155,11 @@ private void OnEndExecute(EventWrittenEventArgs eventData)
[2] -> SqlExceptionNumber
*/

if (SqlClientInstrumentation.TracingHandles == 0)
{
return;
}

if (eventData.Payload.Count < 3)
{
SqlClientInstrumentationEventSource.Log.InvalidPayload(nameof(SqlEventSourceListener), nameof(this.OnEndExecute));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,18 @@ namespace OpenTelemetry.Instrumentation.SqlClient;
/// <summary>
/// SqlClient instrumentation.
/// </summary>
#if NET
[RequiresUnreferencedCode(SqlClientTrimmingUnsupportedMessage)]
#endif
internal sealed class SqlClientInstrumentation : IDisposable
{
public static readonly SqlClientInstrumentation Instance = new SqlClientInstrumentation();

internal const string SqlClientDiagnosticListenerName = "SqlClientDiagnosticListener";
#if NET
internal const string SqlClientTrimmingUnsupportedMessage = "Trimming is not yet supported with SqlClient instrumentation.";
#endif
internal static int TracingHandles;
#if NETFRAMEWORK
private readonly SqlEventSourceListener sqlEventSourceListener;
#else
Expand All @@ -39,25 +45,24 @@ internal sealed class SqlClientInstrumentation : IDisposable
/// <summary>
/// Initializes a new instance of the <see cref="SqlClientInstrumentation"/> class.
/// </summary>
/// <param name="options">Configuration options for sql instrumentation.</param>
#if NET
[RequiresUnreferencedCode(SqlClientTrimmingUnsupportedMessage)]
#endif
public SqlClientInstrumentation(
SqlClientTraceInstrumentationOptions? options = null)
private SqlClientInstrumentation()
{
#if NETFRAMEWORK
this.sqlEventSourceListener = new SqlEventSourceListener(options);
this.sqlEventSourceListener = new SqlEventSourceListener();
#else
this.diagnosticSourceSubscriber = new DiagnosticSourceSubscriber(
name => new SqlClientDiagnosticListener(name, options),
name => new SqlClientDiagnosticListener(name),
listener => listener.Name == SqlClientDiagnosticListenerName,
this.isEnabled,
SqlClientInstrumentationEventSource.Log.UnknownErrorProcessingEvent);
this.diagnosticSourceSubscriber.Subscribe();
#endif
}

public static SqlClientTraceInstrumentationOptions TracingOptions { get; set; } = new SqlClientTraceInstrumentationOptions();

public static IDisposable AddTracingHandle() => new TracingHandle();

/// <inheritdoc/>
public void Dispose()
{
Expand All @@ -67,4 +72,26 @@ public void Dispose()
this.diagnosticSourceSubscriber?.Dispose();
#endif
}

#if NET
[RequiresUnreferencedCode(SqlClientTrimmingUnsupportedMessage)]
#endif
private sealed class TracingHandle : IDisposable
{
private bool disposed;

public TracingHandle()
{
Interlocked.Increment(ref TracingHandles);
}

public void Dispose()
{
if (!this.disposed)
{
Interlocked.Decrement(ref TracingHandles);
this.disposed = true;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ public static TracerProviderBuilder AddSqlClientInstrumentation(
#if NET
[RequiresUnreferencedCode(SqlClientInstrumentation.SqlClientTrimmingUnsupportedMessage)]
#endif

public static TracerProviderBuilder AddSqlClientInstrumentation(
this TracerProviderBuilder builder,
string? name,
Expand All @@ -70,8 +69,8 @@ public static TracerProviderBuilder AddSqlClientInstrumentation(
builder.AddInstrumentation(sp =>
{
var sqlOptions = sp.GetRequiredService<IOptionsMonitor<SqlClientTraceInstrumentationOptions>>().Get(name);

return new SqlClientInstrumentation(sqlOptions);
SqlClientInstrumentation.TracingOptions = sqlOptions;
return SqlClientInstrumentation.AddTracingHandle();
});

builder.AddSource(SqlActivitySourceHelper.ActivitySourceName);
Expand Down
Loading