Last active
October 14, 2022 14:28
-
-
Save gertjvr/3ee7674f359942d964952dfd80753e00 to your computer and use it in GitHub Desktop.
MT3 + Serilog CorrelationId Enricher.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Runtime.Remoting.Messaging; | |
using System.Threading.Tasks; | |
using MassTransit; | |
using MassTransit.Configurators; | |
using MassTransit.PipeBuilders; | |
using MassTransit.PipeConfigurators; | |
using MassTransit.Pipeline; | |
using Serilog; | |
using Serilog.Configuration; | |
using Serilog.Core; | |
using Serilog.Events; | |
namespace ConsoleApplication2 | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
Log.Logger = new LoggerConfiguration() | |
.MinimumLevel.Debug() | |
.Enrich.WithThreadId() | |
.Enrich.WithCorrelationId("CorrelationId") | |
.WriteTo.Seq("http://seq.localtest.me:5341/") | |
.WriteTo.ColoredConsole() | |
.CreateLogger(); | |
var bus = Bus.Factory.CreateUsingInMemory(cfg => | |
{ | |
cfg.UseSerilog(Log.Logger); | |
cfg.ConfigurePublish(x => x.UseSendExecute(y => y.CorrelationId = Guid.NewGuid())); | |
cfg.ReceiveEndpoint("input", endpoint => | |
{ | |
endpoint.UseSeriLogEnricher(); | |
endpoint.Consumer<CommandConsumer>(); | |
}); | |
}); | |
bus.Start(); | |
bus.Publish(new Command("Hello")); | |
Console.ReadLine(); | |
bus.Stop(); | |
} | |
} | |
public static class CorrelationContext | |
{ | |
public const string IdKey = "CorrelationId"; | |
public static string Id | |
{ | |
get { return IdKey.Get(() => Guid.NewGuid().ToString()); } | |
set { IdKey.Set(value); } | |
} | |
static T Get<T>(this string key, Func<T> defaulter = null) | |
{ | |
var value = (T)CallContext.LogicalGetData(key); | |
if (defaulter != null && EqualityComparer<T>.Default.Equals(value, default(T))) | |
{ | |
value = defaulter(); | |
key.Set(value); | |
} | |
return value; | |
} | |
static void Set<T>(this string key, T value) | |
{ | |
CallContext.LogicalSetData(key, value); | |
} | |
} | |
public static class SerilogConfigurationExtensions | |
{ | |
public static LoggerConfiguration WithCorrelationId(this LoggerEnrichmentConfiguration configuration, string propertyName) | |
{ | |
return configuration.With((ILogEventEnricher)new CorrelationIdEnricher(propertyName)); | |
} | |
} | |
public class CorrelationIdEnricher : ILogEventEnricher | |
{ | |
private readonly string _propertyName; | |
public CorrelationIdEnricher(string propertyName) | |
{ | |
_propertyName = propertyName; | |
} | |
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory factory) | |
{ | |
logEvent.AddOrUpdateProperty(factory.CreateProperty(_propertyName, CorrelationContext.Id)); | |
} | |
} | |
public static class ExampleMiddlewareConfiguratorExtensions | |
{ | |
public static void UseSeriLogEnricher<T>(this IPipeConfigurator<T> configurator) | |
where T : class, PipeContext | |
{ | |
configurator.AddPipeSpecification(new SerilogEnricherSpecification<T>()); | |
} | |
} | |
public class SerilogEnricherSpecification<T> : IPipeSpecification<T> where T : class, PipeContext | |
{ | |
public IEnumerable<ValidationResult> Validate() | |
{ | |
return Enumerable.Empty<ValidationResult>(); | |
} | |
public void Apply(IPipeBuilder<T> builder) | |
{ | |
builder.AddFilter(new SerilogEnricherFilter<T>()); | |
} | |
} | |
public class SerilogEnricherFilter<T> : IFilter<T> | |
where T : class, PipeContext | |
{ | |
public void Probe(ProbeContext context) | |
{ | |
var scope = context.CreateFilterScope("SerilogEnricher"); | |
scope.Add("CorrelationId", CorrelationContext.Id); | |
} | |
public async Task Send(T context, IPipe<T> next) | |
{ | |
var consumeContext = context.GetPayload<ConsumeContext>(); | |
CorrelationContext.Id = consumeContext.CorrelationId.Value.ToString(); | |
await next.Send(context); | |
} | |
} | |
public class Command | |
{ | |
public Command(string say) | |
{ | |
Say = say; | |
} | |
public string Say { get; } | |
} | |
class CommandConsumer : IConsumer<Command> | |
{ | |
public string X { get; set; } | |
public Task Consume(ConsumeContext<Command> context) | |
{ | |
Log.Logger.Debug("Say: {Say}", context.Message.Say); | |
return Task.CompletedTask; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Where is
CallContext
from?