我正在处理syslog日志文件,每行作为单独的syslog条目,并使用Attoparsec解析器解析该条目。所以我正在使用
fileToBS :: IO Handle -> C.Source (ResourceT IO) BS.ByteString
fileToBS handleMaker = source C.$= bsSplitterConduit
where source = CB.sourceIOHandle handleMaker
bsSplitterConduit = CB.lines
生成syslog条目流。我正在使用
parseToLogData:: C.Conduit BS.ByteString (ResourceT IO) (Either CATT.ParseError (CATT.PositionRange, LogData))
parseToLogData = CATT.conduitParserEither syslogParser
将这些字节串转换为syslog值。系统日志值是从这个解析器生成的(我自己的某些类型的同义词):
syslogParser :: Parser (Priority, Maybe UTCTime, IPAddress, BS.ByteString)
syslogParser = do
pri <- priority <?> "priority parse error"
mbDate <- date <?> "date parse error"
space
srcAddr <- ip
space
msg <- ATT.takeByteString
return LogData{pri = pri, timestamp = mbDate, source = srcAddr, message = "msg"}
priority :: Parser Priority
priority = do
string "<"
digitsString <- takeWhile1 digit
string ">"
return (RawPriority digitsString)
date :: Parser (Maybe UTCTime)
date = do
rawDate <- ATT.take 15
let stringDate = BS.unpack rawDate
let parsedDate = parseTime defaultTimeLocale syslogDateFormat stringDate
return parsedDate
ip :: Parser IPAddress
ip = do
oct0 <- takeWhile1 digit
period
oct1 <- takeWhile1 digit
period
oct2 <- takeWhile1 digit
period
oct3 <- takeWhile1 digit
return (oct0, oct1, oct2, oct3)
--ip = takeWhile1 (\x -> digit x || x == 46)
space = string " "
colon = string ":"
period = string "."
digit test = (test >= 48 && test <= 57)
octet = digit
问题是接收所有其余syslog条目(msg <- ATT.takeByteString
)的行。这个函数对流不好用,因为如果使用可恢复的解析器(这是管道的attoparsec库使用的那个),它需要一个终止信号。
我试图产生空的字节串来修复此行为,但它没有按预期工作(请参阅https://hackage.haskell.org/package/attoparsec-0.12.1.2/docs/Data-Attoparsec-ByteString.html上的增量输入)。它将整个syslog输入文件用于一个已解析的值。这是一个80MB的测试文件,因此在初始字段提取之后,它将所有后续的syslog消息放入syslog值的消息字段中。
这是我尝试发出“原子消息”行为的终结器管道。我不确定为什么它不起作用。
terminator :: C.Conduit BS.ByteString (ResourceT IO) BS.ByteString
terminator = C.awaitForever yieldAndAddTerminator
where
yieldAndAddTerminator bs = do
C.yield bs
C.yield terminator
terminator = ""
如何在管道世界中将UDP消息视为原子数据?
此代码库的副本可在此处找到:https://github.com/tureus/safe-forwarder。
答案 0 :(得分:1)
您可能希望将parseToLogData
与一个阻止其消耗新行的功能(ASCII代码10)融合。使用管道组合器术语,如:
takeWhileCE (/= 10) =$= parseToLogData
dropWhileCE (/= 10) >> dropCE 1 -- flush the rest of it
您可能还想查看line
组合函数。