diff --git a/tracer/src/Datadog.Trace.Trimming/build/Datadog.Trace.Trimming.xml b/tracer/src/Datadog.Trace.Trimming/build/Datadog.Trace.Trimming.xml
index b8fd04046b8a..8712f01fda36 100644
--- a/tracer/src/Datadog.Trace.Trimming/build/Datadog.Trace.Trimming.xml
+++ b/tracer/src/Datadog.Trace.Trimming/build/Datadog.Trace.Trimming.xml
@@ -204,6 +204,7 @@
+
@@ -211,6 +212,7 @@
+
diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AdoNet/DbScopeFactory.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AdoNet/DbScopeFactory.cs
index 686ef8c4f549..730d3628a34b 100644
--- a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AdoNet/DbScopeFactory.cs
+++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AdoNet/DbScopeFactory.cs
@@ -107,7 +107,7 @@ internal static class DbScopeFactory
}
// try context injection only after comment injection, so that if it fails, we still have service level propagation
- var traceParentInjectedInContext = DatabaseMonitoringPropagator.PropagateDataViaContext(tracer.Settings.DbmPropagationMode, integrationId, command.Connection, scope.Span);
+ var traceParentInjectedInContext = DatabaseMonitoringPropagator.PropagateDataViaContext(tracer.Settings.DbmPropagationMode, integrationId, command, scope.Span);
if (traceParentInjectedInComment || traceParentInjectedInContext)
{
tags.DbmTraceInjected = "true";
diff --git a/tracer/src/Datadog.Trace/DatabaseMonitoring/DatabaseMonitoringPropagator.cs b/tracer/src/Datadog.Trace/DatabaseMonitoring/DatabaseMonitoringPropagator.cs
index b90f4532a06f..f79eeaa0a244 100644
--- a/tracer/src/Datadog.Trace/DatabaseMonitoring/DatabaseMonitoringPropagator.cs
+++ b/tracer/src/Datadog.Trace/DatabaseMonitoring/DatabaseMonitoringPropagator.cs
@@ -113,21 +113,37 @@ internal static string PropagateDataViaComment(DbmPropagationLevel propagationSt
/// Currently only working for MSSQL (uses an instruction that is specific to it)
///
/// True if the traceparent information was set
- internal static bool PropagateDataViaContext(DbmPropagationLevel propagationLevel, IntegrationId integrationId, IDbConnection? connection, Span span)
+ internal static bool PropagateDataViaContext(DbmPropagationLevel propagationLevel, IntegrationId integrationId, IDbCommand command, Span span)
{
- if (propagationLevel != DbmPropagationLevel.Full || integrationId != IntegrationId.SqlClient || connection == null)
+ if (propagationLevel != DbmPropagationLevel.Full || integrationId != IntegrationId.SqlClient)
{
return false;
}
+ // NOTE: For Npgsql command.Connection throws NotSupportedException for NpgsqlDataSourceCommand (v7.0+)
+ // Since the feature isn't available for Npgsql we avoid this due to the integrationId check above
+ if (command.Connection == null)
+ {
+ return false;
+ }
+
+ if (command.Connection.State != ConnectionState.Open)
+ {
+ Log.Debug("PropagateDataViaContext did not have an Open connection, so it could not propagate Span data for DBM. Connection state was {ConnectionState}", command.Connection.State);
+
+ 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())
+ using (var injectionCommand = command.Connection.CreateCommand())
{
+ // if there is a Transaction we need to copy it or our ExecuteNonQuery will throw
+ injectionCommand.Transaction = command.Transaction;
injectionCommand.CommandText = SetContextCommand;
var parameter = injectionCommand.CreateParameter();
diff --git a/tracer/test/Datadog.Trace.ClrProfiler.IntegrationTests/AdoNet/MicrosoftDataSqliteTests.cs b/tracer/test/Datadog.Trace.ClrProfiler.IntegrationTests/AdoNet/MicrosoftDataSqliteTests.cs
index a47218938b01..902d23edc0bd 100644
--- a/tracer/test/Datadog.Trace.ClrProfiler.IntegrationTests/AdoNet/MicrosoftDataSqliteTests.cs
+++ b/tracer/test/Datadog.Trace.ClrProfiler.IntegrationTests/AdoNet/MicrosoftDataSqliteTests.cs
@@ -8,14 +8,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Datadog.Trace.Configuration;
using Datadog.Trace.TestHelpers;
+using VerifyXunit;
using Xunit;
using Xunit.Abstractions;
namespace Datadog.Trace.ClrProfiler.IntegrationTests.AdoNet
{
+ [UsesVerify]
public class MicrosoftDataSqliteTests : TracingIntegrationTest
{
public MicrosoftDataSqliteTests(ITestOutputHelper output)
@@ -47,7 +50,7 @@ public async Task SubmitsTraces(string packageVersion, string metadataSchemaVers
return;
}
#endif
- const int expectedSpanCount = 91;
+ const int expectedSpanCount = 105;
const string dbType = "sqlite";
const string expectedOperationName = dbType + ".query";
@@ -64,6 +67,22 @@ public async Task SubmitsTraces(string packageVersion, string metadataSchemaVers
ValidateIntegrationSpans(spans, metadataSchemaVersion, expectedServiceName: clientSpanServiceName, isExternalSpan);
telemetry.AssertIntegrationEnabled(IntegrationId.Sqlite);
+
+ var settings = VerifyHelper.GetSpanVerifierSettings();
+ settings.AddRegexScrubber(new Regex("Sqlite-Test-[a-zA-Z0-9]{32}"), "System-Data-SqlClient-Test-GUID");
+ settings.AddSimpleScrubber("out.host: localhost", "out.host: sqlserver");
+ settings.AddSimpleScrubber("out.host: (localdb)\\MSSQLLocalDB", "out.host: sqlserver");
+ settings.AddSimpleScrubber("out.host: sqledge_arm64", "out.host: sqlserver");
+ settings.AddSimpleScrubber("peer.service: localhost", "peer.service: sqlserver");
+ settings.AddSimpleScrubber("peer.service: (localdb)\\MSSQLLocalDB", "peer.service: sqlserver");
+ settings.AddSimpleScrubber("peer.service: sqledge_arm64", "peer.service: sqlserver");
+ settings.AddRegexScrubber(new Regex("dd.instrumentation.time_ms: \\d+.\\d+"), "dd.instrumentation.time_ms: 123.456");
+
+ var fileName = nameof(MicrosoftDataSqliteTests);
+
+ await VerifyHelper.VerifySpans(spans, settings)
+ .DisableRequireUniquePrefix()
+ .UseFileName($"{fileName}.Schema{metadataSchemaVersion.ToUpper()}");
}
[SkippableFact]
diff --git a/tracer/test/Datadog.Trace.ClrProfiler.IntegrationTests/AdoNet/SystemDataSqliteTests.cs b/tracer/test/Datadog.Trace.ClrProfiler.IntegrationTests/AdoNet/SystemDataSqliteTests.cs
index 17a30b649fdc..f76299450619 100644
--- a/tracer/test/Datadog.Trace.ClrProfiler.IntegrationTests/AdoNet/SystemDataSqliteTests.cs
+++ b/tracer/test/Datadog.Trace.ClrProfiler.IntegrationTests/AdoNet/SystemDataSqliteTests.cs
@@ -4,14 +4,17 @@
//
using System.Linq;
+using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Datadog.Trace.Configuration;
using Datadog.Trace.TestHelpers;
+using VerifyXunit;
using Xunit;
using Xunit.Abstractions;
namespace Datadog.Trace.ClrProfiler.IntegrationTests.AdoNet
{
+ [UsesVerify]
public class SystemDataSqliteTests : TracingIntegrationTest
{
public SystemDataSqliteTests(ITestOutputHelper output)
@@ -56,7 +59,7 @@ public async Task IntegrationDisabled()
private async Task RunTest(string metadataSchemaVersion)
{
- const int expectedSpanCount = 91;
+ const int expectedSpanCount = 105;
const string dbType = "sqlite";
const string expectedOperationName = dbType + ".query";
@@ -72,6 +75,22 @@ private async Task RunTest(string metadataSchemaVersion)
Assert.Equal(expectedSpanCount, spans.Count);
ValidateIntegrationSpans(spans, metadataSchemaVersion, expectedServiceName: clientSpanServiceName, isExternalSpan);
telemetry.AssertIntegrationEnabled(IntegrationId.Sqlite);
+
+ var settings = VerifyHelper.GetSpanVerifierSettings();
+ settings.AddRegexScrubber(new Regex("SQLite-Test-[a-zA-Z0-9]{32}"), "System-Data-SqlClient-Test-GUID");
+ settings.AddSimpleScrubber("out.host: localhost", "out.host: sqlserver");
+ settings.AddSimpleScrubber("out.host: (localdb)\\MSSQLLocalDB", "out.host: sqlserver");
+ settings.AddSimpleScrubber("out.host: sqledge_arm64", "out.host: sqlserver");
+ settings.AddSimpleScrubber("peer.service: localhost", "peer.service: sqlserver");
+ settings.AddSimpleScrubber("peer.service: (localdb)\\MSSQLLocalDB", "peer.service: sqlserver");
+ settings.AddSimpleScrubber("peer.service: sqledge_arm64", "peer.service: sqlserver");
+ settings.AddRegexScrubber(new Regex("dd.instrumentation.time_ms: \\d+.\\d+"), "dd.instrumentation.time_ms: 123.456");
+
+ var fileName = nameof(SystemDataSqliteTests);
+
+ await VerifyHelper.VerifySpans(spans, settings)
+ .DisableRequireUniquePrefix()
+ .UseFileName($"{fileName}.Schema{metadataSchemaVersion.ToUpper()}");
}
}
}
diff --git a/tracer/test/Datadog.Trace.Tests/DatabaseMonitoring/DatabaseMonitoringPropagatorTests.cs b/tracer/test/Datadog.Trace.Tests/DatabaseMonitoring/DatabaseMonitoringPropagatorTests.cs
index 0449a4bcf9fd..d9eeeb53a72e 100644
--- a/tracer/test/Datadog.Trace.Tests/DatabaseMonitoring/DatabaseMonitoringPropagatorTests.cs
+++ b/tracer/test/Datadog.Trace.Tests/DatabaseMonitoring/DatabaseMonitoringPropagatorTests.cs
@@ -144,10 +144,12 @@ public void ExpectedContextSet(string propagationMode, string integration, int s
var commandMock = new Mock();
var parameterMock = new Mock();
connectionMock.Setup(c => c.CreateCommand()).Returns(commandMock.Object);
+ connectionMock.SetupGet(c => c.State).Returns(ConnectionState.Open);
commandMock.SetupSet(c => c.CommandText = It.IsAny())
.Callback(value => sql = value);
commandMock.Setup(c => c.CreateParameter()).Returns(parameterMock.Object);
commandMock.SetupGet(c => c.Parameters).Returns(Mock.Of());
+ commandMock.SetupGet(c => c.Connection).Returns(connectionMock.Object);
parameterMock.SetupSet(p => p.Value = It.IsAny())
.Callback