syslog 로그 파일을 처리하고 있으며, 각 행을 개별 syslog 항목으로 처리하고 Attoparsec 파서를 사용하여 해당 항목을 구문 분석합니다. 그래서 나는 syslog 항목의 스트림을 생성하기 위해Conduit Attoparsec의 입력을 수동으로 종료
fileToBS :: IO Handle -> C.Source (ResourceT IO) BS.ByteString
fileToBS handleMaker = source C.$= bsSplitterConduit
where source = CB.sourceIOHandle handleMaker
bsSplitterConduit = CB.lines
을 사용하고있다. 사용하고 있습니다.
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
문제는 시스템 로그 항목 (msg <- ATT.takeByteString
)의 나머지는 모두 소요되는 라인입니다. 이 함수는 재개 가능한 파서 (conduit의 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에서 찾을 수 있습니다.
필자는'fileToBS' (Data.Conduit.List 함수'lines'을 사용합니다)는 줄 바꿈을 사용한다고 생각했습니다. 나는 분리 된 ByteString으로 입력 파일을 분해 할 수있다. 문제는 이러한 ByteString이 동일한 구문 분석기 인스턴스로 공급된다는 것입니다. 이 동작 대신에 불완전한 구문 분석을 오류 ('Left')로 계속하고 이후의 ByteString 값을 독립적으로 파싱해야합니다. – xrl
그런 경우 Data.Conduit.List.isolate를 사용하여 입력 청크를 제한해야합니다. –
ByteStrings를 개별적인 덩어리로 보지 않는 것처럼 보입니다. 한 줄만 소비 한 다음 더 이상 처리하지 않는 것처럼 보입니다. 'fileToBS openAction C. $ = (CL.isolate 1) C. $ = parseToLogData C. $$ printer' – xrl