HORIZON HASKELLDocslts/ghc-9.10.x248f8f02026-10-05Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · 248f8f0 · 2026-10-05

Modulelog-base-0.12.0.1Haskell2010

Log.Logger

The Logger type of logging back-ends.

  • 2 types
  • 7 values
  • Packagelog-base-0.12.0.1
  • Exports9
  • LanguageHaskell2010
  • LicenceBSD-3-Clause
  • SourceLogger.hs
datadata Logger
#

An object used for communication with a logger thread that outputs LogMessages using e.g. PostgreSQL, Elasticsearch or stdout (depending on the back-end chosen).

Instances2Semigroup, Monoid
valuemkLogger :: Text -> (LogMessage -> IO ()) -> IO Logger
#

Start a logger thread that consumes one queued message at a time.

Note: a bounded queue of size 1000000 is used internally to avoid unrestricted memory consumption.

valuemkBulkLogger :: Text -> ([LogMessage] -> IO ()) -> IO () -> IO Logger
#

Start an asynchronous logger thread that consumes all queued messages once per second.

Note: a bounded queue of size 1000000 is used internally to avoid unrestricted memory consumption.

To make sure that the messages get written out in the presence of exceptions, use high-level wrappers like withLogger, Log.Backend.ElasticSearch.withElasticSearchLogger or withBulkStdOutLogger instead of this function directly.

Note: some messages can be lost when the main thread shuts down without making sure that all logger threads have written out all messages, because in that case child threads are not given a chance to clean up by the RTS. This is apparently a feature: https://mail.haskell.org/pipermail/haskell-cafe/2014-February/112754.html

To work around this issue, make sure that the main thread doesn't exit until all its children have terminated. The async package makes this easy.

Problematic example:

import Control.Concurrent.Async

main :: IO ()
main = do
   logger <- Log.Backend.ElasticSearch.elasticSearchLogger
   a <- Control.Concurrent.Async.async (Log.Backend.ElasticSearch.withElasticSearchLogger $ \logger ->
               runLogT "main" logger defaultLogLevel $ logTrace_ "foo")
   -- Main thread exits without waiting for the child
   -- to finish and without giving the child a chance
   -- to do proper cleanup.

Fixed example:

import Control.Concurrent.Async

main :: IO ()
main = do
   logger <- Log.Backend.ElasticSearch.elasticSearchLogger
   a <- Control.Concurrent.Async.async (Log.Backend.ElasticSearch.withElasticSearchLogger $ \logger ->
               runLogT "main" logger defaultLogLevel $ logTrace_ "foo")
   Control.Concurrent.Async.wait a
   -- Main thread waits for the child to finish, giving
   -- it a chance to shut down properly. This works even
   -- in the presence of exceptions in the child thread.
valueshutdownLogger :: Logger -> IO ()
#

Shutdown the logger thread associated with this Logger object. Subsequent attempts to write messages via this Logger will result in an exception.