Skip to content

Commit a237e71

Browse files
committed
chore: fix DSM example in AWS deployment
1 parent d388844 commit a237e71

30 files changed

Lines changed: 301 additions & 71 deletions

mise.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,3 +280,19 @@ docker compose --profile load-test run --rm load-simulator
280280
docker compose --profile load-test down -v
281281
"""
282282

283+
[tasks."aws:load-test:smoke"]
284+
description = "Run load tests against AWS deployment"
285+
dir = "e2e"
286+
depends = ["ui-test:install"]
287+
run = """
288+
BASE_URL=$(aws cloudformation describe-stacks \
289+
--stack-name "StickerlandiaSharedResources-${ENV:-dev}" \
290+
--query "Stacks[0].Outputs[?OutputKey=='BaseUrl'].OutputValue" \
291+
--output text)
292+
DEPLOYMENT_HOST_URL=$(aws cloudformation describe-stacks \
293+
--stack-name "StickerlandiaSharedResources-${ENV:-dev}" \
294+
--query "Stacks[0].Outputs[?OutputKey=='BaseUrl'].OutputValue" \
295+
--output text)
296+
echo "Running tests against: $BASE_URL"
297+
BASE_URL=$BASE_URL DEPLOYMENT_HOST_URL=$DEPLOYMENT_HOST_URL npx playwright test
298+
"""

print-service/src/Stickerlandia.PrintService.AWS/EventBridgeEventPublisher.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public class EventBridgeEventPublisher(
3232
ILogger<EventBridgeEventPublisher> logger,
3333
IAmazonEventBridge client,
3434
IOptions<AwsConfiguration> awsConfiguration,
35-
DatadogTransactionTracker transactionTracker) : IPrintServiceEventPublisher
35+
IDatadogTransactionTracker transactionTracker) : IPrintServiceEventPublisher
3636
{
3737
[Channel("printJobs.queued.v1")]
3838
[PublishOperation(typeof(PrintJobQueuedEvent))]
@@ -151,7 +151,7 @@ internal async Task PublishCloudEventAsync(CloudEvent cloudEvent)
151151
}
152152
else
153153
{
154-
Log.GenericWarning(logger, "Failure publishing event", null);
154+
Log.GenericWarning(logger, "DSM injection skipped for EventBridge: no active Datadog scope", null);
155155
activity?.SetTag("dsm.injection_skipped", "no active scope");
156156
}
157157

print-service/src/Stickerlandia.PrintService.AWS/ServiceExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public static IServiceCollection AddAwsAdapters(this IServiceCollection services
6363
services.AddSingleton<IPrintServiceEventPublisher, EventBridgeEventPublisher>();
6464

6565
services.AddHttpClient();
66-
services.AddSingleton<DatadogTransactionTracker>();
66+
services.AddSingleton<IDatadogTransactionTracker, DatadogTransactionTracker>();
6767

6868
return services;
6969
}

print-service/src/Stickerlandia.PrintService.Agnostic/KafkaEventPublisher.cs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using CloudNative.CloudEvents;
88
using CloudNative.CloudEvents.SystemTextJson;
99
using Confluent.Kafka;
10+
using Datadog.Trace;
1011
using Microsoft.Extensions.Logging;
1112
using Saunter.Attributes;
1213
using Stickerlandia.PrintService.Core;
@@ -17,7 +18,7 @@
1718

1819
namespace Stickerlandia.PrintService.Agnostic;
1920

20-
public class KafkaEventPublisher(ProducerConfig config, ILogger<KafkaEventPublisher> logger, DatadogTransactionTracker transactionTracker) : IPrintServiceEventPublisher
21+
public class KafkaEventPublisher(ProducerConfig config, ILogger<KafkaEventPublisher> logger, IDatadogTransactionTracker transactionTracker) : IPrintServiceEventPublisher
2122
{
2223
[Channel("printJobs.queued.v1")]
2324
[PublishOperation(typeof(PrintJobQueuedEvent))]
@@ -127,13 +128,33 @@ private async Task Publish<T>(CloudEvent cloudEvent)
127128
var formatter = new JsonEventFormatter<T>();
128129
var data = formatter.EncodeStructuredModeMessage(cloudEvent, out _);
129130

131+
var message = new Message<string, string>
132+
{
133+
Key = cloudEvent.Id!,
134+
Value = Encoding.UTF8.GetString(data.Span)
135+
};
136+
137+
if (Tracer.Instance.ActiveScope is not null)
138+
{
139+
message.Headers = new Headers();
140+
new SpanContextInjector().InjectIncludingDsm(
141+
message.Headers,
142+
(headers, key, value) => headers.Add(key, Encoding.UTF8.GetBytes(value)),
143+
Tracer.Instance.ActiveScope.Span.Context,
144+
"kafka",
145+
cloudEvent.Type!);
146+
}
147+
else
148+
{
149+
Log.GenericWarning(logger, "DSM injection skipped for Kafka: no active Datadog scope", null);
150+
activity?.SetTag("dsm.injection_skipped", "no active scope");
151+
}
152+
130153
using var producer = new ProducerBuilder<string, string>(config).Build();
131154

132155
try
133156
{
134-
var deliveryReport = await producer.ProduceAsync(cloudEvent.Type,
135-
new Message<string, string> { Key = cloudEvent.Id!, Value = Encoding.UTF8.GetString(data.Span) },
136-
default);
157+
var deliveryReport = await producer.ProduceAsync(cloudEvent.Type, message, default);
137158

138159
if (deliveryReport.Status == PersistenceStatus.PossiblyPersisted)
139160
{

print-service/src/Stickerlandia.PrintService.Agnostic/ServiceExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ public static IServiceCollection AddKafkaMessaging(this IServiceCollection servi
124124
services.AddSingleton(consumerConfig);
125125

126126
services.AddHttpClient();
127-
services.AddSingleton<DatadogTransactionTracker>();
127+
services.AddSingleton<IDatadogTransactionTracker, DatadogTransactionTracker>();
128128

129129
// Register event publisher as singleton
130130
services.AddSingleton<IPrintServiceEventPublisher, KafkaEventPublisher>();

print-service/src/Stickerlandia.PrintService.Client/Services/PrintJobPollingService.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,18 +132,20 @@ private async Task ProcessJobAsync(PrintJobDto job)
132132
{
133133
_logger.LogInformation("Processing job {JobId} for sticker {StickerId}", job.PrintJobId, job.StickerId);
134134

135-
// Extract DSM context first so the consumer span wraps all processing work
135+
// Extract DSM context and activate the Datadog scope before starting the OTel activity,
136+
// so the activity is parented to the DSM-extracted context rather than the ambient poll span.
136137
var extractedContext = new SpanContextExtractor().ExtractIncludingDsm(
137138
job,
138139
GetHeader,
139140
"queue",
140141
"print_queue");
141142

142-
using var activity = PrintClientInstrumentation.StartProcessJobActivity(job);
143143
using var scope = Tracer.Instance.StartActive(
144144
"process print.job",
145145
new SpanCreationSettings { Parent = extractedContext });
146146

147+
using var activity = PrintClientInstrumentation.StartProcessJobActivity(job);
148+
147149
await _transactionTracker.TrackTransactionAsync(job.PrintJobId, "print-received");
148150
var stopwatch = Stopwatch.StartNew();
149151

print-service/src/Stickerlandia.PrintService.Client/Stickerlandia.PrintService.Client.csproj

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,17 @@
3636
</PackageReference>
3737
</ItemGroup>
3838

39+
<ItemGroup>
40+
<_ContentIncludedByDefault Remove="print-jobs\2026-03-24\415ea02f-bc10-4ef6-89e7-2f769009f87e.json" />
41+
<_ContentIncludedByDefault Remove="print-jobs\2026-03-24\506dccea-4c39-4e96-95bf-6858e30d043e.json" />
42+
<_ContentIncludedByDefault Remove="print-jobs\2026-03-24\5270f1d5-9e9a-45b7-91dc-9eb65e4b23cb.json" />
43+
<_ContentIncludedByDefault Remove="print-jobs\2026-03-24\6868ccee-3ddf-4c36-813a-e51c130865c3.json" />
44+
<_ContentIncludedByDefault Remove="print-jobs\2026-03-24\82a74161-0eca-4fe1-a3d5-bb3fd86f2afc.json" />
45+
<_ContentIncludedByDefault Remove="print-jobs\2026-03-24\c1f03d74-0c92-429f-807c-e8e86dffa326.json" />
46+
<_ContentIncludedByDefault Remove="print-jobs\2026-03-24\c64e482c-9200-4406-8501-56a17bc8ac7d.json" />
47+
<_ContentIncludedByDefault Remove="print-jobs\2026-03-24\c72499f4-ce72-4169-be33-7b3eb918f614.json" />
48+
<_ContentIncludedByDefault Remove="print-jobs\2026-03-24\d8e56c15-6e4c-4cb6-b9e4-3a277c0725b0.json" />
49+
<_ContentIncludedByDefault Remove="print-jobs\2026-03-24\e03b614b-b23d-4ebb-a747-bfdaee9f67ee.json" />
50+
</ItemGroup>
51+
3952
</Project>

print-service/src/Stickerlandia.PrintService.Client/Telemetry/DatadogTransactionTracker.cs

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ namespace Stickerlandia.PrintService.Client.Telemetry;
1515

1616
internal class DatadogTransactionTracker
1717
{
18-
private readonly string _apiKey;
1918
private readonly string _service;
2019
private readonly string _environment;
20+
private readonly string _ddApiKey;
2121
private readonly Uri _pipelineStatsEndpoint;
2222

2323
private readonly IHttpClientFactory _httpClientFactory;
@@ -28,24 +28,17 @@ public DatadogTransactionTracker(IHttpClientFactory httpClientFactory,
2828
ILogger<DatadogTransactionTracker> logger)
2929
{
3030
ArgumentNullException.ThrowIfNull(configuration);
31-
31+
3232
_httpClientFactory = httpClientFactory;
3333
_logger = logger;
34-
_apiKey = configuration["DD_API_KEY"] ?? string.Empty;
3534
_service = configuration["DD_SERVICE"] ?? "print-service";
3635
_environment = configuration["DD_ENV"] ?? "local";
37-
var ddSite = configuration["DD_SITE"] ?? "datadoghq.com";
38-
_pipelineStatsEndpoint = new Uri($"https://trace.agent.{ddSite}/api/v0.1/pipeline_stats");
36+
_ddApiKey = configuration["DD_API_KEY"] ?? "";
37+
_pipelineStatsEndpoint = new Uri($"https://trace.agent.{configuration["DD_SITE"] ?? "datadoghq.com"}/api/v0.1/pipeline_stats");
3938
}
4039

4140
internal async Task TrackTransactionAsync(string transactionId, string checkpoint)
4241
{
43-
if (string.IsNullOrEmpty(_apiKey))
44-
{
45-
_logger.LogWarning("DD_API_KEY is not configured. Skipping transaction tracking for transaction {TransactionId} at checkpoint {Checkpoint}.", transactionId, checkpoint);
46-
return;
47-
}
48-
4942
try
5043
{
5144
if (Activity.Current is not null)
@@ -77,10 +70,10 @@ internal async Task TrackTransactionAsync(string transactionId, string checkpoin
7770

7871
using var client = _httpClientFactory.CreateClient();
7972
using var request = new HttpRequestMessage(HttpMethod.Post, _pipelineStatsEndpoint);
80-
request.Headers.Add("DD-API-KEY", _apiKey);
8173
request.Content = new ByteArrayContent(compressed);
8274
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
8375
request.Content.Headers.ContentEncoding.Add("gzip");
76+
request.Content.Headers.Add("DD-API-KEY", _ddApiKey);
8477

8578
var response = await client.SendAsync(request);
8679
response.EnsureSuccessStatusCode();
@@ -93,7 +86,7 @@ internal async Task TrackTransactionAsync(string transactionId, string checkpoin
9386
catch (Exception ex)
9487
#pragma warning restore CA1031
9588
{
96-
_logger.LogWarning(ex, "Failed to track transaction {TransactionId} at checkpoint {Checkpoint}. Exception: {ExceptionMessage}", transactionId, checkpoint);
89+
_logger.LogWarning(ex, "Failed to track transaction {TransactionId} at checkpoint {Checkpoint}", transactionId, checkpoint);
9790
}
9891
}
9992

print-service/src/Stickerlandia.PrintService.Core/Observability/DatadogTransactionTracker.cs

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@
1313

1414
namespace Stickerlandia.PrintService.Core.Observability;
1515

16-
public class DatadogTransactionTracker
16+
public class DatadogTransactionTracker : IDatadogTransactionTracker
1717
{
18-
private readonly string _apiKey;
1918
private readonly string _service;
2019
private readonly string _environment;
20+
private readonly string _ddApiKey;
2121
private readonly Uri _pipelineStatsEndpoint;
2222

2323
private readonly IHttpClientFactory _httpClientFactory;
@@ -28,24 +28,17 @@ public DatadogTransactionTracker(IHttpClientFactory httpClientFactory,
2828
ILogger<DatadogTransactionTracker> logger)
2929
{
3030
ArgumentNullException.ThrowIfNull(configuration);
31-
31+
3232
_httpClientFactory = httpClientFactory;
3333
_logger = logger;
34-
_apiKey = configuration["DD_API_KEY"] ?? string.Empty;
3534
_service = configuration["DD_SERVICE"] ?? "print-service";
3635
_environment = configuration["DD_ENV"] ?? "local";
37-
var ddSite = configuration["DD_SITE"] ?? "datadoghq.com";
38-
_pipelineStatsEndpoint = new Uri($"https://trace.agent.{ddSite}/api/v0.1/pipeline_stats");
36+
_ddApiKey = configuration["DD_API_KEY"] ?? "";
37+
_pipelineStatsEndpoint = new Uri($"https://trace.agent.{configuration["DD_SITE"] ?? "datadoghq.com"}/api/v0.1/pipeline_stats");
3938
}
4039

4140
public async Task TrackTransactionAsync(string transactionId, string checkpoint)
4241
{
43-
if (string.IsNullOrEmpty(_apiKey))
44-
{
45-
Log.TransactionTrackingSkipped(_logger);
46-
return;
47-
}
48-
4942
try
5043
{
5144
if (Activity.Current is not null)
@@ -77,10 +70,10 @@ public async Task TrackTransactionAsync(string transactionId, string checkpoint)
7770

7871
using var client = _httpClientFactory.CreateClient();
7972
using var request = new HttpRequestMessage(HttpMethod.Post, _pipelineStatsEndpoint);
80-
request.Headers.Add("DD-API-KEY", _apiKey);
8173
request.Content = new ByteArrayContent(compressed);
8274
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
8375
request.Content.Headers.ContentEncoding.Add("gzip");
76+
request.Content.Headers.Add("DD-API-KEY", _ddApiKey);
8477

8578
var response = await client.SendAsync(request);
8679
response.EnsureSuccessStatusCode();
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
2+
// This product includes software developed at Datadog (https://www.datadoghq.com/).
3+
// Copyright 2026 Datadog, Inc.
4+
5+
namespace Stickerlandia.PrintService.Core.Observability;
6+
7+
public interface IDatadogTransactionTracker
8+
{
9+
Task TrackTransactionAsync(string transactionId, string checkpoint);
10+
}

0 commit comments

Comments
 (0)