2012-05-17 08:15:25 +04:00
|
|
|
{-# LANGUAGE NoImplicitPrelude #-}
|
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
2012-05-17 10:32:11 +04:00
|
|
|
{-# LANGUAGE TemplateHaskell #-}
|
2012-05-17 08:15:25 +04:00
|
|
|
module Keter.LogFile
|
|
|
|
( LogFile
|
|
|
|
, start
|
|
|
|
, addChunk
|
|
|
|
, close
|
|
|
|
) where
|
|
|
|
|
2012-05-17 11:59:17 +04:00
|
|
|
import Keter.Prelude hiding (getCurrentTime)
|
2012-05-17 08:15:25 +04:00
|
|
|
import qualified Data.ByteString as S
|
|
|
|
import Data.Time (getCurrentTime)
|
|
|
|
import qualified System.IO as SIO
|
|
|
|
import qualified Filesystem as F
|
|
|
|
import qualified Data.Text as T
|
|
|
|
|
|
|
|
data Command = AddChunk S.ByteString
|
|
|
|
| Close
|
|
|
|
|
|
|
|
newtype LogFile = LogFile (Command -> KIO ())
|
|
|
|
|
|
|
|
addChunk :: LogFile -> S.ByteString -> KIO ()
|
|
|
|
addChunk (LogFile f) bs = f $ AddChunk bs
|
|
|
|
|
|
|
|
close :: LogFile -> KIO ()
|
|
|
|
close (LogFile f) = f Close
|
|
|
|
|
|
|
|
start :: FilePath -- ^ folder to contain logs
|
|
|
|
-> KIO (Either SomeException LogFile)
|
|
|
|
start dir = do
|
|
|
|
res <- liftIO $ do
|
|
|
|
createTree dir
|
|
|
|
moveCurrent Nothing
|
|
|
|
case res of
|
|
|
|
Left e -> return $ Left e
|
|
|
|
Right handle -> do
|
|
|
|
chan <- newChan
|
|
|
|
forkKIO $ loop chan handle 0
|
|
|
|
return $ Right $ LogFile $ writeChan chan
|
|
|
|
where
|
|
|
|
current = dir </> "current.log"
|
|
|
|
moveCurrent mhandle = do
|
|
|
|
maybe (return ()) SIO.hClose mhandle
|
|
|
|
x <- isFile current
|
|
|
|
when x $ do
|
|
|
|
now <- getCurrentTime
|
|
|
|
rename current $ dir </> suffix now
|
|
|
|
F.openFile current F.WriteMode
|
2012-05-17 12:47:54 +04:00
|
|
|
suffix now = fromText (T.concatMap fix $ T.takeWhile (/= '.') $ show now) <.> "log"
|
|
|
|
fix ' ' = "_"
|
|
|
|
fix c | '0' <= c && c <= '9' = T.singleton c
|
|
|
|
fix _ = T.empty
|
2012-05-17 08:15:25 +04:00
|
|
|
loop chan handle total = do
|
|
|
|
c <- readChan chan
|
|
|
|
case c of
|
|
|
|
AddChunk bs -> do
|
|
|
|
let total' = total + S.length bs
|
|
|
|
res <- liftIO $ S.hPut handle bs >> SIO.hFlush handle
|
2012-05-17 10:32:11 +04:00
|
|
|
either $logEx return res
|
2012-05-17 08:15:25 +04:00
|
|
|
if total' > maxTotal
|
|
|
|
then do
|
|
|
|
res2 <- liftIO $ moveCurrent $ Just handle
|
|
|
|
case res2 of
|
|
|
|
Left e -> do
|
2012-05-17 10:32:11 +04:00
|
|
|
$logEx e
|
2012-05-17 08:15:25 +04:00
|
|
|
deadLoop chan
|
|
|
|
Right handle' -> loop chan handle' 0
|
|
|
|
else loop chan handle total'
|
|
|
|
Close ->
|
|
|
|
liftIO (SIO.hClose handle) >>=
|
2012-05-17 10:32:11 +04:00
|
|
|
either $logEx return
|
2012-05-17 08:15:25 +04:00
|
|
|
deadLoop chan = do
|
|
|
|
c <- readChan chan
|
|
|
|
case c of
|
|
|
|
AddChunk _ -> deadLoop chan
|
|
|
|
Close -> return ()
|
|
|
|
|
|
|
|
maxTotal = 5 * 1024 * 1024 -- 5 MB
|