module Logger
(
Logger,
LogRecord,
LogQueue,
LogLevel(..),
newLogger,
postLog,
postLogBlocking,
postStop,
processLogRecords,
loggerSentryService
)
where
import SentryLogging (getCrashLogger, logCrashMessage)
import Config (Config, configSentryDSN, configDisableSentryLogging, configQueueCapacity)
import Control.Monad (unless, when, forM_)
import Control.Concurrent.STM (atomically)
import Control.Concurrent.STM.TBQueue (TBQueue, newTBQueue, readTBQueue, writeTBQueue, isFullTBQueue)
import Data.Text (Text, unpack)
import Prelude hiding (log)
import qualified System.Log.Raven.Types as Sentry
import qualified Data.Text.IO as T
type LogRecord = Text
data LogLevel = LogInfo | LogError
deriving (Eq, Ord, Show, Read)
type LogQueue = TBQueue LogCommand
data Logger = Logger { loggerQueue :: LogQueue, loggerSentryService :: Maybe Sentry.SentryService }
data LogCommand = LogRecord LogLevel LogRecord | LogStop
deriving (Eq, Ord, Show, Read)
newLogger :: Config -> IO Logger
newLogger config = Logger
<$> createQueue
<*> createSentryService
where
createQueue = atomically (newTBQueue (fromIntegral $ configQueueCapacity config))
createSentryService
| configDisableSentryLogging config = pure Nothing
| otherwise = traverse getCrashLogger (configSentryDSN config)
postLog :: Logger -> LogLevel -> LogRecord -> IO ()
postLog logger level record = atomically $ do
isFull <- isFullTBQueue (loggerQueue logger)
unless isFull $ writeTBQueue (loggerQueue logger) (LogRecord level record)
postLogBlocking :: Logger -> LogLevel -> LogRecord -> IO ()
postLogBlocking logger level record = atomically $
writeTBQueue (loggerQueue logger) (LogRecord level record)
postStop :: Logger -> IO ()
postStop logger = atomically $ writeTBQueue (loggerQueue logger) LogStop
processLogRecords :: Logger -> IO ()
processLogRecords logger = go
where
go = do
cmd <- atomically $ readTBQueue (loggerQueue logger)
case cmd of
LogRecord logLevel logRecord -> do
T.putStrLn logRecord
when (logLevel == LogError) (
forM_
(loggerSentryService logger)
(\service -> logCrashMessage "Icepeak" service (unpack logRecord))
)
go
LogStop -> pure ()