{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
module ELynx.Tools.Logger
( Verbosity (..),
HasLock (..),
HasLogHandles (..),
HasStartingTime (..),
HasVerbosity (..),
Logger,
logOutB,
logDebugB,
logDebugS,
logWarnB,
logWarnS,
logInfoB,
logInfoS,
logHeader,
logInfoHeader,
logInfoFooter,
logInfoNewSection,
)
where
import Control.Concurrent.MVar
import Control.Monad
import Control.Monad.IO.Class
import Control.Monad.Trans.Reader
import Data.Aeson.TH
import qualified Data.ByteString.Builder as BB
import qualified Data.ByteString.Lazy.Char8 as BL
import Data.List
import Data.Time
import Data.Version
import GHC.Generics
import Language.Haskell.TH
import Paths_elynx_tools
import System.Environment
import System.IO
data Verbosity = Quiet | Warn | Info | Debug
deriving (Verbosity
Verbosity -> Verbosity -> Bounded Verbosity
forall a. a -> a -> Bounded a
maxBound :: Verbosity
$cmaxBound :: Verbosity
minBound :: Verbosity
$cminBound :: Verbosity
Bounded, Int -> Verbosity
Verbosity -> Int
Verbosity -> [Verbosity]
Verbosity -> Verbosity
Verbosity -> Verbosity -> [Verbosity]
Verbosity -> Verbosity -> Verbosity -> [Verbosity]
(Verbosity -> Verbosity)
-> (Verbosity -> Verbosity)
-> (Int -> Verbosity)
-> (Verbosity -> Int)
-> (Verbosity -> [Verbosity])
-> (Verbosity -> Verbosity -> [Verbosity])
-> (Verbosity -> Verbosity -> [Verbosity])
-> (Verbosity -> Verbosity -> Verbosity -> [Verbosity])
-> Enum Verbosity
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: Verbosity -> Verbosity -> Verbosity -> [Verbosity]
$cenumFromThenTo :: Verbosity -> Verbosity -> Verbosity -> [Verbosity]
enumFromTo :: Verbosity -> Verbosity -> [Verbosity]
$cenumFromTo :: Verbosity -> Verbosity -> [Verbosity]
enumFromThen :: Verbosity -> Verbosity -> [Verbosity]
$cenumFromThen :: Verbosity -> Verbosity -> [Verbosity]
enumFrom :: Verbosity -> [Verbosity]
$cenumFrom :: Verbosity -> [Verbosity]
fromEnum :: Verbosity -> Int
$cfromEnum :: Verbosity -> Int
toEnum :: Int -> Verbosity
$ctoEnum :: Int -> Verbosity
pred :: Verbosity -> Verbosity
$cpred :: Verbosity -> Verbosity
succ :: Verbosity -> Verbosity
$csucc :: Verbosity -> Verbosity
Enum, Verbosity -> Verbosity -> Bool
(Verbosity -> Verbosity -> Bool)
-> (Verbosity -> Verbosity -> Bool) -> Eq Verbosity
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Verbosity -> Verbosity -> Bool
$c/= :: Verbosity -> Verbosity -> Bool
== :: Verbosity -> Verbosity -> Bool
$c== :: Verbosity -> Verbosity -> Bool
Eq, (forall x. Verbosity -> Rep Verbosity x)
-> (forall x. Rep Verbosity x -> Verbosity) -> Generic Verbosity
forall x. Rep Verbosity x -> Verbosity
forall x. Verbosity -> Rep Verbosity x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Verbosity x -> Verbosity
$cfrom :: forall x. Verbosity -> Rep Verbosity x
Generic, Eq Verbosity
Eq Verbosity
-> (Verbosity -> Verbosity -> Ordering)
-> (Verbosity -> Verbosity -> Bool)
-> (Verbosity -> Verbosity -> Bool)
-> (Verbosity -> Verbosity -> Bool)
-> (Verbosity -> Verbosity -> Bool)
-> (Verbosity -> Verbosity -> Verbosity)
-> (Verbosity -> Verbosity -> Verbosity)
-> Ord Verbosity
Verbosity -> Verbosity -> Bool
Verbosity -> Verbosity -> Ordering
Verbosity -> Verbosity -> Verbosity
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Verbosity -> Verbosity -> Verbosity
$cmin :: Verbosity -> Verbosity -> Verbosity
max :: Verbosity -> Verbosity -> Verbosity
$cmax :: Verbosity -> Verbosity -> Verbosity
>= :: Verbosity -> Verbosity -> Bool
$c>= :: Verbosity -> Verbosity -> Bool
> :: Verbosity -> Verbosity -> Bool
$c> :: Verbosity -> Verbosity -> Bool
<= :: Verbosity -> Verbosity -> Bool
$c<= :: Verbosity -> Verbosity -> Bool
< :: Verbosity -> Verbosity -> Bool
$c< :: Verbosity -> Verbosity -> Bool
compare :: Verbosity -> Verbosity -> Ordering
$ccompare :: Verbosity -> Verbosity -> Ordering
$cp1Ord :: Eq Verbosity
Ord, ReadPrec [Verbosity]
ReadPrec Verbosity
Int -> ReadS Verbosity
ReadS [Verbosity]
(Int -> ReadS Verbosity)
-> ReadS [Verbosity]
-> ReadPrec Verbosity
-> ReadPrec [Verbosity]
-> Read Verbosity
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [Verbosity]
$creadListPrec :: ReadPrec [Verbosity]
readPrec :: ReadPrec Verbosity
$creadPrec :: ReadPrec Verbosity
readList :: ReadS [Verbosity]
$creadList :: ReadS [Verbosity]
readsPrec :: Int -> ReadS Verbosity
$creadsPrec :: Int -> ReadS Verbosity
Read, Int -> Verbosity -> ShowS
[Verbosity] -> ShowS
Verbosity -> String
(Int -> Verbosity -> ShowS)
-> (Verbosity -> String)
-> ([Verbosity] -> ShowS)
-> Show Verbosity
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Verbosity] -> ShowS
$cshowList :: [Verbosity] -> ShowS
show :: Verbosity -> String
$cshow :: Verbosity -> String
showsPrec :: Int -> Verbosity -> ShowS
$cshowsPrec :: Int -> Verbosity -> ShowS
Show)
$(deriveJSON defaultOptions ''Verbosity)
class HasLock e where
getLock :: e -> MVar ()
class HasLogHandles e where
getLogHandles :: e -> [Handle]
class HasStartingTime s where
getStartingTime :: s -> UTCTime
class HasVerbosity s where
getVerbosity :: s -> Verbosity
type Logger e a = ReaderT e IO a
msgPrepare :: BL.ByteString -> BL.ByteString -> BL.ByteString
msgPrepare :: ByteString -> ByteString -> ByteString
msgPrepare ByteString
pref ByteString
msg = ByteString -> [ByteString] -> ByteString
BL.intercalate ByteString
"\n" ([ByteString] -> ByteString) -> [ByteString] -> ByteString
forall a b. (a -> b) -> a -> b
$ (ByteString -> ByteString) -> [ByteString] -> [ByteString]
forall a b. (a -> b) -> [a] -> [b]
map (ByteString -> ByteString -> ByteString
BL.append ByteString
pref) ([ByteString] -> [ByteString]) -> [ByteString] -> [ByteString]
forall a b. (a -> b) -> a -> b
$ ByteString -> [ByteString]
BL.lines ByteString
msg
atomicAction :: HasLock e => IO () -> Logger e ()
atomicAction :: IO () -> Logger e ()
atomicAction IO ()
a = do
MVar ()
l <- (e -> MVar ()) -> ReaderT e IO (MVar ())
forall (m :: * -> *) r a. Monad m => (r -> a) -> ReaderT r m a
reader e -> MVar ()
forall e. HasLock e => e -> MVar ()
getLock
IO () -> Logger e ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Logger e ()) -> IO () -> Logger e ()
forall a b. (a -> b) -> a -> b
$ MVar () -> (() -> IO ()) -> IO ()
forall a b. MVar a -> (a -> IO b) -> IO b
withMVar MVar ()
l (IO () -> () -> IO ()
forall a b. a -> b -> a
const IO ()
a)
logOutB ::
(HasLogHandles e, HasLock e) =>
BL.ByteString ->
BL.ByteString ->
Logger e ()
logOutB :: ByteString -> ByteString -> Logger e ()
logOutB ByteString
pref ByteString
msg = do
[Handle]
hs <- (e -> [Handle]) -> ReaderT e IO [Handle]
forall (m :: * -> *) r a. Monad m => (r -> a) -> ReaderT r m a
reader e -> [Handle]
forall e. HasLogHandles e => e -> [Handle]
getLogHandles
(Handle -> Logger e ()) -> [Handle] -> Logger e ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (IO () -> Logger e ()
forall e. HasLock e => IO () -> Logger e ()
atomicAction (IO () -> Logger e ())
-> (Handle -> IO ()) -> Handle -> Logger e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Handle -> ByteString -> IO ()
`BL.hPutStrLn` ByteString
msg')) [Handle]
hs
where
msg' :: ByteString
msg' = ByteString -> ByteString -> ByteString
msgPrepare ByteString
pref ByteString
msg
logDebugA :: (HasLock e, HasLogHandles e, HasVerbosity e) => Logger e () -> Logger e ()
logDebugA :: Logger e () -> Logger e ()
logDebugA Logger e ()
a = (e -> Verbosity) -> ReaderT e IO Verbosity
forall (m :: * -> *) r a. Monad m => (r -> a) -> ReaderT r m a
reader e -> Verbosity
forall s. HasVerbosity s => s -> Verbosity
getVerbosity ReaderT e IO Verbosity -> (Verbosity -> Logger e ()) -> Logger e ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Verbosity
v -> Bool -> Logger e () -> Logger e ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Verbosity
v Verbosity -> Verbosity -> Bool
forall a. Ord a => a -> a -> Bool
>= Verbosity
Debug) Logger e ()
a
logDebugB :: (HasLock e, HasLogHandles e, HasVerbosity e) => BL.ByteString -> Logger e ()
logDebugB :: ByteString -> Logger e ()
logDebugB = Logger e () -> Logger e ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
Logger e () -> Logger e ()
logDebugA (Logger e () -> Logger e ())
-> (ByteString -> Logger e ()) -> ByteString -> Logger e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString -> Logger e ()
forall e.
(HasLogHandles e, HasLock e) =>
ByteString -> ByteString -> Logger e ()
logOutB ByteString
"D: "
logDebugS :: (HasLock e, HasLogHandles e, HasVerbosity e) => String -> Logger e ()
logDebugS :: String -> Logger e ()
logDebugS = ByteString -> Logger e ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logDebugB (ByteString -> Logger e ())
-> (String -> ByteString) -> String -> Logger e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ByteString
BL.pack
logWarnA :: (HasLogHandles e, HasVerbosity e) => Logger e () -> Logger e ()
logWarnA :: Logger e () -> Logger e ()
logWarnA Logger e ()
a = (e -> Verbosity) -> ReaderT e IO Verbosity
forall (m :: * -> *) r a. Monad m => (r -> a) -> ReaderT r m a
reader e -> Verbosity
forall s. HasVerbosity s => s -> Verbosity
getVerbosity ReaderT e IO Verbosity -> (Verbosity -> Logger e ()) -> Logger e ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Verbosity
v -> Bool -> Logger e () -> Logger e ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Verbosity
v Verbosity -> Verbosity -> Bool
forall a. Ord a => a -> a -> Bool
>= Verbosity
Warn) Logger e ()
a
logWarnB :: (HasLock e, HasLogHandles e, HasVerbosity e) => BL.ByteString -> Logger e ()
logWarnB :: ByteString -> Logger e ()
logWarnB = Logger e () -> Logger e ()
forall e.
(HasLogHandles e, HasVerbosity e) =>
Logger e () -> Logger e ()
logWarnA (Logger e () -> Logger e ())
-> (ByteString -> Logger e ()) -> ByteString -> Logger e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString -> Logger e ()
forall e.
(HasLogHandles e, HasLock e) =>
ByteString -> ByteString -> Logger e ()
logOutB ByteString
"W: "
logWarnS :: (HasLock e, HasLogHandles e, HasVerbosity e) => String -> Logger e ()
logWarnS :: String -> Logger e ()
logWarnS = ByteString -> Logger e ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logWarnB (ByteString -> Logger e ())
-> (String -> ByteString) -> String -> Logger e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ByteString
BL.pack
logInfoA :: (HasLogHandles e, HasVerbosity e) => Logger e () -> Logger e ()
logInfoA :: Logger e () -> Logger e ()
logInfoA Logger e ()
a = (e -> Verbosity) -> ReaderT e IO Verbosity
forall (m :: * -> *) r a. Monad m => (r -> a) -> ReaderT r m a
reader e -> Verbosity
forall s. HasVerbosity s => s -> Verbosity
getVerbosity ReaderT e IO Verbosity -> (Verbosity -> Logger e ()) -> Logger e ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Verbosity
v -> Bool -> Logger e () -> Logger e ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Verbosity
v Verbosity -> Verbosity -> Bool
forall a. Ord a => a -> a -> Bool
>= Verbosity
Info) Logger e ()
a
logInfoB :: (HasLock e, HasLogHandles e, HasVerbosity e) => BL.ByteString -> Logger e ()
logInfoB :: ByteString -> Logger e ()
logInfoB = Logger e () -> Logger e ()
forall e.
(HasLogHandles e, HasVerbosity e) =>
Logger e () -> Logger e ()
logInfoA (Logger e () -> Logger e ())
-> (ByteString -> Logger e ()) -> ByteString -> Logger e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString -> Logger e ()
forall e.
(HasLogHandles e, HasLock e) =>
ByteString -> ByteString -> Logger e ()
logOutB ByteString
" "
logInfoS :: (HasLock e, HasLogHandles e, HasVerbosity e) => String -> Logger e ()
logInfoS :: String -> Logger e ()
logInfoS = ByteString -> Logger e ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB (ByteString -> Logger e ())
-> (String -> ByteString) -> String -> Logger e ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ByteString
BL.pack
versionString :: String
versionString :: String
versionString = String
"ELynx Suite version " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Version -> String
showVersion Version
version String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"."
copyrightString :: String
copyrightString :: String
copyrightString = String
"Developed by Dominik Schrempf."
compilationString :: String
compilationString :: String
compilationString =
String
"Compiled on "
String -> ShowS
forall a. [a] -> [a] -> [a]
++ $( stringE
=<< runIO
( formatTime defaultTimeLocale "%B %-e, %Y, at %H:%M %P, %Z."
`fmap` getCurrentTime
)
)
logHeader :: [String]
= [String
versionString, String
copyrightString, String
compilationString]
alignRightWithNoTrim :: Char -> Int -> BL.ByteString -> BL.ByteString
alignRightWithNoTrim :: Char -> Int -> ByteString -> ByteString
alignRightWithNoTrim Char
c Int
n ByteString
s = Int64 -> Char -> ByteString
BL.replicate (Int -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n Int64 -> Int64 -> Int64
forall a. Num a => a -> a -> a
- Int64
l) Char
c ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
s
where
l :: Int64
l = ByteString -> Int64
BL.length ByteString
s
renderDuration :: NominalDiffTime -> BL.ByteString
renderDuration :: NominalDiffTime -> ByteString
renderDuration NominalDiffTime
dt = ByteString
hTxt ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
mTxt ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
sTxt
where
hTxt :: ByteString
hTxt = Int -> ByteString
renderDecimal Int
h ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
":"
mTxt :: ByteString
mTxt = Int -> ByteString
renderDecimal Int
m ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
":"
sTxt :: ByteString
sTxt = Int -> ByteString
renderDecimal Int
s
(Int
h, Int
hRem) = Int
ts Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
3600
(Int
m, Int
s) = Int
hRem Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
60
ts :: Int
ts :: Int
ts = NominalDiffTime -> Int
forall a b. (RealFrac a, Integral b) => a -> b
round NominalDiffTime
dt
renderDecimal :: Int -> ByteString
renderDecimal Int
n = Char -> Int -> ByteString -> ByteString
alignRightWithNoTrim Char
'0' Int
2 (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ Builder -> ByteString
BB.toLazyByteString (Builder -> ByteString) -> Builder -> ByteString
forall a b. (a -> b) -> a -> b
$ Int -> Builder
BB.intDec Int
n
renderTime :: FormatTime t => t -> String
renderTime :: t -> String
renderTime = TimeLocale -> String -> t -> String
forall t. FormatTime t => TimeLocale -> String -> t -> String
formatTime TimeLocale
defaultTimeLocale String
"%B %-e, %Y, at %H:%M %P, %Z."
logInfoHeader :: (HasLock e, HasLogHandles e, HasStartingTime e, HasVerbosity e) => String -> [String] -> Logger e ()
String
cmdName [String]
cmdDsc = do
String -> Logger e ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
String -> Logger e ()
logInfoS String
hline
String -> Logger e ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
String -> Logger e ()
logInfoS (String -> Logger e ()) -> String -> Logger e ()
forall a b. (a -> b) -> a -> b
$ String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"\n" [String]
logHeader
String
t <- UTCTime -> String
forall t. FormatTime t => t -> String
renderTime (UTCTime -> String) -> ReaderT e IO UTCTime -> ReaderT e IO String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (e -> UTCTime) -> ReaderT e IO UTCTime
forall (m :: * -> *) r a. Monad m => (r -> a) -> ReaderT r m a
reader e -> UTCTime
forall s. HasStartingTime s => s -> UTCTime
getStartingTime
String
p <- IO String -> ReaderT e IO String
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO String
getProgName
[String]
as <- IO [String] -> ReaderT e IO [String]
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO [String]
getArgs
String -> Logger e ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
String -> Logger e ()
logInfoS (String -> Logger e ()) -> String -> Logger e ()
forall a b. (a -> b) -> a -> b
$
String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"\n" ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$
String
hline String -> [String] -> [String]
forall a. a -> [a] -> [a]
:
(String
"Command name: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
cmdName) String -> [String] -> [String]
forall a. a -> [a] -> [a]
:
[String]
cmdDsc
[String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String
"Starting time: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
t, String
"Command line: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
p String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ [String] -> String
unwords [String]
as]
String -> Logger e ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
String -> Logger e ()
logInfoS String
hline
where
hline :: String
hline = Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
78 Char
'-'
logInfoFooter :: (HasLock e, HasLogHandles e, HasStartingTime e, HasVerbosity e) => Logger e ()
= do
UTCTime
ti <- (e -> UTCTime) -> ReaderT e IO UTCTime
forall (m :: * -> *) r a. Monad m => (r -> a) -> ReaderT r m a
reader e -> UTCTime
forall s. HasStartingTime s => s -> UTCTime
getStartingTime
UTCTime
te <- IO UTCTime -> ReaderT e IO UTCTime
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO UTCTime
getCurrentTime
let dt :: NominalDiffTime
dt = UTCTime
te UTCTime -> UTCTime -> NominalDiffTime
`diffUTCTime` UTCTime
ti
ByteString -> Logger e ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
ByteString -> Logger e ()
logInfoB (ByteString -> Logger e ()) -> ByteString -> Logger e ()
forall a b. (a -> b) -> a -> b
$ ByteString
"Wall clock run time: " ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> NominalDiffTime -> ByteString
renderDuration NominalDiffTime
dt ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
"."
String -> Logger e ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
String -> Logger e ()
logInfoS (String -> Logger e ()) -> String -> Logger e ()
forall a b. (a -> b) -> a -> b
$ String
"End time: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> UTCTime -> String
forall t. FormatTime t => t -> String
renderTime UTCTime
te
logInfoNewSection :: (HasLock e, HasLogHandles e, HasVerbosity e) => String -> Logger e ()
logInfoNewSection :: String -> Logger e ()
logInfoNewSection String
s = String -> Logger e ()
forall e.
(HasLock e, HasLogHandles e, HasVerbosity e) =>
String -> Logger e ()
logInfoS (String -> Logger e ()) -> String -> Logger e ()
forall a b. (a -> b) -> a -> b
$ String
"== " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
s