Skip to content

Tag Enrichers

Named tags can be given at every append call, but some tags belong to the surroundings of the append rather than to the code that does it. Chronicle resolves the tags of every event in one step, used by every append path: single appends, AppendMany, and units of work.

For each event the tags are resolved in this order and merged without duplicates:

  1. The static [Tag] tags of the event type.
  2. The tags already on the event, including those given at the call site.
  3. The built-in enrichers: the ambient scope and [Audience] properties.
  4. Your own IEventTagEnricher implementations.

For a unit of work this happens when the event is added, not when the unit commits.

Implement IEventTagEnricher. Enrichers are discovered automatically, resolved through dependency injection, and all of them run for every event. They must be pure, synchronous and additive: they can add tags, never remove or change them.

using Cratis.Chronicle;
public class EnrichersTenantRegionTagEnricher(IRegionLookup regions) : IEventTagEnricher
{
public IEnumerable<NamedTag> GetTags(EventTagContext context)
{
if (context.EventSequenceId != Cratis.Chronicle.EventSequences.EventSequenceId.Outbox)
{
return [];
}
return [new NamedTag(new TagName("region"), regions.For(context.EventSourceId.Value))];
}
}
public interface IRegionLookup
{
string For(string eventSourceId);
}

View C# snippet source on GitHub

The EventTagContext gives you the event store name, the event sequence, the event source id, the event type, the event itself and the tags it already has.

EventTags.Scope(name, value) stamps a tag on every event appended inside the scope, without the appending code having to know. The scope flows with the async execution context and is closed by disposing it.

using Cratis.Chronicle;
using Cratis.Chronicle.Events;
[EventType]
public record EnrichersOrderPlaced(string OrderId);
public static class EnrichersAmbientScope
{
public static async Task Place(IEventStore eventStore)
{
// Every event appended inside the scope gets region=eu, without the append code knowing.
using var scope = EventTags.Scope("region", "eu");
await eventStore.EventLog.Append("order-1", new EnrichersOrderPlaced("order-1"));
}
}

View C# snippet source on GitHub

Nested scopes add up. EventTags.Audience(value) is the same with the audience name; see Audiences for where it applies.