Version

1.1.2

Next

Routing Messages

Previous

Topic Based Routing

Message Correlation


The Envelope class in Jasper tracks several properties for message correlation that you can utilize in your own logging to track how messages are related to one another:

  1. Id - The message identifier. This is unique to a message body and destination
  2. CausationId - The identifier to the parent message -- if any -- whose handling triggered the current message
  3. CorrelationId - Tracks a set of related messages originating from the same original messages. All messages sent from a single IMessageContext will share the same CorrelationId. In the case of messages resulting from the handling of a first message, the resulting messages will share the same CorrelationId as the original Envelope.

All of the above properties are of type Guid, and the values are assigned through a sequential Guid to optimize any database storage of Envelope information.

Customized Message Logging

Jasper internally uses the concept of semantic logging for messaging events with the following interface registered with a default MessageLogger implementation in the underlying IoC container.


public interface IMessageLogger
{
    void LogException(Exception ex, Guid correlationId = default(Guid), string message = "Exception detected:");

    void Sent(Envelope envelope);

    void Received(Envelope envelope);

    void ExecutionStarted(Envelope envelope);

    void ExecutionFinished(Envelope envelope);

    void MessageSucceeded(Envelope envelope);

    void MessageFailed(Envelope envelope, Exception ex);

    void NoHandlerFor(Envelope envelope);

    void NoRoutesFor(Envelope envelope);

    void MovedToErrorQueue(Envelope envelope, Exception ex);

    void DiscardedEnvelope(Envelope envelope);
}

The default implementation just writes formatted string messages to the built in ASP.Net Core ILogger mechanisms. You can of course substitute in your own custom logging to track more structured logging by writing your own custom IMessageLogger. The easiest way to do that is to subclass MessageLogger and just intercept the events you care about as in this example:


public class CustomMessageLogger : MessageLogger
{
    private readonly ILogger<CustomMessageLogger> _logger;

    public CustomMessageLogger(ILoggerFactory factory, IMetrics metrics, ILogger<CustomMessageLogger> logger) :
        base(factory, metrics)
    {
        _logger = logger;
    }

    public override void ExecutionStarted(Envelope envelope)
    {
        base.ExecutionStarted(envelope);
        _logger.LogInformation(
            $"Executing envelope {envelope.Id}, caused by {envelope.CausationId}, correlated by {envelope.CorrelationId}");
    }

    // And any other events you might care about
}

Lastly, you can override the IMessageLogger in the IoC container like so:


public class AppWithCustomLogging : JasperOptions
{
    public AppWithCustomLogging()
    {
        Services.AddSingleton<IMessageLogger, CustomMessageLogger>();
    }
}