@@ -53,14 +53,15 @@ module Colog.Concurrent
5353 -- $worker-thread-usage
5454 ) where
5555
56- import Control.Applicative (many )
56+ import Control.Applicative (many , (<|>) , some )
5757import Control.Concurrent (forkFinally , killThread )
58- import Control.Concurrent.STM (atomically , check , newTVarIO , readTVar , writeTVar )
58+ import Control.Concurrent.STM (STM , atomically , check , newTVarIO , readTVar , writeTVar )
5959import Control.Concurrent.STM.TBQueue (newTBQueueIO , readTBQueue , writeTBQueue )
6060import Control.Exception (bracket , finally )
6161import Control.Monad (forever , join )
6262import Control.Monad.IO.Class (MonadIO (.. ))
6363import Data.Foldable (for_ )
64+ import Numeric.Natural (Natural )
6465
6566import Colog.Concurrent.Internal (BackgroundWorker (.. ), Capacity (.. ), mkCapacity )
6667import Colog.Core.Action (LogAction (.. ))
@@ -140,12 +141,16 @@ See 'forkBackgroundLogger' for more details.
140141application state or thread info, so you should only pass methods that serialize
141142and dump data there.
142143
144+ @IO ()@ - flush provides a function to flush all the logs, it allows flush logs
145+ by chunks, so @LogAction@ may not care about flushing.
146+
143147@
144148main :: IO ()
145149main =
146150 'withBackgroundLogger'
147151 'defCapacity'
148152 'Colog.Actions.logByteStringStdout'
153+ '(pure ())
149154 (\log -> 'Colog.Monad.usingLoggerT' log $ __do__
150155 'Colog.Monad.logMsg' \@ByteString "Starting application..."
151156 'Colog.Monad.logMsg' \@ByteString "Finishing application..."
@@ -156,16 +161,17 @@ withBackgroundLogger
156161 :: MonadIO m
157162 => Capacity -- ^ Capacity of messages to handle; bounded channel size
158163 -> LogAction IO msg -- ^ Action that will be used in a forked thread
164+ -> IO () -- ^ Action to flush logs
159165 -> (LogAction m msg -> IO a ) -- ^ Continuation action
160166 -> IO a
161- withBackgroundLogger cap logger action =
162- bracket (forkBackgroundLogger cap logger)
167+ withBackgroundLogger cap logger flush action =
168+ bracket (forkBackgroundLogger cap logger flush )
163169 killBackgroundLogger
164170 (action . convertToLogAction)
165171
166172-- | Default capacity size, (4096)
167173defCapacity :: Capacity
168- defCapacity = Capacity 4096
174+ defCapacity = Capacity 4096 ( Just 32 )
169175
170176
171177{- $extended-api
@@ -218,19 +224,30 @@ __N.B.__ On exit, even in case of exception thread will dump all values
218224that are in the queue. But it will stop doing that in case if another
219225exception will happen.
220226-}
221- forkBackgroundLogger :: Capacity -> LogAction IO msg -> IO (BackgroundWorker msg )
222- forkBackgroundLogger (Capacity cap) logAction = do
227+ forkBackgroundLogger :: Capacity -> LogAction IO msg -> IO () -> IO ( BackgroundWorker msg )
228+ forkBackgroundLogger (Capacity cap lim ) logAction flush = do
223229 queue <- newTBQueueIO cap
224230 isAlive <- newTVarIO True
225231 tid <- forkFinally
226232 (forever $ do
227- msg <- atomically $ readTBQueue queue
228- unLogAction logAction msg)
233+ msgs <- atomically $ fetch $ readTBQueue queue
234+ for_ msgs $ unLogAction logAction
235+ flush)
229236 (\ _ ->
230237 (do msgs <- atomically $ many $ readTBQueue queue
231- for_ msgs $ unLogAction logAction)
238+ for_ msgs $ unLogAction logAction
239+ flush)
232240 `finally` atomically (writeTVar isAlive False ))
233241 pure $ BackgroundWorker tid (writeTBQueue queue) isAlive
242+ where
243+ fetch
244+ | Just n <- lim = someN n
245+ | otherwise = some
246+ someN :: Natural -> STM a -> STM [a ]
247+ someN 0 _ = pure []
248+ someN n f = (:) <$> f <*> go n where
249+ go 0 = pure []
250+ go k = ((:) <$> f <*> go (k- 1 )) <|> pure []
234251
235252
236253{- | Convert a given 'BackgroundWorker msg' into a 'LogAction msg'
@@ -280,9 +297,13 @@ happening.
280297When closed it will dump all pending messages, unless
281298another asynchronous exception will arrive, or synchronous
282299exception will happen during the logging.
300+
301+ Note. Limit parameter of capacity is ignored here as the function
302+ performs IO actions and seems that doesn't benefit from the chunking.
303+ However it may change in the future versions if proved to be wrong.
283304-}
284305mkBackgroundThread :: Capacity -> IO (BackgroundWorker (IO () ))
285- mkBackgroundThread (Capacity cap) = do
306+ mkBackgroundThread (Capacity cap _lim ) = do
286307 queue <- newTBQueueIO cap
287308 isAlive <- newTVarIO True
288309 tid <- forkFinally
0 commit comments