EventBuilder

public struct EventBuilder

An EventBuilder is what your app uses to add information to events and send them when they’re complete.

Using the current event

Event.current is an event builder that different parts of your app can use to attach custom data to a currently in-progress event. Various parts of your app can add fields to the current event without having to coordinate passing the event around or even having to know about each other.

When the work corresponding to an event is complete, be sure to send the current event. When you do, the current event will be reset to a blank slate so that the next action can start adding information for the next event.

Attaching fields to all events

Event.global is an event builder that is not meant to be sent. Instead, you can add fields to the global event builder, and those fields will be included automatically in all events.

  • An error that should be logged with the event.

    Since needing to log errors is a very common case, you can use this field instead of having to define an event key for errors in your app. When encoding the event, the error’s localizedDescription will be encoded in the err key of the event.

    Generally, for consistency, you should always use this property to log an error, but there may be cases where a single event can generate multiple errors because it doesn’t stop short in the case of an error. In this situation, it’s fine to define custom event keys for each error and store both on the event.

    Declaration

    Swift

    public var error: Error?
  • Create a new EventBuilder.

    Think carefully before constructing an EventBuilder directly. Most of the time, you’ll want to use Event.current to avoid having to pass the event around to different parts of your app explicitly. However, if you have background work that may be happening concurrently with user actions, you’ll want to let the user actions use Event.current and create a separate EventBuilder for the background work to use so that you can log those events separately.

    Declaration

    Swift

    public init(sink: EventSink = Event.sink)

    Parameters

    sink

    A different event sink to use than the default that is set at Event.sink.

  • Get or set custom fields to include app-specific data in your events

    This is the primary way to include dynamic data in your events. You should define an Event.Key for each field you want to include, then use the subscript to assign data to that field in your app. The value you assign can be anything Encodable, though depending on the event sink you use and the encoder it uses, there may be limitations on what values can actually be encoded in the event. For example, the OSLogEventSink does not currently support nested keys, so your values need to encode to a flat structure.

    Declaration

    Swift

    public subscript<T>(key: Event.Key) -> T? where T : Encodable { get set }

    Parameters

    key

    The key of the data in the event.

    Return Value

    The encodable value associated with the key in the event.

  • Set a custom field to a value that will be evaluated on-demand when the event is sent.

    This is very similar to normal field assignment, but instead of providing the value directly, you must provide a closure that returns the value you want to be included in the event. When the event is about to be sent, the closure will be called, and the result will be used as the field value.

    If you reuse the event builder, either by making copies and sending those or by setting closures for fields in Event.global, the result of the closure will not be cached: it will be called each time an event is sent that included that field. This kind of field is useful for including dynamic system state in your events that may change at any time.

    Important

    Due to the way on-demand fields are stored, it’s not possible to get the closure that was originally set for the field back out later. Attempting to do so will result in a fatalError(), because Swift requires a getter for all subscripts.

    Declaration

    Swift

    public subscript<T>(key: Event.Key) -> () -> T where T : Encodable { get set }

    Parameters

    key

    The key of the data in the event.

    Return Value

    A closure that returns the encodable value associated with the key in the event.

  • Starts a timer that will store a duration for a given key.

    It can be useful to track durations of specific parts of the work your app does during an event and store those durations as fields in the event. This method provides an easy way to do that.

    Call startTimer(_:) when the work you want to measure begins, then call stopTimer(_:) with the same key when it completes. When you stop the timer, the duration in milliseconds of the work will be stored in the event under key.

    Precondition

    There must not be a timer already started for this key.

    Declaration

    Swift

    public mutating func startTimer(_ key: Event.Key)

    Parameters

    key

    The key in the event where the timer duration will be stored when stopped.

  • Stops a timer that was previously started and records the duration in the event.

    The duration is stored as the milliseconds that passed between starting the timer and calling this method.

    Precondition

    A timer must have been started for this key already.

    Declaration

    Swift

    public mutating func stopTimer(_ key: Event.Key)

    Parameters

    key

    The key used to start the timer and where the duration will be stored on the event.

  • Send the event to its sink using the default level.

    See send(_:_:) for more details on sending events.

    Declaration

    Swift

    public mutating func send(_ message: StaticString)

    Parameters

    message

    A message to describe the event.

  • Send the event to its sink at a given level.

    This creates an Event based on the current fields in this builder and the global builder, and sends it to the event sink.

    After sending the event, all fields are cleared from the builder so that it can be reused to send a new event. This is primarily to support reusing Event.current in a natural way. If you need to send an event and also keep using the existing fields for it, you can copy the event into a new var and send the copy, and only the copy will be reset. If you find yourself doing this, it may be a sign that you are sending too many events and should be collapsing more data into less granular events.

    Declaration

    Swift

    public mutating func send(_ level: OSLogType, _ message: StaticString)

    Parameters

    level

    The log level to send this event at. Not all sinks will do something useful with this information.

    message

    A message to describe the event. This message cannot include dynamic data. All dynamic data should be added as fields on the event.