Skip to content

Commit

Permalink
Add integration test for DSM manual instrumentation API (#5419)
Browse files Browse the repository at this point in the history
* add integration test for manual API

* change callback return type to array in extractWithDSM

* remove scrubber

Co-authored-by: Andrew Lock <andrew.lock@datadoghq.com>

* remove indexers name

Co-authored-by: Andrew Lock <andrew.lock@datadoghq.com>

* clean csproj

Co-authored-by: Andrew Lock <andrew.lock@datadoghq.com>

* Revert "change callback return type to array in extractWithDSM"

This reverts commit fdeae27.

* handle pathways that are not in string arrays

* remove telemetry setup from test

* add timeout to sample app

* rewrite sample program in a less modern way to please older versions

* remove more modern stuff

* bump timeout

---------

Co-authored-by: Andrew Lock <andrew.lock@datadoghq.com>
  • Loading branch information
vandonr and andrewlock committed Apr 19, 2024
1 parent 0b03553 commit fe100b0
Show file tree
Hide file tree
Showing 8 changed files with 250 additions and 1 deletion.
3 changes: 2 additions & 1 deletion Datadog.Trace.OSX.slnf
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
"tracer\\test\\test-applications\\integrations\\Samples.Couchbase\\Samples.Couchbase.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.Dapper\\Samples.Dapper.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.DataStreams.Kafka\\Samples.DataStreams.Kafka.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.DataStreams.ManualAPI\\Samples.DataStreams.ManualAPI.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.Deduplication\\Samples.Deduplication.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.Elasticsearch.V5\\Samples.Elasticsearch.V5.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.Elasticsearch.V7\\Samples.Elasticsearch.V7.csproj",
Expand All @@ -103,8 +104,8 @@
"tracer\\test\\test-applications\\integrations\\Samples.Microsoft.Data.Sqlite\\Samples.Microsoft.Data.Sqlite.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.MongoDB\\Samples.MongoDB.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.Msmq\\Samples.Msmq.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.MSTestTests\\Samples.MSTestTests.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.MSTestTests2\\Samples.MSTestTests2.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.MSTestTests\\Samples.MSTestTests.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.MySqlConnector\\Samples.MySqlConnector.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.MySql\\Samples.MySql.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.NetActivitySdk\\Samples.NetActivitySdk.csproj",
Expand Down
7 changes: 7 additions & 0 deletions Datadog.Trace.sln
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Datadog.Trace.Manual", "tra
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples.OpenTracing", "tracer\test\test-applications\integrations\Samples.OpenTracing\Samples.OpenTracing.csproj", "{79A63F25-A5F9-441C-8C52-F8033A9F8ABA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Samples.DataStreams.ManualAPI", "tracer\test\test-applications\integrations\Samples.DataStreams.ManualAPI\Samples.DataStreams.ManualAPI.csproj", "{5E290FA1-E87B-4782-B977-EB5FA6C96EFE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -1360,6 +1362,10 @@ Global
{79A63F25-A5F9-441C-8C52-F8033A9F8ABA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{79A63F25-A5F9-441C-8C52-F8033A9F8ABA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{79A63F25-A5F9-441C-8C52-F8033A9F8ABA}.Release|Any CPU.Build.0 = Release|Any CPU
{5E290FA1-E87B-4782-B977-EB5FA6C96EFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5E290FA1-E87B-4782-B977-EB5FA6C96EFE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5E290FA1-E87B-4782-B977-EB5FA6C96EFE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5E290FA1-E87B-4782-B977-EB5FA6C96EFE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -1581,6 +1587,7 @@ Global
{0F1D9FB5-4415-40F1-B7B0-6DD5A3BAB0C4} = {BAF8F246-3645-42AD-B1D0-0F7EAFBAB34A}
{D18A4340-268E-4EAA-8603-38EA998EBDF2} = {9E5F0022-0A50-40BF-AC6A-C3078585ECAB}
{79A63F25-A5F9-441C-8C52-F8033A9F8ABA} = {BAF8F246-3645-42AD-B1D0-0F7EAFBAB34A}
{5E290FA1-E87B-4782-B977-EB5FA6C96EFE} = {BAF8F246-3645-42AD-B1D0-0F7EAFBAB34A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {160A1D00-1F5B-40F8-A155-621B4459D78F}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,17 @@ public void InjectAsBase64String<TCarrier>(PathwayContext context, TCarrier head
}
}
}
else
{
// can happen if the value is coming from a user-provided getter, for instance via SpanContextExtractor
foreach (var headerValue in headerValues)
{
if (!string.IsNullOrEmpty(headerValue))
{
return PathwayContextEncoder.Decode(Convert.FromBase64String(headerValue));
}
}
}

return null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// <copyright file="DataStreamsMonitoringManualApiTest.cs" company="Datadog">
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
// </copyright>

using System.Threading.Tasks;
using Datadog.Trace.Configuration;
using Datadog.Trace.TestHelpers;
using Datadog.Trace.TestHelpers.DataStreamsMonitoring;
using FluentAssertions;
using VerifyXunit;
using Xunit;
using Xunit.Abstractions;

namespace Datadog.Trace.ClrProfiler.IntegrationTests;

[UsesVerify]
public class DataStreamsMonitoringManualApiTest : TestHelper
{
public DataStreamsMonitoringManualApiTest(ITestOutputHelper output)
: base("DataStreams.ManualAPI", output)
{
SetServiceVersion("1.0.0");
}

[SkippableFact]
[Trait("Category", "EndToEnd")]
public async Task ContextPropagation()
{
SetEnvironmentVariable(ConfigurationKeys.DataStreamsMonitoring.Enabled, "1");

using var agent = EnvironmentHelper.GetMockAgent();
using var processResult = await RunSampleAndWaitForExit(agent);

var spans = agent.WaitForSpans(count: 2);
spans.Should().HaveCount(expected: 2);
spans[1].TraceId.Should().Be(spans[0].TraceId); // trace context propagation

var dsPoints = agent.WaitForDataStreamsPoints(statsCount: 2);
// using span verifier to add all the default scrubbers
var settings = VerifyHelper.GetSpanVerifierSettings();
settings.AddDataStreamsScrubber();
await Verifier.Verify(MockDataStreamsPayload.Normalize(dsPoints), settings)
.UseFileName($"{nameof(DataStreamsMonitoringManualApiTest)}.{nameof(ContextPropagation)}")
.DisableRequireUniquePrefix();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
{
Env: integration_tests,
Service: Samples.DataStreams.ManualAPI,
TracerVersion: <snip>,
Lang: dotnet,
Stats: [
{
Start: 1661520120000000000,
Duration: 10000000000,
Stats: [
{
EdgeTags: [
direction:out,
topic:_queue,
type:ConcurrentQueue
],
Hash: 4846659945844582174,
PathwayLatency: /w==,
EdgeLatency: /w==,
PayloadSize: /w==,
TimestampType: current
},
{
EdgeTags: [
direction:in,
topic:_queue,
type:ConcurrentQueue
],
Hash: 11038489780599490290,
ParentHash: 4846659945844582174,
PathwayLatency: /w==,
EdgeLatency: /w==,
PayloadSize: /w==,
TimestampType: current
}
]
},
{
Start: 1661520120000000000,
Duration: 10000000000,
Stats: [
{
EdgeTags: [
direction:out,
topic:_queue,
type:ConcurrentQueue
],
Hash: 4846659945844582174,
PathwayLatency: /w==,
EdgeLatency: /w==,
PayloadSize: /w==,
TimestampType: origin
},
{
EdgeTags: [
direction:in,
topic:_queue,
type:ConcurrentQueue
],
Hash: 11038489780599490290,
ParentHash: 4846659945844582174,
PathwayLatency: /w==,
EdgeLatency: /w==,
PayloadSize: /w==,
TimestampType: origin
}
]
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Datadog.Trace;

namespace Samples.DataStreams.ManualAPI;

public class Program
{
private static ConcurrentQueue<string> _queue = new();

private static async Task Main(string[] args)
{
var writing = Send("my message");
var reading = Receive();

// wait up to 20 second for threads
await Task.WhenAny(Task.WhenAll(reading, writing), Task.Delay(TimeSpan.FromSeconds(value: 20)));
}

private static async Task Send(string message)
{
using var scope = Tracer.Instance.StartActive("Samples.DataStreams.ManualAPI.Send");

await Task.Delay(millisecondsDelay: 100);

Console.WriteLine("Sending one message to the queue...");
var sb = new StringBuilder();
var injector = new SpanContextInjector();
injector.InjectIncludingDsm(sb, (b, k, v) => b.Append($"{k}:{v};"), scope.Span.Context, "ConcurrentQueue", nameof(_queue));
sb.Append(message);
_queue.Enqueue(sb.ToString());
Console.WriteLine("message sent");
}

private static async Task<string> Receive()
{
Console.WriteLine("Receiving one message from the queue...");
string result;
while (!_queue.TryDequeue(out result))
{
await Task.Delay(millisecondsDelay: 100);
Console.WriteLine("Retrying to receive");
}

var headers = Parse(result, out var content);
Console.WriteLine($"Parsed {headers.Count} headers");
var extractor = new SpanContextExtractor();
var extractedContext = extractor.ExtractIncludingDsm(
headers,
// complicated getter because we need to return an empty array if no result
(d, k) =>
{
if (d.TryGetValue(k, out var val))
{
return [val];
}
return [];
},
"ConcurrentQueue",
nameof(_queue));
using var scope = Tracer.Instance.StartActive("Samples.DataStreams.ManualAPI.Receive", new SpanCreationSettings { Parent = extractedContext });

Console.WriteLine("Done");
return content;
}

/// <returns>headers and message</returns>
private static Dictionary<string, string> Parse(string raw, out string msg)
{
var content = raw.Split(separator: ';');
var headers = content
.Take(content.Length - 1) // SkipLast() is unavailable in older versions that we are testing on
.Select(s => s.Split(separator: ':'))
.ToDictionary(a => a[0], a => a[1]);
msg = content.Last();
return headers;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"profiles": {
"Samples.DataStreams.ManualAPI": {
"commandName": "Project",
"environmentVariables": {
"COR_ENABLE_PROFILING": "1",
"COR_PROFILER": "{846F5F1C-F9AE-4B07-969E-05C26BC060D8}",
"COR_PROFILER_PATH": "$(SolutionDir)shared\\bin\\monitoring-home\\win-$(Platform)\\Datadog.Trace.ClrProfiler.Native.dll",

"CORECLR_ENABLE_PROFILING": "1",
"CORECLR_PROFILER": "{846F5F1C-F9AE-4B07-969E-05C26BC060D8}",
"CORECLR_PROFILER_PATH": "$(SolutionDir)shared\\bin\\monitoring-home\\win-$(Platform)\\Datadog.Trace.ClrProfiler.Native.dll",

"DD_DOTNET_TRACER_HOME": "$(SolutionDir)shared\\bin\\monitoring-home",
"DD_VERSION": "1.0.0",

"DD_DATA_STREAMS_ENABLED": "1"
},

"nativeDebugging": false
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Datadog.Trace.Manual\Datadog.Trace.Manual.csproj" />
</ItemGroup>
</Project>

0 comments on commit fe100b0

Please sign in to comment.