packages feed

opentracing-jaeger-0.2.0: src/OpenTracing/Jaeger/Propagation.hs

{-# LANGUAGE DataKinds         #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards   #-}

module OpenTracing.Jaeger.Propagation
    ( jaegerPropagation

    , _JaegerTextMap
    , _JaegerHeaders

    , _UberTraceId
    )
where

import           Control.Lens
import           Data.Bits
import qualified Data.HashMap.Strict     as HashMap
import           Data.Text               (Text, isPrefixOf)
import qualified Data.Text               as Text
import qualified Data.Text.Read          as Text
import           OpenTracing.Propagation
import           OpenTracing.Span
import           OpenTracing.Types


jaegerPropagation :: Propagation '[TextMap, Headers]
jaegerPropagation = Carrier _JaegerTextMap :& Carrier _JaegerHeaders :& RNil


_JaegerTextMap :: Prism' TextMap SpanContext
_JaegerTextMap = prism' fromCtx toCtx
  where
    fromCtx c = HashMap.fromList $
          ("uber-trace-id", review _UberTraceId c)
        : map (over _1 ("uberctx-" <>)) (view (ctxBaggage . to HashMap.toList) c)

    toCtx m =
          fmap (set ctxBaggage
                    (HashMap.filterWithKey (\k _ -> "uberctx-" `isPrefixOf` k) m))
        $ HashMap.lookup "uber-trace-id" m >>= preview _UberTraceId

_JaegerHeaders :: Prism' Headers SpanContext
_JaegerHeaders = _HeadersTextMap . _JaegerTextMap

_UberTraceId :: Prism' Text SpanContext
_UberTraceId = prism' fromCtx toCtx
  where
    fromCtx c@SpanContext{..} =
        let traceid = view hexText ctxTraceID
            spanid  = view hexText ctxSpanID
            parent  = maybe mempty (view hexText) ctxParentSpanID
            flags   = if view (ctxSampled . re _IsSampled) c then "1" else "0"
         in Text.intercalate ":" [traceid, spanid, parent, flags]

    toCtx t =
        let sampledFlag = 1 :: Word
            debugFlag   = 2 :: Word
            shouldSample fs = fs .&. sampledFlag > 0 || fs .&. debugFlag > 0
         in case Text.split (==':') t of
                [traceid, spanid, _, flags] -> SpanContext
                    <$> preview _Hex (knownHex traceid)
                    <*> preview _Hex (knownHex spanid)
                    <*> pure Nothing
                    <*> either (const $ Just NotSampled)
                               (Just . view _IsSampled . shouldSample . fst)
                               (Text.decimal flags)
                    <*> pure mempty

                _ -> Nothing