eventuo11y-0.9.0.0: An event-oriented observability library
CopyrightCopyright 2022 Shea Levy.
LicenseApache-2.0
Maintainershea@shealevy.com
Safe HaskellSafe-Inferred
LanguageHaskell2010

Observe.Event.Explicit

Description

MonadEvent and EventT-based instrumentation implicitly track the underlying EventBackend for you. This module is for those who would rather pass around EventBackends explicitly.

Synopsis

Documentation

data Event m r f Source #

An instrumentation event.

Events are the core of the instrumenting user's interface to eventuo11y. Typical usage would be to create an Event using withEvent and add fields to the Event at appropriate points in your code with addField.

m
The monad we're instrumenting in.
r
The type of event references. See reference.
f
The type of fields on this event. See addField.

hoistEvent :: (forall x. m x -> n x) -> Event m r f -> Event n r f Source #

Hoist an Event along a given natural transformation into a new monad.

Event manipulation

addField :: Event m r f -> f -> m () Source #

Add a field to an Event.

Fields make up the basic data captured in an event. They should be added to an Event as the code progresses through various phases of work, and can be both milestone markers ("we got this far in the process") or more detailed instrumentation ("we've processed N records").

They are intended to be of a domain specific type per unit of functionality within an instrumented codebase (but see DynamicField for a generic option).

reference :: Event m r f -> r Source #

Obtain a reference to an Event.

References are used to link Events together, via the newEventParent and newEventCauses fields of NewEventArgs.

References can live past when an event has been finalized.

Code being instrumented should always have r as an unconstrained type parameter, both because it is an implementation concern for EventBackends and because references are backend-specific and it would be an error to reference an event in one backend from an event in a different backend.

Resource-safe event allocation

data NewEventArgs r s f Source #

Arguments specifying how an Event should be created.

See simpleNewEventArgs for a simple case.

Constructors

NewEventArgs 

Fields

emitImmediateEvent :: EventBackend m r s -> forall f. NewEventArgs r s f -> m r Source #

Create an event which has no duration and is immediately finalized successfully.

Returns a reference to the event.

allocateEvent :: (Monad m, Exceptable e) => EventBackend m r s -> forall f. s f -> GeneralAllocate m e () releaseArg (Event m r f) Source #

Allocate a new Event, selected by the given selector.

The selector specifies the category of new event we're creating, as well as the type of fields that can be added to it (with addField).

Selectors are intended to be of a domain specific type per unit of functionality within an instrumented codebase, implemented as a GADT (but see DynamicEventSelector for a generic option).

The Event is automatically finalized on release.

allocateEventArgs :: (Monad m, Exceptable e) => EventBackend m r s -> forall f. NewEventArgs r s f -> GeneralAllocate m e () releaseArg (Event m r f) Source #

Allocate a new Event, based on given NewEventArgs.

The Event is automatically finalized on release.

withEvent Source #

Arguments

:: MonadWithExceptable m 
=> EventBackend m r s 
-> forall f. s f

The event selector.

-> (Event m r f -> m a) 
-> m a 

Run an action with a new Event, selected by the given selector.

The selector specifies the category of new event we're creating, as well as the type of fields that can be added to it (with addField).

Selectors are intended to be of a domain specific type per unit of functionality within an instrumented codebase, implemented as a GADT (but see DynamicEventSelector for a generic option).

The Event is automatically finalized at the end of the function it's passed to.

withEventArgs Source #

Arguments

:: MonadWithExceptable m 
=> EventBackend m r s 
-> forall f. NewEventArgs r s f

The event selector.

-> (Event m r f -> m a) 
-> m a 

Run an action with a new Event, based on the given NewEventArgs.

The Event is automatically finalized at the end of the function it's passed to.

EventBackends

data EventBackend m r s Source #

A backend for creating Events.

Different EventBackends will be used to emit instrumentation to different systems. Multiple backends can be combined with pairEventBackend.

A simple EventBackend for logging to a Handle can be created with jsonHandleBackend.

From an EventBackend, new events can be created via selectors (of type s f for some field type f), typically with the resource-safe allocation functions. Selectors are values which designate the general category of event being created, as well as the type of fields that can be added to it. For example, a web service's selector type may have a ServicingRequest constructor, whose field type includes a ResponseCode constructor which records the HTTP status code.

Selectors are intended to be of a domain specific type per unit of functionality within an instrumented codebase, implemented as a GADT (but see DynamicEventSelector for a generic option).

Implementations must ensure that EventBackends and their underlying Events are safe to use across threads.

m
The monad we're instrumenting in.
r
The type of event references used in this EventBackend. See reference.
s
The type of event selectors. See newEventSelector.

Backend transformation

subEventBackend Source #

Arguments

:: Functor m 
=> InjectSelector s t

Bring selectors from the new backend into the parent event's backend.

-> Event m r f

The parent event.

-> EventBackend m r t 
-> EventBackend m r s 

An EventBackend where every otherwise parentless event will be marked as a child of the given Event.

causedEventBackend Source #

Arguments

:: Functor m 
=> InjectSelector s t

Bring selectors from the new backend into the causing event's backend.

-> [Event m r f]

The causing events.

-> EventBackend m r t 
-> EventBackend m r s 

An EventBackend where every otherwise causeless event will be marked as caused by the given Events.

hoistEventBackend :: Functor m => (forall x. m x -> n x) -> EventBackend m r s -> EventBackend n r s Source #

Hoist an EventBackend along a given natural transformation into a new monad.

narrowEventBackend :: Functor m => InjectSelector s t -> EventBackend m r t -> EventBackend m r s Source #

Narrow an EventBackend to a new selector type via a given injection function.

A typical usage, where component A calls component B, would be to have A's selector type have a constructor to take any value of B's selector type (and preserve the field) and then call narrowEventBackend with that constructor when invoking functions in B.

type InjectSelector s t = forall f. s f -> forall a. (forall g. t g -> (f -> g) -> a) -> a Source #

Inject a narrower selector and its fields into a wider selector.

See injectSelector for a simple way to construct one of these.

injectSelector :: (forall f. s f -> t f) -> InjectSelector s t Source #

Construct an InjectSelector with a straightforward injection from s to t

setAncestorEventBackend :: r -> EventBackend m r s -> EventBackend m r s Source #

Transform an EventBackend so all of its Events have a given parent, if they are not given another parent.

setInitialCauseEventBackend :: [r] -> EventBackend m r s -> EventBackend m r s Source #

Transform an EventBackend so all of its Events have the given causes, if they are not given another set of causes.

Backend composition

unitEventBackend :: Applicative m => EventBackend m () s Source #

A no-op EventBackend.

This can be used if calling instrumented code from an un-instrumented context, or to purposefully ignore instrumentation from some call.

unitEventBackend is the algebraic unit of pairEventBackend.

pairEventBackend :: Applicative m => EventBackend m a s -> EventBackend m b s -> EventBackend m (a, b) s Source #

An EventBackend which sequentially generates Events in the two given EventBackends.

This can be used to emit instrumentation in multiple ways (e.g. logs to grafana and metrics on a prometheus HTML page).

noopEventBackend :: Applicative m => r -> EventBackend m r s Source #

A no-op EventBackend that can be integrated with other backends.

This can be used to purposefully ignore instrumentation from some call.

All events will have the given reference, so can be connected to appropriate events in non-no-op backends, but not in a way that can distinguish between different events from the same no-op backend.

Primitive Event resource management.

Prefer the resource-safe event allocation functions to these when possible.

finalize :: Event m r f -> Maybe SomeException -> m () Source #

Mark an Event as finished, perhaps due to an Exception.

In normal usage, this should be automatically called via the use of the resource-safe event allocation functions.

This is a no-op if the Event has already been finalized. As a result, it is likely pointless to call addField after this call, though it still may be reasonable to call reference.

newEvent :: EventBackend m r s -> forall f. NewEventArgs r s f -> m (Event m r f) Source #

Create a new Event, specified by the given arguments.

Consider the resource-safe event allocation functions instead of calling this directly.