{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedLabels #-}
{-# LANGUAGE TypeFamilies #-}
module Colog.Message
(
SimpleMsg (..)
, logText
, fmtSimpleMessage
, formatWith
, Msg (..)
, Message
, log
, logDebug
, logInfo
, logWarning
, logError
, logException
, fmtMessage
, showSeverity
, showSourceLoc
, FieldType
, MessageField (..)
, unMessageField
, extractField
, FieldMap
, defaultFieldMap
, RichMessage
, RichMsg (..)
, fmtRichMessageDefault
, fmtSimpleRichMessageDefault
, fmtRichMessageCustomDefault
, upgradeMessageAction
) where
import Prelude hiding (log)
import Control.Concurrent (ThreadId, myThreadId)
import Control.Exception (Exception, displayException)
import Control.Monad.IO.Class (MonadIO (..))
import Data.Kind (Type)
import Data.Semigroup ((<>))
import Data.Text (Text)
import Data.Text.Lazy (toStrict)
import Data.TypeRepMap (TypeRepMap)
import GHC.Exts (IsList (..))
import GHC.OverloadedLabels (IsLabel (..))
import GHC.Stack (CallStack, SrcLoc (..), callStack, getCallStack, withFrozenCallStack)
import GHC.TypeLits (KnownSymbol, Symbol)
import System.Console.ANSI (Color (..), ColorIntensity (Vivid), ConsoleLayer (Foreground), SGR (..),
setSGRCode)
import Colog.Core (LogAction, Severity (..), cmap)
import Colog.Monad (WithLog, logMsg)
import qualified Chronos as C
import qualified Chronos.Locale.English as C
import qualified Data.Text as T
import qualified Data.Text.Lazy.Builder as TB
import qualified Data.Text.Lazy.Builder.Int as TB
import qualified Data.TypeRepMap as TM
import qualified Data.Vector as Vector
data Msg sev = Msg
{ Msg sev -> sev
msgSeverity :: !sev
, Msg sev -> CallStack
msgStack :: !CallStack
, Msg sev -> Text
msgText :: !Text
}
data SimpleMsg = SimpleMsg
{ SimpleMsg -> CallStack
simpleMsgStack :: !CallStack
, SimpleMsg -> Text
simpleMsgText :: !Text
}
type Message = Msg Severity
log :: WithLog env (Msg sev) m => sev -> Text -> m ()
log :: sev -> Text -> m ()
log msgSeverity :: sev
msgSeverity msgText :: Text
msgText =
(HasCallStack => m ()) -> m ()
forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack (Msg sev -> m ()
forall msg env (m :: * -> *). WithLog env msg m => msg -> m ()
logMsg $WMsg :: forall sev. sev -> CallStack -> Text -> Msg sev
Msg{ msgStack :: CallStack
msgStack = CallStack
HasCallStack => CallStack
callStack, .. })
logDebug :: WithLog env Message m => Text -> m ()
logDebug :: Text -> m ()
logDebug = (HasCallStack => Text -> m ()) -> Text -> m ()
forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack (Severity -> Text -> m ()
forall env sev (m :: * -> *).
WithLog env (Msg sev) m =>
sev -> Text -> m ()
log Severity
Debug)
logInfo :: WithLog env Message m => Text -> m ()
logInfo :: Text -> m ()
logInfo = (HasCallStack => Text -> m ()) -> Text -> m ()
forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack (Severity -> Text -> m ()
forall env sev (m :: * -> *).
WithLog env (Msg sev) m =>
sev -> Text -> m ()
log Severity
Info)
logWarning :: WithLog env Message m => Text -> m ()
logWarning :: Text -> m ()
logWarning = (HasCallStack => Text -> m ()) -> Text -> m ()
forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack (Severity -> Text -> m ()
forall env sev (m :: * -> *).
WithLog env (Msg sev) m =>
sev -> Text -> m ()
log Severity
Warning)
logError :: WithLog env Message m => Text -> m ()
logError :: Text -> m ()
logError = (HasCallStack => Text -> m ()) -> Text -> m ()
forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack (Severity -> Text -> m ()
forall env sev (m :: * -> *).
WithLog env (Msg sev) m =>
sev -> Text -> m ()
log Severity
Error)
logException :: forall e m env . (WithLog env Message m, Exception e) => e -> m ()
logException :: e -> m ()
logException = (HasCallStack => e -> m ()) -> e -> m ()
forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack (Text -> m ()
forall env (m :: * -> *). WithLog env Message m => Text -> m ()
logError (Text -> m ()) -> (e -> Text) -> e -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack (String -> Text) -> (e -> String) -> e -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. e -> String
forall e. Exception e => e -> String
displayException)
logText :: WithLog env SimpleMsg m => Text -> m ()
logText :: Text -> m ()
logText msgText :: Text
msgText = (HasCallStack => m ()) -> m ()
forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack (SimpleMsg -> m ()
forall msg env (m :: * -> *). WithLog env msg m => msg -> m ()
logMsg $WSimpleMsg :: CallStack -> Text -> SimpleMsg
SimpleMsg{ simpleMsgStack :: CallStack
simpleMsgStack = CallStack
HasCallStack => CallStack
callStack, simpleMsgText :: Text
simpleMsgText = Text
msgText })
fmtMessage :: Message -> Text
fmtMessage :: Message -> Text
fmtMessage Msg{..} =
Severity -> Text
showSeverity Severity
msgSeverity
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> CallStack -> Text
showSourceLoc CallStack
msgStack
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
msgText
fmtSimpleMessage :: SimpleMsg -> Text
fmtSimpleMessage :: SimpleMsg -> Text
fmtSimpleMessage SimpleMsg{..} = CallStack -> Text
showSourceLoc CallStack
simpleMsgStack Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
simpleMsgText
formatWith :: (msg -> Text) -> LogAction m Text -> LogAction m msg
formatWith :: (msg -> Text) -> LogAction m Text -> LogAction m msg
formatWith = (msg -> Text) -> LogAction m Text -> LogAction m msg
forall a b (m :: * -> *).
(a -> b) -> LogAction m b -> LogAction m a
cmap
{-# INLINE formatWith #-}
showSeverity :: Severity -> Text
showSeverity :: Severity -> Text
showSeverity = \case
Debug -> Color -> Text -> Text
color Color
Green "[Debug] "
Info -> Color -> Text -> Text
color Color
Blue "[Info] "
Warning -> Color -> Text -> Text
color Color
Yellow "[Warning] "
Error -> Color -> Text -> Text
color Color
Red "[Error] "
where
color :: Color -> Text -> Text
color :: Color -> Text -> Text
color c :: Color
c txt :: Text
txt =
String -> Text
T.pack ([SGR] -> String
setSGRCode [ConsoleLayer -> ColorIntensity -> Color -> SGR
SetColor ConsoleLayer
Foreground ColorIntensity
Vivid Color
c])
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
txt
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
T.pack ([SGR] -> String
setSGRCode [SGR
Reset])
square :: Text -> Text
square :: Text -> Text
square t :: Text
t = "[" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
t Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> "] "
showSourceLoc :: CallStack -> Text
showSourceLoc :: CallStack -> Text
showSourceLoc cs :: CallStack
cs = Text -> Text
square Text
showCallStack
where
showCallStack :: Text
showCallStack :: Text
showCallStack = case CallStack -> [(String, SrcLoc)]
getCallStack CallStack
cs of
[] -> "<unknown loc>"
[(name :: String
name, loc :: SrcLoc
loc)] -> String -> SrcLoc -> Text
showLoc String
name SrcLoc
loc
(_, loc :: SrcLoc
loc) : (callerName :: String
callerName, _) : _ -> String -> SrcLoc -> Text
showLoc String
callerName SrcLoc
loc
showLoc :: String -> SrcLoc -> Text
showLoc :: String -> SrcLoc -> Text
showLoc name :: String
name SrcLoc{..} =
String -> Text
T.pack String
srcLocModule Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> "." Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
T.pack String
name Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> "#" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
T.pack (Int -> String
forall a. Show a => a -> String
show Int
srcLocStartLine)
type family FieldType (fieldName :: Symbol) :: Type
type instance FieldType "threadId" = ThreadId
type instance FieldType "posixTime" = C.Time
newtype MessageField (m :: Type -> Type) (fieldName :: Symbol) where
MessageField :: forall fieldName m . m (FieldType fieldName) -> MessageField m fieldName
unMessageField :: forall fieldName m . MessageField m fieldName -> m (FieldType fieldName)
unMessageField :: MessageField m fieldName -> m (FieldType fieldName)
unMessageField (MessageField f :: m (FieldType fieldName)
f) = m (FieldType fieldName)
f
{-# INLINE unMessageField #-}
instance (KnownSymbol fieldName, a ~ m (FieldType fieldName))
=> IsLabel fieldName (a -> TM.WrapTypeable (MessageField m)) where
#if MIN_VERSION_base(4,11,0)
fromLabel :: a -> WrapTypeable (MessageField m)
fromLabel field :: a
field = MessageField m fieldName -> WrapTypeable (MessageField m)
forall k (a :: k) (f :: k -> *).
Typeable a =>
f a -> WrapTypeable f
TM.WrapTypeable (MessageField m fieldName -> WrapTypeable (MessageField m))
-> MessageField m fieldName -> WrapTypeable (MessageField m)
forall a b. (a -> b) -> a -> b
$ m (FieldType fieldName) -> MessageField m fieldName
forall (fieldName :: Symbol) (m :: * -> *).
m (FieldType fieldName) -> MessageField m fieldName
MessageField @fieldName a
m (FieldType fieldName)
field
#else
fromLabel field = TM.WrapTypeable $ MessageField @_ @fieldName field
#endif
{-# INLINE fromLabel #-}
extractField
:: Applicative m
=> Maybe (MessageField m fieldName)
-> m (Maybe (FieldType fieldName))
= (MessageField m fieldName -> m (FieldType fieldName))
-> Maybe (MessageField m fieldName)
-> m (Maybe (FieldType fieldName))
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse MessageField m fieldName -> m (FieldType fieldName)
forall (fieldName :: Symbol) (m :: * -> *).
MessageField m fieldName -> m (FieldType fieldName)
unMessageField
{-# INLINE extractField #-}
type FieldMap (m :: Type -> Type) = TypeRepMap (MessageField m)
defaultFieldMap :: MonadIO m => FieldMap m
defaultFieldMap :: FieldMap m
defaultFieldMap = [Item (FieldMap m)] -> FieldMap m
forall l. IsList l => [Item l] -> l
fromList
[ IsLabel "threadId" (m ThreadId -> WrapTypeable (MessageField m))
m ThreadId -> WrapTypeable (MessageField m)
#threadId (IO ThreadId -> m ThreadId
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO ThreadId
myThreadId)
, IsLabel "posixTime" (m Time -> WrapTypeable (MessageField m))
m Time -> WrapTypeable (MessageField m)
#posixTime (IO Time -> m Time
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO Time
C.now)
]
data RichMsg (m :: Type -> Type) (msg :: Type) = RichMsg
{ RichMsg m msg -> msg
richMsgMsg :: !msg
, RichMsg m msg -> FieldMap m
richMsgMap :: {-# UNPACK #-} !(FieldMap m)
} deriving stock (a -> RichMsg m b -> RichMsg m a
(a -> b) -> RichMsg m a -> RichMsg m b
(forall a b. (a -> b) -> RichMsg m a -> RichMsg m b)
-> (forall a b. a -> RichMsg m b -> RichMsg m a)
-> Functor (RichMsg m)
forall a b. a -> RichMsg m b -> RichMsg m a
forall a b. (a -> b) -> RichMsg m a -> RichMsg m b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
forall (m :: * -> *) a b. a -> RichMsg m b -> RichMsg m a
forall (m :: * -> *) a b. (a -> b) -> RichMsg m a -> RichMsg m b
<$ :: a -> RichMsg m b -> RichMsg m a
$c<$ :: forall (m :: * -> *) a b. a -> RichMsg m b -> RichMsg m a
fmap :: (a -> b) -> RichMsg m a -> RichMsg m b
$cfmap :: forall (m :: * -> *) a b. (a -> b) -> RichMsg m a -> RichMsg m b
Functor)
type RichMessage m = RichMsg m Message
fmtRichMessageDefault :: MonadIO m => RichMessage m -> m Text
fmtRichMessageDefault :: RichMessage m -> m Text
fmtRichMessageDefault msg :: RichMessage m
msg = RichMessage m
-> (Maybe ThreadId -> Maybe Time -> Message -> Text) -> m Text
forall (m :: * -> *) msg.
MonadIO m =>
RichMsg m msg
-> (Maybe ThreadId -> Maybe Time -> msg -> Text) -> m Text
fmtRichMessageCustomDefault RichMessage m
msg Maybe ThreadId -> Maybe Time -> Message -> Text
formatRichMessage
where
formatRichMessage :: Maybe ThreadId -> Maybe C.Time -> Message -> Text
formatRichMessage :: Maybe ThreadId -> Maybe Time -> Message -> Text
formatRichMessage (Text -> (ThreadId -> Text) -> Maybe ThreadId -> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe "" ThreadId -> Text
showThreadId -> Text
thread) (Text -> (Time -> Text) -> Maybe Time -> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe "" Time -> Text
showTime -> Text
time) Msg{..} =
Severity -> Text
showSeverity Severity
msgSeverity
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
time
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> CallStack -> Text
showSourceLoc CallStack
msgStack
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
thread
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
msgText
fmtSimpleRichMessageDefault :: MonadIO m => RichMsg m SimpleMsg -> m Text
fmtSimpleRichMessageDefault :: RichMsg m SimpleMsg -> m Text
fmtSimpleRichMessageDefault msg :: RichMsg m SimpleMsg
msg = RichMsg m SimpleMsg
-> (Maybe ThreadId -> Maybe Time -> SimpleMsg -> Text) -> m Text
forall (m :: * -> *) msg.
MonadIO m =>
RichMsg m msg
-> (Maybe ThreadId -> Maybe Time -> msg -> Text) -> m Text
fmtRichMessageCustomDefault RichMsg m SimpleMsg
msg Maybe ThreadId -> Maybe Time -> SimpleMsg -> Text
formatRichMessage
where
formatRichMessage :: Maybe ThreadId -> Maybe C.Time -> SimpleMsg -> Text
formatRichMessage :: Maybe ThreadId -> Maybe Time -> SimpleMsg -> Text
formatRichMessage (Text -> (ThreadId -> Text) -> Maybe ThreadId -> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe "" ThreadId -> Text
showThreadId -> Text
thread) (Text -> (Time -> Text) -> Maybe Time -> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe "" Time -> Text
showTime -> Text
time) SimpleMsg{..} =
Text
time
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> CallStack -> Text
showSourceLoc CallStack
simpleMsgStack
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
thread
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
simpleMsgText
fmtRichMessageCustomDefault
:: MonadIO m
=> RichMsg m msg
-> (Maybe ThreadId -> Maybe C.Time -> msg -> Text)
-> m Text
fmtRichMessageCustomDefault :: RichMsg m msg
-> (Maybe ThreadId -> Maybe Time -> msg -> Text) -> m Text
fmtRichMessageCustomDefault RichMsg{..} formatter :: Maybe ThreadId -> Maybe Time -> msg -> Text
formatter = do
Maybe ThreadId
maybeThreadId <- Maybe (MessageField m "threadId") -> m (Maybe ThreadId)
forall (m :: * -> *) (fieldName :: Symbol).
Applicative m =>
Maybe (MessageField m fieldName) -> m (Maybe (FieldType fieldName))
extractField (Maybe (MessageField m "threadId") -> m (Maybe ThreadId))
-> Maybe (MessageField m "threadId") -> m (Maybe ThreadId)
forall a b. (a -> b) -> a -> b
$ FieldMap m -> Maybe (MessageField m "threadId")
forall k (a :: k) (f :: k -> *).
Typeable a =>
TypeRepMap f -> Maybe (f a)
TM.lookup @"threadId" FieldMap m
richMsgMap
Maybe Time
maybePosixTime <- Maybe (MessageField m "posixTime") -> m (Maybe Time)
forall (m :: * -> *) (fieldName :: Symbol).
Applicative m =>
Maybe (MessageField m fieldName) -> m (Maybe (FieldType fieldName))
extractField (Maybe (MessageField m "posixTime") -> m (Maybe Time))
-> Maybe (MessageField m "posixTime") -> m (Maybe Time)
forall a b. (a -> b) -> a -> b
$ FieldMap m -> Maybe (MessageField m "posixTime")
forall k (a :: k) (f :: k -> *).
Typeable a =>
TypeRepMap f -> Maybe (f a)
TM.lookup @"posixTime" FieldMap m
richMsgMap
Text -> m Text
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Text -> m Text) -> Text -> m Text
forall a b. (a -> b) -> a -> b
$ Maybe ThreadId -> Maybe Time -> msg -> Text
formatter Maybe ThreadId
maybeThreadId Maybe Time
maybePosixTime msg
richMsgMsg
showTime :: C.Time -> Text
showTime :: Time -> Text
showTime t :: Time
t =
Text -> Text
square
(Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ Text -> Text
toStrict
(Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ Builder -> Text
TB.toLazyText
(Builder -> Text) -> Builder -> Text
forall a b. (a -> b) -> a -> b
$ Datetime -> Builder
builderDmyHMSz (Time -> Datetime
C.timeToDatetime Time
t)
builderDmyHMSz :: C.Datetime -> TB.Builder
builderDmyHMSz :: Datetime -> Builder
builderDmyHMSz (C.Datetime date :: Date
date time :: TimeOfDay
time) =
Date -> Builder
builderDmy Date
date
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
spaceSep
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> SubsecondPrecision -> Maybe Char -> TimeOfDay -> Builder
C.builder_HMS (Int -> SubsecondPrecision
C.SubsecondPrecisionFixed 3) (Char -> Maybe Char
forall a. a -> Maybe a
Just ':') TimeOfDay
time
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
spaceSep
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> OffsetFormat -> Offset -> Builder
C.builderOffset OffsetFormat
C.OffsetFormatColonOn (Int -> Offset
C.Offset 0)
where
spaceSep :: TB.Builder
spaceSep :: Builder
spaceSep = Char -> Builder
TB.singleton ' '
builderDmy :: C.Date -> TB.Builder
builderDmy :: Date -> Builder
builderDmy (C.Date (C.Year y :: Int
y) m :: Month
m d :: DayOfMonth
d) =
DayOfMonth -> Builder
zeroPadDayOfMonth DayOfMonth
d
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
spaceSep
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Text -> Builder
TB.fromText (MonthMatch Text -> Month -> Text
forall a. MonthMatch a -> Month -> a
C.caseMonth MonthMatch Text
C.abbreviated Month
m)
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
spaceSep
Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Int -> Builder
forall a. Integral a => a -> Builder
TB.decimal Int
y
zeroPadDayOfMonth :: C.DayOfMonth -> TB.Builder
zeroPadDayOfMonth :: DayOfMonth -> Builder
zeroPadDayOfMonth (C.DayOfMonth d :: Int
d) =
if Int
d Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< 100
then Vector Builder -> Int -> Builder
forall a. Vector a -> Int -> a
Vector.unsafeIndex Vector Builder
twoDigitTextBuilder Int
d
else Int -> Builder
forall a. Integral a => a -> Builder
TB.decimal Int
d
twoDigitTextBuilder :: Vector.Vector TB.Builder
twoDigitTextBuilder :: Vector Builder
twoDigitTextBuilder = [Builder] -> Vector Builder
forall a. [a] -> Vector a
Vector.fromList ([Builder] -> Vector Builder) -> [Builder] -> Vector Builder
forall a b. (a -> b) -> a -> b
$
(String -> Builder) -> [String] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
map (Text -> Builder
TB.fromText (Text -> Builder) -> (String -> Text) -> String -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack) [String]
twoDigitStrings
{-# NOINLINE twoDigitTextBuilder #-}
twoDigitStrings :: [String]
twoDigitStrings :: [String]
twoDigitStrings =
[ "00","01","02","03","04","05","06","07","08","09"
, "10","11","12","13","14","15","16","17","18","19"
, "20","21","22","23","24","25","26","27","28","29"
, "30","31","32","33","34","35","36","37","38","39"
, "40","41","42","43","44","45","46","47","48","49"
, "50","51","52","53","54","55","56","57","58","59"
, "60","61","62","63","64","65","66","67","68","69"
, "70","71","72","73","74","75","76","77","78","79"
, "80","81","82","83","84","85","86","87","88","89"
, "90","91","92","93","94","95","96","97","98","99"
]
showThreadId :: ThreadId -> Text
showThreadId :: ThreadId -> Text
showThreadId = Text -> Text
square (Text -> Text) -> (ThreadId -> Text) -> ThreadId -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack (String -> Text) -> (ThreadId -> String) -> ThreadId -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ThreadId -> String
forall a. Show a => a -> String
show
upgradeMessageAction
:: forall m msg .
FieldMap m
-> LogAction m (RichMsg m msg)
-> LogAction m msg
upgradeMessageAction :: FieldMap m -> LogAction m (RichMsg m msg) -> LogAction m msg
upgradeMessageAction fieldMap :: FieldMap m
fieldMap = (msg -> RichMsg m msg)
-> LogAction m (RichMsg m msg) -> LogAction m msg
forall a b (m :: * -> *).
(a -> b) -> LogAction m b -> LogAction m a
cmap msg -> RichMsg m msg
addMap
where
addMap :: msg -> RichMsg m msg
addMap :: msg -> RichMsg m msg
addMap msg :: msg
msg = msg -> FieldMap m -> RichMsg m msg
forall (m :: * -> *) msg. msg -> FieldMap m -> RichMsg m msg
RichMsg msg
msg FieldMap m
fieldMap