Skip to content

Commit 2a3e560

Browse files
authored
Merge pull request #7590 from Particular/nsb10-logging-datadog
Add Datadog Logging sample for NServiceBus 10
2 parents 5a5576e + 7397248 commit 2a3e560

File tree

8 files changed

+260
-0
lines changed

8 files changed

+260
-0
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
Microsoft Visual Studio Solution File, Format Version 12.00
2+
# Visual Studio Version 17
3+
VisualStudioVersion = 17.8.34408.163
4+
MinimumVisualStudioVersion = 15.0.26730.12
5+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Endpoint", "Endpoint\Endpoint.csproj", "{FF5BEF96-88BA-470D-975A-4EF710EE2B7A}"
6+
EndProject
7+
Global
8+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
9+
Debug|Any CPU = Debug|Any CPU
10+
EndGlobalSection
11+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
12+
{FF5BEF96-88BA-470D-975A-4EF710EE2B7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
13+
{FF5BEF96-88BA-470D-975A-4EF710EE2B7A}.Debug|Any CPU.Build.0 = Debug|Any CPU
14+
EndGlobalSection
15+
GlobalSection(SolutionProperties) = preSolution
16+
HideSolutionNode = FALSE
17+
EndGlobalSection
18+
EndGlobal
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using NServiceBus;
4+
using NServiceBus.Configuration.AdvancedExtensibility;
5+
using StatsdClient;
6+
7+
public static class DataDogMetrics
8+
{
9+
static string endpointName;
10+
11+
public static void Setup(EndpointConfiguration endpointConfiguration)
12+
{
13+
var metricOptions = endpointConfiguration.EnableMetrics();
14+
endpointName = endpointConfiguration.GetSettings().EndpointName();
15+
16+
#region setup-datadog-client
17+
18+
var dogstatsdConfig = new StatsdConfig
19+
{
20+
StatsdServerName = "127.0.0.1",
21+
StatsdPort = 8125
22+
}; //Datadog agent default address, port
23+
24+
DogStatsd.Configure(dogstatsdConfig);
25+
26+
#endregion
27+
28+
#region datadog-enable-nsb-metrics
29+
30+
metricOptions.RegisterObservers(register: probeContext =>
31+
{
32+
foreach (var duration in probeContext.Durations)
33+
{
34+
if (!nameMapping.ContainsKey(duration.Name))
35+
{
36+
continue;
37+
}
38+
duration.Register((ref DurationEvent @event) =>
39+
{
40+
var statName = ComposeStatName(duration.Name);
41+
var tags = ComposeTags(@event.MessageType);
42+
DogStatsd.Timer(statName, @event.Duration.TotalMilliseconds, tags: tags);
43+
});
44+
}
45+
46+
foreach (var signal in probeContext.Signals)
47+
{
48+
if (!nameMapping.ContainsKey(signal.Name))
49+
{
50+
continue;
51+
}
52+
signal.Register((ref SignalEvent @event) =>
53+
{
54+
var statName = ComposeStatName(signal.Name);
55+
var tags = ComposeTags(@event.MessageType);
56+
DogStatsd.Increment(statName, tags: tags);
57+
});
58+
}
59+
});
60+
61+
#endregion
62+
}
63+
64+
static string ComposeStatName(string eventName)
65+
{
66+
nameMapping.TryGetValue(eventName, out var mappedName);
67+
return mappedName;
68+
}
69+
70+
static string[] ComposeTags(string messageType)
71+
{
72+
var tags = new List<string>
73+
{
74+
"endpoint:" + endpointName
75+
};
76+
77+
if (!string.IsNullOrEmpty(messageType))
78+
{
79+
var fullMessageName = messageType.Split(',')[0];
80+
tags.Add("messagetype_fullname:" + fullMessageName);
81+
82+
var shortMessageName = fullMessageName.Split('.').Last();
83+
tags.Add("messagetype_name:" + shortMessageName);
84+
}
85+
86+
return tags.ToArray();
87+
}
88+
89+
static readonly Dictionary<string, string> nameMapping = new()
90+
{
91+
{"# of msgs successfully processed / sec", "nservicebus.processed"},
92+
{"# of msgs pulled from the input queue /sec", "nservicebus.fetched"},
93+
{"# of msgs failures / sec", "nservicebus.failed"},
94+
{"Critical Time", "nservicebus.critical_time"},
95+
{"Processing Time", "nservicebus.processing_time"},
96+
{"Retries", "nservicebus.retries"},
97+
};
98+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<TargetFramework>net10.0</TargetFramework>
4+
<OutputType>Exe</OutputType>
5+
<LangVersion>preview</LangVersion>
6+
</PropertyGroup>
7+
<ItemGroup>
8+
<PackageReference Include="DogStatsD-CSharp-Client" Version="8.*" />
9+
<PackageReference Include="NServiceBus" Version="10.0.0-alpha.1" />
10+
<PackageReference Include="NServiceBus.Metrics" Version="6.0.0-alpha.1" />
11+
<PackageReference Include="NServiceBus.Extensions.Hosting" Version="4.0.0-alpha.1" />
12+
</ItemGroup>
13+
</Project>
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using System;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
using NServiceBus;
5+
6+
// Simulates busy (almost no delay) / quiet time in a sine wave
7+
class LoadSimulator(IMessageSession messageSession, TimeSpan minimumDelay, TimeSpan idleDuration)
8+
{
9+
CancellationTokenSource tokenSource = new();
10+
TimeSpan idleDuration = TimeSpan.FromTicks(idleDuration.Ticks / 2);
11+
Task fork;
12+
13+
public Task Start()
14+
{
15+
fork = Loop();
16+
return Task.CompletedTask;
17+
}
18+
19+
async Task Loop()
20+
{
21+
try
22+
{
23+
while (true)
24+
{
25+
await Work();
26+
var delay = NextDelay();
27+
await Task.Delay(delay, tokenSource.Token);
28+
}
29+
}
30+
catch (OperationCanceledException)
31+
{
32+
}
33+
}
34+
35+
int index;
36+
37+
TimeSpan NextDelay()
38+
{
39+
var angleInRadians = Math.PI / 180.0 * ++index;
40+
var delay = TimeSpan.FromMilliseconds(idleDuration.TotalMilliseconds * Math.Sin(angleInRadians));
41+
delay += idleDuration;
42+
delay += minimumDelay;
43+
return delay;
44+
}
45+
46+
Task Work() => messageSession.SendLocal(new SomeCommand());
47+
48+
public Task Stop()
49+
{
50+
tokenSource.Cancel();
51+
return fork;
52+
}
53+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using System;
2+
using Microsoft.Extensions.DependencyInjection;
3+
using NServiceBus;
4+
using Microsoft.Extensions.Hosting;
5+
6+
const string EndpointName = "Samples.Metrics.Tracing.Endpoint";
7+
8+
Console.Title = EndpointName;
9+
10+
var host = Host.CreateDefaultBuilder(args)
11+
.UseConsoleLifetime()
12+
.UseNServiceBus(_ =>
13+
{
14+
var endpointConfiguration = new EndpointConfiguration(EndpointName);
15+
16+
endpointConfiguration.UseSerialization<SystemJsonSerializer>();
17+
endpointConfiguration.UseTransport<LearningTransport>();
18+
19+
DataDogMetrics.Setup(endpointConfiguration);
20+
21+
return endpointConfiguration;
22+
})
23+
.Build();
24+
25+
await host.StartAsync();
26+
27+
var endpointInstance = host.Services.GetRequiredService<IMessageSession>();
28+
29+
var simulator = new LoadSimulator(endpointInstance, TimeSpan.Zero, TimeSpan.FromSeconds(10));
30+
await simulator.Start();
31+
32+
try
33+
{
34+
Console.WriteLine("Endpoint started.");
35+
Console.WriteLine("Press [ENTER] to send additional messages.");
36+
Console.WriteLine("Press [Q] to quit.");
37+
38+
while (true)
39+
{
40+
var key = Console.ReadKey(true);
41+
if (key.Key == ConsoleKey.Q)
42+
{
43+
break;
44+
}
45+
46+
await endpointInstance.SendLocal(new SomeCommand());
47+
}
48+
}
49+
finally
50+
{
51+
await simulator.Stop();
52+
await host.StopAsync();
53+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
using NServiceBus;
2+
3+
class SomeCommand : ICommand;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using NServiceBus;
4+
using NServiceBus.Logging;
5+
6+
class SomeCommandHandler : IHandleMessages<SomeCommand>
7+
{
8+
static ILog log = LogManager.GetLogger<SomeCommandHandler>();
9+
static Random random = new Random();
10+
11+
public async Task Handle(SomeCommand message, IMessageHandlerContext context)
12+
{
13+
await Task.Delay(random.Next(50, 250), context.CancellationToken);
14+
15+
if (random.Next(10) <= 1)
16+
{
17+
throw new Exception("Random 10% chaos!");
18+
}
19+
20+
log.Info("Hello from SomeCommandHandler");
21+
}
22+
}

samples/logging/datadog/Core_10/prerelease.txt

Whitespace-only changes.

0 commit comments

Comments
 (0)