{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} module Logging.Global.Internal ( log , run ) where import Control.Exception import Control.Monad import Control.Monad.IO.Class import Data.IORef import Prelude hiding (log) import System.IO.Unsafe import Logging.Level import Logging.Logger import Logging.Manager import qualified Logging.Monad.Internal as M {-# NOINLINE ref #-} ref :: IORef Manager ref = unsafePerformIO $ newIORef $ error "Global logging manager is not set, see Logging.Global.run" log :: MonadIO m => Logger -> Level -> String -> (String, String, String, Int) -> m () log logger level message location = liftIO $ do manager <- readIORef ref M.runLoggingT (M.log logger level message location) manager {-| Run the global logging environment. You should always run you application in the global logging environment. @ main :: IO () main = run manager app app :: IO () app = do $(info) \"App\" "..." ... @ Never run multiple global logging environments concurrently. @ -- bad useage main :: IO () main = do forkIO $ run manager1 app1 forkIO $ run manager2 app2 ... -- correct useage main :: IO () main = run manager $ do forkIO app1 forkIO app2 ... @ -} run :: Manager -> IO a -> IO a run manager@Manager{..} io = do bracket_ (initialize manager >> atomicWriteIORef ref manager) (terminate manager) (runInner catchUncaughtException io) where unknownLoc = ("unknown file", "unknown package", "unknown module", 0) runInner :: Bool -> IO a -> IO a runInner False io = io runInner True io = catch io $ \e -> do log "" "ERROR" (show (e :: SomeException)) unknownLoc runInner True io