@@ -5,6 +5,7 @@ module Katip.Scribes.Handle where
55-------------------------------------------------------------------------------
66import Control.Applicative as A
77import Control.Monad
8+import Control.Exception (onException)
89import Data.Aeson
910import qualified Data.HashMap.Strict as HM
1011import Data.Monoid
@@ -61,19 +62,27 @@ data WorkerCmd =
6162-- > [2016-05-11 21:01:15][MyApp][Info][myhost.example.com][1724][ThreadId 1154][main:Helpers.Logging Helpers/Logging.hs:32:7] Started
6263-- > [2016-05-11 21:01:15][MyApp.confrabulation][Debug][myhost.example.com][1724][ThreadId 1154][confrab_factor:42.0][main:Helpers.Logging Helpers/Logging.hs:41:9] Confrabulating widgets, with extra namespace and context
6364-- > [2016-05-11 21:01:15][MyApp][Info][myhost.example.com][1724][ThreadId 1154][main:Helpers.Logging Helpers/Logging.hs:43:7] Namespace and context are back to normal
64−mkHandleScribe :: ColorStrategy -> Handle -> Severity -> Verbosity -> IO Scribe
65+--
66+-- Returns the newly-created `Scribe` together with a finaliser the user needs to run to perform resource cleanup.
67+mkHandleScribe :: ColorStrategy -> Handle -> Severity -> Verbosity -> IO (Scribe, IO ())
6568mkHandleScribe cs h sev verb = do
6669 (inChan, outChan) <- U.newChan 4096
67− -- TODO: Come up with a good story for resource cleanup.
68− _ <- async $ workerLoop outChan
69− hSetBuffering h LineBuffering
70− colorize <- case cs of
71− ColorIfTerminal -> hIsTerminalDevice h
72− ColorLog b -> return b
73− return $ Scribe $ \i -> when (permitItem sev i) $ do
74− void (U.tryWriteChan inChan (NewItem (formatItem colorize verb i)))
70+ worker <- async $ workerLoop outChan
71+ flip onException (stopWorker worker inChan) $ do
72+ hSetBuffering h LineBuffering
73+ colorize <- case cs of
74+ ColorIfTerminal -> hIsTerminalDevice h
75+ ColorLog b -> return b
76+ let scribe = Scribe $ \i ->
77+ when (permitItem sev i) $ void (U.tryWriteChan inChan (NewItem (formatItem colorize verb i)))
78+ return (scribe, stopWorker worker inChan)
7579
7680 where
81+ stopWorker :: Async () -> U.InChan WorkerCmd -> IO ()
82+ stopWorker worker inChan = do
83+ U.writeChan inChan PoisonPill
84+ wait worker
85+
7786 workerLoop :: U.OutChan WorkerCmd -> IO ()
7887 workerLoop outChan = do
7988 newCmd <- U.readChan outChan
@@ -114,10 +123,11 @@ formatItem withColor verb Item{..} =
114123
115124-------------------------------------------------------------------------------
116125-- | An implicit environment to enable logging directly ouf of the IO monad.
126+-- Be careful as this LogEnv won't perform any resource cleanup for you.
117127_ioLogEnv :: LogEnv
118128_ioLogEnv = unsafePerformIO $ do
119129 le <- initLogEnv "io" "io"
120− lh <- mkHandleScribe ColorIfTerminal stdout DebugS V3
130+ (lh, _) <- mkHandleScribe ColorIfTerminal stdout DebugS V3
121131 return $ registerScribe "stdout" lh le
122132{-# NOINLINE _ioLogEnv #-}
123133