Skip to content

Logging #15

Open
Open
@chris-martin

Description

@chris-martin

I like concurrent logging as the subject as a Phrasebook example because it's a common need and a good excuse to concisely put together a lot of topics.

Here's some code that comes straight out of the repo for the Type Classes server. It probably contains a few too many topics and needs to be significantly simplified and better focused.

  • Starting threads with withAsync
  • Concurrent queues TQueue
  • Catching exceptions with catchAny
  • Cleaning up after interrupts with finally
  • Introducing strictness with ($!)
import Control.Concurrent.Async (withAsync)
import Control.Concurrent.STM
import Control.Exception.Safe (Exception (displayException), catchAny, finally)
import Control.Monad (forever)
import Control.Monad.Trans.Cont
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.IO as Text
import System.IO (stderr)

data Log =
  Log
    { logText :: Text -> IO ()
    , logString :: String -> IO ()
    }

withLogging :: ContT a IO Log
withLogging = ContT \continue ->
  do
    q <- atomically newTQueue

    let
        logText msg = atomically (writeTQueue q $! msg)
        logString = logText . Text.pack
        l = Log {..}

    withAsync (runLogger q) \_ -> (continue l)

runLogger :: TQueue Text -> IO ()
runLogger q = finally runForever runUntilEmpty
  where
    runForever = forever $ atomically (readTQueue q) >>= write

    runUntilEmpty =
        atomically (tryReadTQueue q) >>=
        \case
            Nothing -> return ()
            Just msg -> write msg *> runUntilEmpty

    write msg = Text.hPutStrLn stderr msg

recover :: Log -> IO a -> IO (Maybe a)
recover log a = catchAny (fmap Just a) (\e -> logException log e *> return Nothing)

logException :: Exception e => Log -> e -> IO ()
logException log e = logString log (displayException e)

Metadata

Metadata

Assignees

No one assigned

    Labels

    good for new contributorsPull requests welcome!new exampleThis issue is about writing a new example program.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions