如何(有效地)使用Haskell跟踪/尾随文件,包括检测文件轮换?(尾部-F)

ppb*_*ppb 7 haskell

本质上,我想知道如何tail -F在Haskell中实现Linux命令功能.我的目标是遵循日志文件,例如Web服务器日志文件,并通过在输入时解析输入来计算各种实时统计信息.理想情况下,如果日志文件使用logrotate或类似服务轮换,则不会中断.

我有点不知道如何处理这个问题,在懒惰的I/O存在的性能方面我应该考虑什么.任何流媒体库都与此相关吗?

dan*_*iaz 7

这是一个部分答案,因为它不处理文件截断logrotate.它避免懒I/O和使用的字节串,流媒体,流媒体,字节串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)
Run Code Online (Sandbox Code Playgroud)

这是"拖尾"功能:

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
Run Code Online (Sandbox Code Playgroud)

它需要一个文件路径作为一个消耗流字节串的回调.

我们的想法是,每次从句柄读取到EOF之前,我们都会减少一个信号量,只有在修改文件时调用的回调才会增加.

我们可以像这样测试函数:

main :: IO ()
main = do
    filepath : _ <- getArgs
    tailing filepath B.stdout
Run Code Online (Sandbox Code Playgroud)