{-| Non-intrusive distributed tracing

Let's assume for example we are interested in tracing the two following functions:

> listTaskIDs' :: MonadIO m => m [Int] -- Returns a list of all task IDs.
> fetchTasks' :: MonadIO m => [Int] -> m [Task] -- Resolves IDs into tasks.

We can do so simply by wrapping them inside a 'childSpan' call and adding a 'MonadTrace' constraint:

> import Monitor.Tracing
>
> listTaskIDs :: (MonadIO m, MonadTrace m) => m [Int]
> listTaskIDs = childSpan "list-task-ids" listTaskIDs'
>
> fetchTasks :: (MonadIO m, MonadTrace m) => [Int] -> m [Task]
> fetchTasks = childSpan "fetch-tasks" . fetchTasks'

Spans will now automatically get generated any time these actions are run! Each span will be
associated with various useful pieces of metadata, including lineage. For example, if we wrap the
two above functions in a 'rootSpan', the spans will correctly be nested:

> printTasks :: (MonadIO m, MonadTrace m) => m ()
> printTasks = rootSpan alwaysSampled "list-tasks" $ listTaskIDs >>= fetchTasks >>= print

Spans can then be published to various backends. For example, to run the above action and publish
its spans using Zipkin:

> import qualified Monitor.Tracing.Zipkin as ZPK
>
> main :: IO ()
> main = ZPK.with ZPK.defaultSettings $ ZPK.run printTasks

-}
module Monitor.Tracing (
  -- * Overview
  MonadTrace,
  -- * Generic span creation
  Sampling, alwaysSampled, neverSampled, sampledEvery, sampledWhen, debugEnabled,
  rootSpan, rootSpanWith, childSpan, childSpanWith,
  -- * Backends
  Zipkin
) where

import Control.Monad.Trace.Class
import Monitor.Tracing.Zipkin (Zipkin)