module Yore.Log (Yore.Log.error, info, setup) where import Control.Monad.IO.Class (MonadIO (..)) import Data.Time (ZonedTime, getZonedTime) import Data.Time.Format (defaultTimeLocale, formatTime) import GHC.Stack (HasCallStack, SrcLoc (..), callStack, getCallStack) import System.IO (BufferMode (..), hSetBuffering, stdout) import Text.Printf (printf) import qualified Data.Text as Text import qualified Data.Text.IO as TextIO setup :: IO () setup = hSetBuffering stdout LineBuffering info :: (HasCallStack, MonadIO m) => String -> m () info = doLog "INF" error :: (HasCallStack, MonadIO m) => String -> m () error = doLog "ERR" doLog :: (HasCallStack, MonadIO m) => String -> String -> m () doLog level msg = liftIO $ do now <- getZonedTime let location = getLocation $ getCallStack callStack TextIO.putStrLn $ Text.pack $ printf "(%s) (%s) (%s) %s" (iso8601Show now) level location msg where getLocation :: [(String, SrcLoc)] -> String -- First entry is always a function from this module, skip it getLocation (_ : (_, srcLoc) : _) = printf "%s:%d" (srcLocFile srcLoc) (srcLocStartLine srcLoc) getLocation _ = "" -- | Unlike 'Data.Time.Format.ISO8601.iso8601Show', this function -- aligns the second decimals. This is purely for asthetic reasons. iso8601Show :: ZonedTime -> String iso8601Show = formatTime defaultTimeLocale "%FT%T%02Q%Ez"