{-# LANGUAGE CPP #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE StrictData #-}
{-# LANGUAGE TemplateHaskell #-}
module OpenTracing.Log
( LogRecord(..)
, logTime
, logFields
, LogField(..)
, logFieldLabel
, logFieldEncoding
, logFieldValue
, LogFieldsFormatter
, jsonAssoc
, jsonMap
)
where
import Control.Exception
import Control.Lens hiding ((.=))
import Data.Aeson
import qualified Data.Aeson.Encoding as Encoding
#if MIN_VERSION_aeson(2, 0, 0)
import qualified Data.Aeson.Key as Key
#endif
import Data.ByteString.Builder (Builder)
import Data.Foldable
import Data.List.NonEmpty (NonEmpty)
import Data.Text (Text)
import Data.Time.Clock
import GHC.Stack
import qualified Data.Map.Strict as Map
data LogRecord = LogRecord
{ LogRecord -> UTCTime
_logTime :: UTCTime
, LogRecord -> NonEmpty LogField
_logFields :: NonEmpty LogField
} deriving Int -> LogRecord -> ShowS
[LogRecord] -> ShowS
LogRecord -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [LogRecord] -> ShowS
$cshowList :: [LogRecord] -> ShowS
show :: LogRecord -> String
$cshow :: LogRecord -> String
showsPrec :: Int -> LogRecord -> ShowS
$cshowsPrec :: Int -> LogRecord -> ShowS
Show
data LogField where
LogField :: Show a => Text -> a -> LogField
Event :: Text -> LogField
Message :: Text -> LogField
Stack :: CallStack -> LogField
ErrKind :: Text -> LogField
ErrObj :: Exception e => e -> LogField
deriving instance (Show LogField)
type LogFieldsFormatter = forall t. Foldable t => t LogField -> Builder
jsonAssoc :: LogFieldsFormatter
jsonAssoc :: LogFieldsFormatter
jsonAssoc = forall tag. Encoding' tag -> Builder
Encoding.fromEncoding forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> Encoding' Value) -> [a] -> Encoding' Value
Encoding.list LogField -> Encoding' Value
go forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a. Foldable t => t a -> [a]
toList
where
go :: LogField -> Encoding' Value
go LogField
lf = Series -> Encoding' Value
Encoding.pairs forall a b. (a -> b) -> a -> b
$ Key -> Encoding' Value -> Series
Encoding.pair (LogField -> Key
key LogField
lf) (LogField -> Encoding' Value
logFieldEncoding LogField
lf)
#if MIN_VERSION_aeson(2, 0, 0)
key :: LogField -> Key
key LogField
lf = Text -> Key
Key.fromText forall a b. (a -> b) -> a -> b
$ LogField -> Text
logFieldLabel LogField
lf
#else
key lf = logFieldLabel lf
#endif
jsonMap :: LogFieldsFormatter
jsonMap :: LogFieldsFormatter
jsonMap
= forall tag. Encoding' tag -> Builder
Encoding.fromEncoding
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall k v m.
(k -> Encoding' Key)
-> (v -> Encoding' Value)
-> (forall a. (k -> v -> a -> a) -> a -> m -> a)
-> m
-> Encoding' Value
Encoding.dict forall a. Text -> Encoding' a
Encoding.text forall a. a -> a
id forall k a b. (k -> a -> b -> b) -> b -> Map k a -> b
Map.foldrWithKey'
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr' LogField
-> Map Text (Encoding' Value) -> Map Text (Encoding' Value)
merge forall a. Monoid a => a
mempty
where
merge :: LogField
-> Map Text (Encoding' Value) -> Map Text (Encoding' Value)
merge LogField
lf = forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert (LogField -> Text
logFieldLabel LogField
lf) (LogField -> Encoding' Value
logFieldEncoding LogField
lf)
logFieldLabel :: LogField -> Text
logFieldLabel :: LogField -> Text
logFieldLabel (LogField Text
x a
_) = Text
x
logFieldLabel (Event Text
_) = Text
"event"
logFieldLabel (Message Text
_) = Text
"message"
logFieldLabel (Stack CallStack
_) = Text
"stack"
logFieldLabel (ErrKind Text
_) = Text
"error.kind"
logFieldLabel (ErrObj e
_) = Text
"error.object"
logFieldEncoding :: LogField -> Encoding
logFieldEncoding :: LogField -> Encoding' Value
logFieldEncoding (LogField Text
_ a
v) = forall a. String -> Encoding' a
Encoding.string forall a b. (a -> b) -> a -> b
$ forall a. Show a => a -> String
show a
v
logFieldEncoding (Event Text
v) = forall a. Text -> Encoding' a
Encoding.text Text
v
logFieldEncoding (Message Text
v) = forall a. Text -> Encoding' a
Encoding.text Text
v
logFieldEncoding (Stack CallStack
v) = forall a. String -> Encoding' a
Encoding.string forall a b. (a -> b) -> a -> b
$ CallStack -> String
prettyCallStack CallStack
v
logFieldEncoding (ErrKind Text
v) = forall a. Text -> Encoding' a
Encoding.text Text
v
logFieldEncoding (ErrObj e
v) = forall a. String -> Encoding' a
Encoding.string forall a b. (a -> b) -> a -> b
$ forall a. Show a => a -> String
show e
v
logFieldValue :: LogField -> Value
logFieldValue :: LogField -> Value
logFieldValue (LogField Text
_ a
v) = forall a. ToJSON a => a -> Value
toJSON forall a b. (a -> b) -> a -> b
$ forall a. Show a => a -> String
show a
v
logFieldValue (Event Text
v) = forall a. ToJSON a => a -> Value
toJSON Text
v
logFieldValue (Message Text
v) = forall a. ToJSON a => a -> Value
toJSON Text
v
logFieldValue (Stack CallStack
v) = forall a. ToJSON a => a -> Value
toJSON forall a b. (a -> b) -> a -> b
$ CallStack -> String
prettyCallStack CallStack
v
logFieldValue (ErrKind Text
v) = forall a. ToJSON a => a -> Value
toJSON Text
v
logFieldValue (ErrObj e
v) = forall a. ToJSON a => a -> Value
toJSON forall a b. (a -> b) -> a -> b
$ forall a. Show a => a -> String
show e
v
makeLenses ''LogRecord