{-# LANGUAGE OverloadedStrings, TypeSynonymInstances, FlexibleInstances, ExistentialQuantification, TypeFamilies, GeneralizedNewtypeDeriving, StandaloneDeriving, MultiParamTypeClasses, UndecidableInstances #-}
module System.Log.Heavy.Backends.Dynamic
(
DynamicBackend,
DynamicBackendHandle,
newDynamicBackendHandle,
updateDynamicBackendSettings,
LogBackendSettings (..),
FilteringM, filteringM, excludingM
) where
import Control.Monad (when)
import Control.Concurrent
import Control.Concurrent.STM
import System.Log.Heavy.Types
import System.Log.Heavy.Util
data DynamicBackendHandle = DynamicBackendHandle {
dbhBroadcast :: TChan LoggingSettings
, dbhDefault :: LoggingSettings
}
newDynamicBackendHandle :: LoggingSettings
-> IO DynamicBackendHandle
newDynamicBackendHandle settings = do
broadcast <- newBroadcastTChanIO
return $ DynamicBackendHandle broadcast settings
updateDynamicBackendSettings :: DynamicBackendHandle
-> LoggingSettings
-> IO ()
updateDynamicBackendSettings handle settings = do
atomically $ writeTChan (dbhBroadcast handle) settings
data DynamicBackend = DynamicBackend {
dbCurrentBackend :: MVar AnyLogBackend
, dbNewSettings :: TChan LoggingSettings
}
instance IsLogBackend DynamicBackend where
data LogBackendSettings DynamicBackend = DynamicSettings DynamicBackendHandle
initLogBackend (DynamicSettings (DynamicBackendHandle broadcast (LoggingSettings dfltSettings))) = do
mySettingsChan <- atomically $ dupTChan broadcast
backend <- initLogBackend dfltSettings
backendVar <- newMVar (AnyLogBackend backend)
return $ DynamicBackend backendVar mySettingsChan
cleanupLogBackend (DynamicBackend backendVar _) = do
backend <- takeMVar backendVar
cleanupLogBackend backend
wouldWriteMessage (DynamicBackend backendVar _) msg = do
backend <- readMVar backendVar
wouldWriteMessage backend msg
makeLogger (DynamicBackend backendVar settingsChan) msg = do
mbNewSettings <- atomically $ tryReadTChan settingsChan
case mbNewSettings of
Nothing -> do
backend <- readMVar backendVar
makeLogger backend msg
Just (LoggingSettings newSettings) -> do
oldBackend <- takeMVar backendVar
cleanupLogBackend oldBackend
newBackend <- initLogBackend newSettings
putMVar backendVar (AnyLogBackend newBackend)
makeLogger newBackend msg
data FilteringM b = FilteringBackendM (MVar (LogMessage -> Bool)) b
filteringM :: IsLogBackend b => LogFilter -> LogBackendSettings b -> IO (LogBackendSettings (FilteringM b))
filteringM fltr b = do
fltrVar <- newMVar (checkLogLevel fltr)
return $ FilteringM fltrVar b
excludingM :: IsLogBackend b => LogFilter -> LogBackendSettings b -> IO (LogBackendSettings (FilteringM b))
excludingM fltr b = do
fltrVar <- newMVar ex
return $ FilteringM fltrVar b
where
ex msg = not $ checkContextFilter' [LogContextFilter Nothing (Just fltr)] (lmSource msg) (lmLevel msg)
instance IsLogBackend b => IsLogBackend (FilteringM b) where
data LogBackendSettings (FilteringM b) =
FilteringM (MVar (LogMessage -> Bool)) (LogBackendSettings b)
wouldWriteMessage (FilteringBackendM fltrVar _) msg = do
fltr <- readMVar fltrVar
return $ fltr msg
makeLogger (FilteringBackendM fltrVar backend) msg = do
fltr <- readMVar fltrVar
when (fltr msg) $ do
makeLogger backend msg
initLogBackend (FilteringM fltrVar settings) = do
backend <- initLogBackend settings
return $ FilteringBackendM fltrVar backend
cleanupLogBackend (FilteringBackendM _ backend) = cleanupLogBackend backend