我已经使用attoparsec编写了一个日志文件解析器。我所有的较小的解析器都会成功,组合的最终解析器也会成功。我已经通过测试确认了这一点。但是我为解析流执行操作而绊脚石。
我首先尝试将成功解析的输入传递给函数。但是似乎所有的都是Done ()
,我想这意味着日志文件已经被消耗了。
prepareStats :: Result Log -> IO ()
prepareStats r =
case r of
Fail _ _ _ -> putStrLn $ "Parsing failed"
Done _ parsedLog -> putStrLn "Success" -- This now has a [LogEntry] array. Do something with it.
main :: IO ()
main = do
[f] <- getArgs
logFile <- B.readFile (f :: FilePath)
let results = parseOnly parseLog logFile
putStrLn "TBC"
我要在消耗输入时从日志文件中累积一些统计信息。例如,我正在解析响应代码,我想计算有2 **个响应和4/5 **个响应。我正在解析每个返回为Ints的响应的字节数,我想有效地将它们相加(听起来像foldl'
?)。我已经定义了这样的数据类型:
data Stats = Stats {
successfulRequestsPerMinute :: Int
, failingRequestsPerMinute :: Int
, meanResponseTime :: Int
, megabytesPerMinute :: Int
} deriving Show
而且,我想在解析输入内容时不断进行更新。但是,我消耗的执行操作的一部分就是卡住了。到目前为止,这print
是我已成功将输出成功传递给的唯一函数,它表明Done
在打印输出之前通过返回已成功进行了解析。
我的主解析器如下所示:
parseLogEntry :: Parser LogEntry
parseLogEntry = do
ip <- logItem
_ <- char ' '
logName <- logItem
_ <- char ' '
user <- logItem
_ <- char ' '
time <- datetimeLogItem
_ <- char ' '
firstLogLine <- quotedLogItem
_ <- char ' '
finalRequestStatus <- intLogItem
_ <- char ' '
responseSizeB <- intLogItem
_ <- char ' '
timeToResponse <- intLogItem
return $ LogEntry ip logName user time firstLogLine finalRequestStatus responseSizeB timeToResponse
type Log = [LogEntry]
parseLog :: Parser Log
parseLog = many $ parseLogEntry <* endOfLine
我想将每个解析的行传递给一个函数,该函数将更新上述数据类型。理想情况下,我希望它具有很高的内存效率,因为它将在大文件上运行。
如果每个日志条目正好是一行,这是一个更简单的解决方案:
do loglines <- fmap BS.lines $ BS.readfile "input-file.log"
foldl' go initialStats loglines
where
go stats logline =
case parseOnly yourParser logline of
Left e -> error $ "oops: " ++ e
Right r -> let stats' = ... combine r with stats ...
in stats'
基本上,您只是逐行读取文件并parseOnly
在每一行上调用并累积结果。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句