module Control.Monad.Logger.Logstash (
runLogstashLoggingT,
stashJsonLine,
jsonLogLine,
withLogstashLoggingT,
runTBMQueueLoggingT,
unTBMQueueLoggingT,
LogstashContext(..)
) where
import Control.Concurrent
import Control.Concurrent.STM
import Control.Concurrent.STM.TBMQueue
import Control.Exception (Handler)
import Control.Monad
import Control.Monad.Logger
import Control.Monad.Trans.Reader
import Control.Retry
import Data.Aeson
import Data.Maybe
import Data.Text (Text)
import Data.Text.Encoding (decodeUtf8)
import UnliftIO (MonadIO(..), MonadUnliftIO)
import Logstash hiding (stashJsonLine)
import qualified Logstash as L (stashJsonLine)
runLogstashLoggingT
:: LogstashContext ctx
=> ctx
-> RetryPolicyM IO
-> Integer
-> ( RetryStatus ->
(Loc, LogSource, LogLevel, LogStr) ->
ReaderT LogstashConnection IO ()
)
-> LoggingT m a
-> m a
runLogstashLoggingT :: ctx
-> RetryPolicyM IO
-> Integer
-> (RetryStatus
-> (Loc, LogSource, LogLevel, LogStr)
-> ReaderT LogstashConnection IO ())
-> LoggingT m a
-> m a
runLogstashLoggingT ctx
ctx RetryPolicyM IO
policy Integer
time RetryStatus
-> (Loc, LogSource, LogLevel, LogStr)
-> ReaderT LogstashConnection IO ()
codec LoggingT m a
log = LoggingT m a
-> (Loc -> LogSource -> LogLevel -> LogStr -> IO ()) -> m a
forall (m :: * -> *) a.
LoggingT m a
-> (Loc -> LogSource -> LogLevel -> LogStr -> IO ()) -> m a
runLoggingT LoggingT m a
log ((Loc -> LogSource -> LogLevel -> LogStr -> IO ()) -> m a)
-> (Loc -> LogSource -> LogLevel -> LogStr -> IO ()) -> m a
forall a b. (a -> b) -> a -> b
$
\Loc
logLoc LogSource
logSource LogLevel
logLevel LogStr
logStr -> ctx
-> RetryPolicyM IO
-> Integer
-> (RetryStatus -> ReaderT LogstashConnection IO ())
-> IO ()
forall ctx (m :: * -> *) a.
(LogstashContext ctx, MonadMask m, MonadUnliftIO m) =>
ctx
-> RetryPolicyM m
-> Integer
-> (RetryStatus -> ReaderT LogstashConnection m a)
-> m a
runLogstash ctx
ctx RetryPolicyM IO
policy Integer
time ((RetryStatus -> ReaderT LogstashConnection IO ()) -> IO ())
-> (RetryStatus -> ReaderT LogstashConnection IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$
\RetryStatus
s -> RetryStatus
-> (Loc, LogSource, LogLevel, LogStr)
-> ReaderT LogstashConnection IO ()
codec RetryStatus
s (Loc
logLoc, LogSource
logSource, LogLevel
logLevel, LogStr
logStr)
withLogstashLoggingT
:: (LogstashContext ctx, MonadUnliftIO m)
=> LogstashQueueCfg ctx
-> ( RetryStatus ->
(Loc, LogSource, LogLevel, LogStr) ->
ReaderT LogstashConnection IO ()
)
-> [(Loc, LogSource, LogLevel, LogStr) -> Handler ()]
-> LoggingT m a
-> m a
withLogstashLoggingT :: LogstashQueueCfg ctx
-> (RetryStatus
-> (Loc, LogSource, LogLevel, LogStr)
-> ReaderT LogstashConnection IO ())
-> [(Loc, LogSource, LogLevel, LogStr) -> Handler ()]
-> LoggingT m a
-> m a
withLogstashLoggingT LogstashQueueCfg ctx
cfg RetryStatus
-> (Loc, LogSource, LogLevel, LogStr)
-> ReaderT LogstashConnection IO ()
dispatch [(Loc, LogSource, LogLevel, LogStr) -> Handler ()]
hs LoggingT m a
log = LogstashQueueCfg ctx
-> (RetryStatus
-> (Loc, LogSource, LogLevel, LogStr)
-> ReaderT LogstashConnection IO ())
-> [(Loc, LogSource, LogLevel, LogStr) -> Handler ()]
-> (TBMQueue (Loc, LogSource, LogLevel, LogStr) -> m a)
-> m a
forall ctx (m :: * -> *) item a.
(LogstashContext ctx, MonadUnliftIO m) =>
LogstashQueueCfg ctx
-> (RetryStatus -> item -> ReaderT LogstashConnection IO ())
-> [item -> Handler ()]
-> (TBMQueue item -> m a)
-> m a
withLogstashQueue LogstashQueueCfg ctx
cfg RetryStatus
-> (Loc, LogSource, LogLevel, LogStr)
-> ReaderT LogstashConnection IO ()
dispatch [(Loc, LogSource, LogLevel, LogStr) -> Handler ()]
hs ((TBMQueue (Loc, LogSource, LogLevel, LogStr) -> m a) -> m a)
-> (TBMQueue (Loc, LogSource, LogLevel, LogStr) -> m a) -> m a
forall a b. (a -> b) -> a -> b
$
\TBMQueue (Loc, LogSource, LogLevel, LogStr)
queue -> TBMQueue (Loc, LogSource, LogLevel, LogStr) -> LoggingT m a -> m a
forall (m :: * -> *) a.
MonadUnliftIO m =>
TBMQueue (Loc, LogSource, LogLevel, LogStr) -> LoggingT m a -> m a
runTBMQueueLoggingT TBMQueue (Loc, LogSource, LogLevel, LogStr)
queue LoggingT m a
log
runTBMQueueLoggingT
:: MonadUnliftIO m
=> TBMQueue (Loc, LogSource, LogLevel, LogStr)
-> LoggingT m a
-> m a
runTBMQueueLoggingT :: TBMQueue (Loc, LogSource, LogLevel, LogStr) -> LoggingT m a -> m a
runTBMQueueLoggingT TBMQueue (Loc, LogSource, LogLevel, LogStr)
queue LoggingT m a
log = LoggingT m a
-> (Loc -> LogSource -> LogLevel -> LogStr -> IO ()) -> m a
forall (m :: * -> *) a.
LoggingT m a
-> (Loc -> LogSource -> LogLevel -> LogStr -> IO ()) -> m a
runLoggingT LoggingT m a
log ((Loc -> LogSource -> LogLevel -> LogStr -> IO ()) -> m a)
-> (Loc -> LogSource -> LogLevel -> LogStr -> IO ()) -> m a
forall a b. (a -> b) -> a -> b
$
\Loc
logLoc LogSource
logSource LogLevel
logLevel LogStr
logStr -> STM () -> IO ()
forall a. STM a -> IO a
atomically (STM () -> IO ()) -> STM () -> IO ()
forall a b. (a -> b) -> a -> b
$
TBMQueue (Loc, LogSource, LogLevel, LogStr)
-> (Loc, LogSource, LogLevel, LogStr) -> STM ()
forall a. TBMQueue a -> a -> STM ()
writeTBMQueue TBMQueue (Loc, LogSource, LogLevel, LogStr)
queue (Loc
logLoc, LogSource
logSource, LogLevel
logLevel, LogStr
logStr)
unTBMQueueLoggingT
:: (MonadIO m, MonadLogger m)
=> TBMQueue (Loc, LogSource, LogLevel, LogStr)
-> m ()
unTBMQueueLoggingT :: TBMQueue (Loc, LogSource, LogLevel, LogStr) -> m ()
unTBMQueueLoggingT TBMQueue (Loc, LogSource, LogLevel, LogStr)
queue = do
Maybe (Loc, LogSource, LogLevel, LogStr)
mLine <- IO (Maybe (Loc, LogSource, LogLevel, LogStr))
-> m (Maybe (Loc, LogSource, LogLevel, LogStr))
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Maybe (Loc, LogSource, LogLevel, LogStr))
-> m (Maybe (Loc, LogSource, LogLevel, LogStr)))
-> IO (Maybe (Loc, LogSource, LogLevel, LogStr))
-> m (Maybe (Loc, LogSource, LogLevel, LogStr))
forall a b. (a -> b) -> a -> b
$ STM (Maybe (Loc, LogSource, LogLevel, LogStr))
-> IO (Maybe (Loc, LogSource, LogLevel, LogStr))
forall a. STM a -> IO a
atomically (STM (Maybe (Loc, LogSource, LogLevel, LogStr))
-> IO (Maybe (Loc, LogSource, LogLevel, LogStr)))
-> STM (Maybe (Loc, LogSource, LogLevel, LogStr))
-> IO (Maybe (Loc, LogSource, LogLevel, LogStr))
forall a b. (a -> b) -> a -> b
$ TBMQueue (Loc, LogSource, LogLevel, LogStr)
-> STM (Maybe (Loc, LogSource, LogLevel, LogStr))
forall a. TBMQueue a -> STM (Maybe a)
readTBMQueue TBMQueue (Loc, LogSource, LogLevel, LogStr)
queue
case Maybe (Loc, LogSource, LogLevel, LogStr)
mLine of
Maybe (Loc, LogSource, LogLevel, LogStr)
Nothing -> () -> m ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
Just (Loc
loc,LogSource
src,LogLevel
lvl,LogStr
msg) -> do
Loc -> LogSource -> LogLevel -> LogStr -> m ()
forall (m :: * -> *) msg.
(MonadLogger m, ToLogStr msg) =>
Loc -> LogSource -> LogLevel -> msg -> m ()
monadLoggerLog Loc
loc LogSource
src LogLevel
lvl LogStr
msg
TBMQueue (Loc, LogSource, LogLevel, LogStr) -> m ()
forall (m :: * -> *).
(MonadIO m, MonadLogger m) =>
TBMQueue (Loc, LogSource, LogLevel, LogStr) -> m ()
unTBMQueueLoggingT TBMQueue (Loc, LogSource, LogLevel, LogStr)
queue
stashJsonLine :: (Loc, LogSource, LogLevel, LogStr)
-> ReaderT LogstashConnection IO ()
stashJsonLine :: (Loc, LogSource, LogLevel, LogStr)
-> ReaderT LogstashConnection IO ()
stashJsonLine = Value -> ReaderT LogstashConnection IO ()
forall (m :: * -> *) a.
(MonadIO m, ToJSON a) =>
a -> ReaderT LogstashConnection m ()
L.stashJsonLine (Value -> ReaderT LogstashConnection IO ())
-> ((Loc, LogSource, LogLevel, LogStr) -> Value)
-> (Loc, LogSource, LogLevel, LogStr)
-> ReaderT LogstashConnection IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Loc, LogSource, LogLevel, LogStr) -> Value
jsonLogLine
jsonLogLine :: (Loc, LogSource, LogLevel, LogStr) -> Value
jsonLogLine :: (Loc, LogSource, LogLevel, LogStr) -> Value
jsonLogLine (Loc
loc, LogSource
src, LogLevel
lvl, LogStr
msg) = [Pair] -> Value
object
[ Key
"message" Key -> LogSource -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= ByteString -> LogSource
decodeUtf8 (LogStr -> ByteString
fromLogStr LogStr
msg)
, Key
"log" Key -> Value -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= [Pair] -> Value
object
[ Key
"logger" Key -> LogSource -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= LogSource
src
, Key
"level" Key -> LogSource -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= LogLevel -> LogSource
jsonLogLevel LogLevel
lvl
, Key
"origin" Key -> Value -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= [Pair] -> Value
object
[ Key
"file" Key -> Value -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= [Pair] -> Value
object
[ Key
"name" Key -> String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Loc -> String
loc_filename Loc
loc
, Key
"line" Key -> Int -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= (Int, Int) -> Int
forall a b. (a, b) -> a
fst (Loc -> (Int, Int)
loc_start Loc
loc)
, Key
"package" Key -> String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Loc -> String
loc_package Loc
loc
, Key
"module" Key -> String -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Loc -> String
loc_module Loc
loc
, Key
"start" Key -> Value -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= (Int, Int) -> Value
jsonCharPos (Loc -> (Int, Int)
loc_start Loc
loc)
, Key
"end" Key -> Value -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= (Int, Int) -> Value
jsonCharPos (Loc -> (Int, Int)
loc_end Loc
loc)
]
]
]
]
where jsonLogLevel :: LogLevel -> Text
jsonLogLevel :: LogLevel -> LogSource
jsonLogLevel LogLevel
LevelDebug = LogSource
"debug"
jsonLogLevel LogLevel
LevelInfo = LogSource
"info"
jsonLogLevel LogLevel
LevelWarn = LogSource
"warn"
jsonLogLevel LogLevel
LevelError = LogSource
"error"
jsonLogLevel (LevelOther LogSource
x) = LogSource
x
jsonCharPos :: (Int, Int) -> Value
jsonCharPos :: (Int, Int) -> Value
jsonCharPos (Int
line, Int
column) =
[Pair] -> Value
object [ Key
"line" Key -> Int -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Int
line, Key
"column" Key -> Int -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Key -> v -> kv
.= Int
column ]