本质上我想知道如何在Haskell中实现tail -F
Linux命令功能。我的目标是遵循日志文件,例如Web服务器日志文件,并通过在输入时解析输入来计算各种实时统计信息。如果日志文件以logrotate
或类似方式轮换,则理想情况下不会中断服务。
我对如何处理问题感到有些不知所措,在懒惰I / O存在的情况下,我应该考虑哪些性能。任何流媒体库都与此相关吗?
答案 0 :(得分:6)
这是部分答案,因为它不处理logrotate
的文件截断。它避免了惰性I / O并使用bytestring,streaming,streaming-bytestring和hinotify包。
一些初步进口:
{-# language OverloadedStrings #-}
module Main where
import qualified Data.ByteString
import Data.ByteString.Lazy.Internal (defaultChunkSize)
import qualified Data.ByteString.Streaming as B
import Streaming
import qualified Streaming.Prelude as S
import Control.Concurrent.QSem
import System.INotify
import System.IO (withFile,IOMode(ReadMode))
import System.Environment (getArgs)
这是“拖尾”功能:
tailing :: FilePath -> (B.ByteString IO () -> IO r) -> IO r
tailing filepath continuation = withINotify $ \i -> do
sem <- newQSem 1
addWatch i [Modify] filepath (\_ -> signalQSem sem)
withFile filepath ReadMode (\h -> continuation (handleToStream sem h))
where
handleToStream sem h = B.concat . Streaming.repeats $ do
lift (waitQSem sem)
readWithoutClosing h
-- Can't use B.fromHandle here because annoyingly it closes handle on EOF
-- instead of just returning, and this causes problems on new appends.
readWithoutClosing h = do
c <- lift (Data.ByteString.hGetSome h defaultChunkSize)
if Data.ByteString.null c
then return ()
else do B.chunk c
readWithoutClosing h
它使文件路径成为使用流式字节串的回调。
这个想法是,每次从句柄读取到EOF之前,我们都会减少一个信号量,只有在修改文件时调用的回调才会增加它。
我们可以测试这样的功能:
main :: IO ()
main = do
filepath : _ <- getArgs
tailing filepath B.stdout