-
Notifications
You must be signed in to change notification settings - Fork 164
DSM Full propagation mode for SQL Server #5859
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
Changes from 24 commits
8c00441
b18a8ac
80af8b5
7c1ef10
f8cb802
08ece1e
87a2142
094dfed
c87e6d2
b292664
e5c6d9c
419a54f
111e373
c7fe369
50aafe2
afe8145
2eecd39
03bef4f
98e3690
af3efd8
3645905
9c0d70e
bc85d08
77d32dc
d7429c6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,10 +4,14 @@ | |
| // </copyright> | ||
|
|
||
| using System; | ||
| using System.Data; | ||
| using Datadog.Trace.Configuration; | ||
| using Datadog.Trace.Logging; | ||
| using Datadog.Trace.Propagators; | ||
| using Datadog.Trace.Tagging; | ||
| using Datadog.Trace.Util; | ||
| using Datadog.Trace.VendoredMicrosoftCode.System.Buffers.Binary; | ||
| using Datadog.Trace.Vendors.Serilog.Events; | ||
|
|
||
| #nullable enable | ||
|
|
||
|
|
@@ -22,8 +26,12 @@ internal static class DatabaseMonitoringPropagator | |
| private const string SqlCommentVersion = "ddpv"; | ||
| private const string SqlCommentEnv = "dde"; | ||
| internal const string DbmPrefix = $"/*{SqlCommentSpanService}='"; | ||
| private const string ContextInfoParameterName = "@dd_trace_context"; | ||
| internal const string SetContextCommand = $"set context_info {ContextInfoParameterName}"; | ||
|
|
||
| internal static string PropagateSpanData(DbmPropagationLevel propagationStyle, string configuredServiceName, string? dbName, string? outhost, Span span, IntegrationId integrationId, out bool traceParentInjected) | ||
| private static readonly IDatadogLogger Log = DatadogLogging.GetLoggerFor(typeof(DatabaseMonitoringPropagator)); | ||
|
|
||
| internal static string PropagateDataViaComment(DbmPropagationLevel propagationStyle, string configuredServiceName, string? dbName, string? outhost, Span span, IntegrationId integrationId, out bool traceParentInjected) | ||
| { | ||
| traceParentInjected = false; | ||
|
|
||
|
|
@@ -73,5 +81,68 @@ internal static string PropagateSpanData(DbmPropagationLevel propagationStyle, s | |
|
|
||
| return string.Empty; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Uses a sql instruction to set a context for the current connection, bearing the span ID and trace ID. | ||
| /// This is meant to circumvent cache invalidation issues that occur when those values are injected in comment. | ||
| /// Currently only working for MSSQL (uses an instruction that is specific to it) | ||
| /// </summary> | ||
| /// <returns>True if the traceparent information was set</returns> | ||
| internal static bool PropagateDataViaContext(DbmPropagationLevel propagationLevel, IntegrationId integrationId, IDbConnection? connection, Span span) | ||
| { | ||
| if (propagationLevel != DbmPropagationLevel.Full || integrationId != IntegrationId.SqlClient || connection == null) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| var stopwatch = System.Diagnostics.Stopwatch.StartNew(); | ||
|
|
||
| const byte version = 0; // version can have a maximum value of 15 in the current format | ||
| var sampled = SamplingPriorityValues.IsKeep(span.Context.TraceContext.GetOrMakeSamplingDecision()); | ||
| var contextValue = BuildContextValue(version, sampled, span.SpanId, span.TraceId128); | ||
|
|
||
| using (var injectionCommand = connection.CreateCommand()) | ||
| { | ||
| injectionCommand.CommandText = SetContextCommand; | ||
|
|
||
| var parameter = injectionCommand.CreateParameter(); | ||
| parameter.ParameterName = ContextInfoParameterName; | ||
| parameter.Value = contextValue; | ||
| parameter.DbType = DbType.Binary; | ||
| injectionCommand.Parameters.Add(parameter); | ||
|
|
||
| injectionCommand.ExecuteNonQuery(); | ||
|
|
||
| if (Log.IsEnabled(LogEventLevel.Debug)) | ||
| { | ||
| // avoid building the string representation in the general case where debug is disabled | ||
| Log.Debug("Span data for DBM propagated for {Integration} via context_info with value {ContextValue} (propagation level: {PropagationLevel}", integrationId, HexConverter.ToString(contextValue), propagationLevel); | ||
| } | ||
| } | ||
|
|
||
| // Since sending the query to the DB can be a bit long, we register the time it took for transparency. | ||
| // Not using _dd because we want the customers to be able to see that tag. | ||
| span.SetMetric("dd.instrumentation.time_ms", stopwatch.Elapsed.TotalMilliseconds); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm yeah it's a one off, I'm actually not aware of any existing instrumentation that would be long enough that we'd want to document how long it takes. |
||
|
|
||
| return true; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Writes the given info in a byte array with the following format: | ||
| /// 4 bits: protocol version, 3 bits: reserved, 1 bit: sampling decision, 64 bits: spanID, 128 bits: traceID | ||
| /// </summary> | ||
| private static byte[] BuildContextValue(byte version, bool isSampled, ulong spanId, TraceId traceId) | ||
| { | ||
| var sampled = isSampled ? 1 : 0; | ||
| var versionAndSampling = (byte)(((version << 4) & 0b1111_0000) | (sampled & 0b0000_0001)); | ||
| var contextBytes = new byte[1 + sizeof(ulong) + TraceId.Size]; | ||
|
|
||
| var span = new VendoredMicrosoftCode.System.Span<byte>(contextBytes) { [0] = versionAndSampling }; | ||
| BinaryPrimitives.WriteUInt64BigEndian(span.Slice(1), spanId); | ||
| BinaryPrimitives.WriteUInt64BigEndian(span.Slice(1 + sizeof(ulong)), traceId.Upper); | ||
| BinaryPrimitives.WriteUInt64BigEndian(span.Slice(1 + sizeof(ulong) + sizeof(ulong)), traceId.Lower); | ||
|
|
||
| return contextBytes; | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.