--
-- Data vault for metrics
--
-- Copyright © 2013-2014 Anchor Systems, Pty Ltd and Others
--
-- The code in this file, and the program it is a part of, is
-- made available to you by its authors as open source software:
-- you can redistribute it and/or modify it under the terms of
-- the 3-clause BSD licence.
--
--
-- | Common program initalization for Vaultaire binaries
--
module Vaultaire.Program
(
initializeProgram,
Verbosity(..)
)
where
import Control.Concurrent.MVar
import Control.Monad
import GHC.Conc
import System.Environment
import System.IO (hFlush, hPutStrLn, stdout)
import System.Log.Formatter
import System.Log.Handler (setFormatter)
import System.Log.Handler.Simple
import System.Log.Logger
import System.Posix.Signals
--
-- Main program entry point
--
interruptHandler :: MVar () -> Handler
interruptHandler semaphore = Catch $ do
putStrLn "\nInterrupt"
hFlush stdout
putMVar semaphore ()
terminateHandler :: MVar () -> Handler
terminateHandler semaphore = Catch $ do
putStrLn "Terminating"
hFlush stdout
putMVar semaphore ()
quitHandler :: Handler
quitHandler = Catch $ do
putStrLn ""
hFlush stdout
logger <- getLogger rootLoggerName
let level = getLevel logger
level' = case level of
Just DEBUG -> INFO
Just INFO -> DEBUG
_ -> DEBUG
logger' = setLevel level' logger
saveGlobalLogger logger'
infoM "Main.quitHandler" ("Change log level to " ++ show level')
data Verbosity = Debug | Normal | Quiet deriving Show
--
-- | Initialize a program. Call this from your 'main' program entry point
-- before doing anything else. Indicate the logging verbosity you want, along
-- with an identification of your program. Returns an MVar which will be set to
-- unit if one of the installed signal handlers catches a signal and requests a
-- shutdown as a result.
--
initializeProgram :: String -> Verbosity -> IO (MVar ())
initializeProgram banner verbosity = do
-- Indicate startup
name <- getProgName
case verbosity of
Quiet -> return ()
_ -> putStrLn $ name ++ " (" ++ banner ++ ") starting"
-- command line +RTS -Nn -RTS value
when (numCapabilities == 1) (getNumProcessors >>= setNumCapabilities)
-- Start and configure logger, deleting the default handler in favour of
-- our own formatter outputting to stdout with timestamps. Run in Zulu time.
setEnv "TZ" "UTC"
let level = case verbosity of
Debug -> DEBUG
Normal -> INFO
Quiet -> WARNING
logger <- getRootLogger
handler <- streamHandler stdout DEBUG
let handler' = setFormatter handler (tfLogFormatter "%Y-%m-%dT%H:%M:%SZ" "$time $msg")
let logger' = (setHandlers [handler'] . setLevel level) logger
saveGlobalLogger logger'
debugM "Program.initialize" "Logging initialized"
quit <- newEmptyMVar
_ <- installHandler sigINT (interruptHandler quit) Nothing
_ <- installHandler sigTERM (terminateHandler quit) Nothing
_ <- installHandler sigQUIT quitHandler Nothing
debugM "Program.initialize" "Signal handlers installed"
return quit