Appending with Tags
Chronicle lets you associate tags with appended events. Tags are stored as event metadata and can be used for categorization, filtering, and concurrency scoping.
Built-in metadata tags
Section titled “Built-in metadata tags”Chronicle maintains built-in metadata tags for event identity and stream routing:
EventSourceTypeEventSourceIdEventStreamTypeEventStreamId
You can add custom tags in addition to these built-in tags. For the full list and behavior, see Event Metadata Tags.
Custom tags
Section titled “Custom tags”Custom tags are simple strings that you provide when appending. They are merged with any static tags defined on the event type.
Append with tags
Section titled “Append with tags”using Cratis.Chronicle.Events;
[EventType]public record TaggedOrderPlaced(string CustomerId, decimal Total);
public class TaggedCheckoutService(IEventLog eventLog){ public Task<AppendResult> PlaceOrder(OrderId orderId, string customerId, decimal total) { return eventLog.Append( orderId, new TaggedOrderPlaced(customerId, total), tags: ["checkout", "priority"]); }}import io.cratis.chronicle.IEventStoreimport io.cratis.chronicle.eventSequences.AppendOptionsimport io.cratis.chronicle.eventSequences.AppendResultimport io.cratis.chronicle.events.EventType
@EventTypedata class TaggedOrderPlaced(val customerId: String, val total: Double)
class TaggedCheckoutService(private val eventStore: IEventStore) { suspend fun placeOrder(orderId: String, customerId: String, total: Double): AppendResult = eventStore.eventLog.append( orderId, TaggedOrderPlaced(customerId, total), AppendOptions(tags = listOf("checkout", "priority")) )}import io.cratis.chronicle.IEventStore;import io.cratis.chronicle.events.EventType;import io.cratis.chronicle.java.AppendOptionsBuilder;import io.cratis.chronicle.java.BlockingEventStore;
@EventTyperecord TaggedOrderPlaced(String customerId, double total) {}
class TaggedCheckoutService { private final BlockingEventStore eventStore;
TaggedCheckoutService(IEventStore eventStore) { this.eventStore = new BlockingEventStore(eventStore); }
void placeOrder(String orderId, String customerId, double total) { var options = new AppendOptionsBuilder().tag("checkout").tag("priority").build(); eventStore.getEventLog().append(orderId, new TaggedOrderPlaced(customerId, total), options); }}defmodule MyApp.Events.TaggedOrderPlaced do defstruct [:customer_id, :total]end
defmodule MyApp.TaggedCheckoutService do alias MyApp.Events.TaggedOrderPlaced
def place_order(order_id, customer_id, total) do Chronicle.append( order_id, %TaggedOrderPlaced{customer_id: customer_id, total: total}, tags: ["checkout", "priority"] ) endendimport { eventType, IEventStore } from '@cratis/chronicle';
@eventType()class TaggedOrderPlaced { constructor(readonly customerId: string, readonly total: number) {}}
class TaggedCheckoutService { constructor(private readonly store: IEventStore) {}
async placeOrder(orderId: string, customerId: string, total: number): Promise<void> { await this.store.eventLog.append( orderId, new TaggedOrderPlaced(customerId, total), { tags: ['checkout', 'priority'] }); }}AppendMany with tags
Section titled “AppendMany with tags”AppendMany applies the provided tags to each event in the batch.
using Cratis.Chronicle.EventSequences;using Cratis.Chronicle.Events;
public readonly record struct TaggedAccountId(string Value){ public static implicit operator EventSourceId(TaggedAccountId id) => new(id.Value);}
[EventType]public record TaggedMoneyWithdrawn(decimal Amount);
[EventType]public record TaggedMoneyDeposited(decimal Amount);
public class TaggedTransferService(IEventLog eventLog){ public Task<AppendManyResult> Transfer(TaggedAccountId fromAccount, TaggedAccountId toAccount, decimal amount) { var events = new[] { new EventForEventSourceId(fromAccount, new TaggedMoneyWithdrawn(amount)), new EventForEventSourceId(toAccount, new TaggedMoneyDeposited(amount)) };
return eventLog.AppendMany(events, tags: ["transfer", "audit"]); }}import io.cratis.chronicle.IEventStoreimport io.cratis.chronicle.eventSequences.AppendResultimport io.cratis.chronicle.eventSequences.EventForEventSourceIdimport io.cratis.chronicle.events.EventType
@EventTypedata class TaggedMoneyWithdrawn(val amount: Double)
@EventTypedata class TaggedMoneyDeposited(val amount: Double)
class TaggedTransferService(private val eventStore: IEventStore) { suspend fun transfer(fromAccount: String, toAccount: String, amount: Double): List<AppendResult> { val events = listOf( EventForEventSourceId(fromAccount, TaggedMoneyWithdrawn(amount), tags = listOf("transfer", "audit")), EventForEventSourceId(toAccount, TaggedMoneyDeposited(amount), tags = listOf("transfer", "audit")) )
return eventStore.eventLog.appendMany(events) }}import io.cratis.chronicle.IEventStore;import io.cratis.chronicle.eventSequences.AppendResult;import io.cratis.chronicle.eventSequences.EventForEventSourceId;import io.cratis.chronicle.events.EventType;import io.cratis.chronicle.java.BlockingEventStore;
import java.util.List;
@EventTyperecord TaggedMoneyWithdrawn(double amount) {}
@EventTyperecord TaggedMoneyDeposited(double amount) {}
class TaggedTransferService { private final BlockingEventStore eventStore;
TaggedTransferService(IEventStore eventStore) { this.eventStore = new BlockingEventStore(eventStore); }
List<AppendResult> transfer(String fromAccount, String toAccount, double amount) { var events = List.of( new EventForEventSourceId(fromAccount, new TaggedMoneyWithdrawn(amount), null, null, null, List.of("transfer", "audit")), new EventForEventSourceId(toAccount, new TaggedMoneyDeposited(amount), null, null, null, List.of("transfer", "audit")));
return eventStore.getEventLog().appendMany(events); }}defmodule MyApp.Events.TaggedMoneyWithdrawn do defstruct [:amount]end
defmodule MyApp.Events.TaggedWithdrawalFeeCharged do defstruct [:amount]end
defmodule MyApp.TaggedWithdrawalService do alias MyApp.Events.TaggedMoneyWithdrawn alias MyApp.Events.TaggedWithdrawalFeeCharged
def withdraw(account_id, amount, fee) do Chronicle.append_many( account_id, [ %TaggedMoneyWithdrawn{amount: amount}, %TaggedWithdrawalFeeCharged{amount: fee} ], tags: ["withdrawal", "audit"] ) endendimport { eventType, EventForEventSourceId, IEventStore } from '@cratis/chronicle';
@eventType()class TaggedMoneyWithdrawn { constructor(readonly amount: number) {}}
@eventType()class TaggedMoneyDeposited { constructor(readonly amount: number) {}}
class TaggedTransferService { constructor(private readonly store: IEventStore) {}
async transfer(fromAccountId: string, toAccountId: string, amount: number): Promise<void> { const events: EventForEventSourceId[] = [ { eventSourceId: fromAccountId, event: new TaggedMoneyWithdrawn(amount) }, { eventSourceId: toAccountId, event: new TaggedMoneyDeposited(amount) } ];
await this.store.eventLog.appendMany(events, { tags: ['transfer', 'audit'] }); }}