freckle-app-1.2.0.0: library/Freckle/App/Test/Logging.hs
{-# LANGUAGE CPP #-}
module Freckle.App.Test.Logging
( MonadLogger
, LoggingT
, runCapturedLoggingT
, logLineToJSON
, logLineToByteString
, logLineToText
) where
import Freckle.App.Prelude
import Control.Concurrent.Chan
import Control.Monad.Logger
import Data.Aeson
import Data.ByteString (ByteString)
import qualified Data.ByteString.Lazy as BSL
import Data.DList (DList)
import qualified Data.DList as DList
import UnliftIO.Async
import UnliftIO.Exception (finally)
#if !MIN_VERSION_monad_logger(0,3,32)
type LogLine = (Loc, LogSource, LogLevel, LogStr)
#endif
-- | Run a 'LoggingT', capturing and returning any logged messages alongside
--
-- This is 'runWriterLoggingT', but we're not able to supply a 'MonadUnliftIO'
-- instance when using that.
--
runCapturedLoggingT :: MonadUnliftIO m => LoggingT m a -> m (a, [LogLine])
runCapturedLoggingT f = do
chan <- liftIO newChan
x <- async $ captureLog DList.empty chan
a <- runChanLoggingT chan $ f `finally` logInfoN doneMessage
msgs <- wait x
pure (a, DList.toList msgs)
captureLog :: MonadIO m => DList LogLine -> Chan LogLine -> m (DList LogLine)
captureLog acc chan = do
ll <- liftIO $ readChan chan
let txt = logLineToText ll
if txt == doneMessage then pure acc else captureLog (DList.snoc acc ll) chan
doneMessage :: Text
doneMessage = "%DONE%"
logLineToJSON :: FromJSON a => LogLine -> Maybe a
logLineToJSON = decode . BSL.fromStrict . logLineToByteString
logLineToByteString :: LogLine -> ByteString
logLineToByteString (_, _, _, str) = fromLogStr str
logLineToText :: LogLine -> Text
logLineToText = decodeUtf8 . logLineToByteString