Created
June 26, 2013 09:32
-
-
Save tatac1/5866108 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE OverloadedStrings #-} | |
module ParsecRFC3164 | |
( | |
parseRFC3164 | |
, RFC3164 | |
, PRI | |
, Severity | |
, Facility | |
, Header | |
, Msg | |
, pri | |
, header | |
, msg | |
, content | |
) where | |
import SyslogPriority | |
import Control.Applicative | |
import Data.Attoparsec as P | |
import qualified Data.Attoparsec.Char8 as P8 | |
import Data.Attoparsec.Char8 (char8, endOfLine) | |
import Data.ByteString | |
{- | |
http://www.amris.co.jp/netdocs/rfc3164_j.html | |
http://www.ietf.org/rfc/rfc3164.txt | |
-} | |
-- SYSLOG-MSG = PRI SP HEADER SP MSG | |
data RFC3164 = RFC3164 | |
{ | |
pri :: !PRI | |
, header :: !Header | |
, msg :: !Msg | |
} deriving (Show) | |
-- | parser for rfc 3164 | |
-- >>> :set -XOverloadedStrings | |
-- >>> parseTest parseRFC3164 "<34>Oct 11 22:14:15 mymachine su: 'su root' failed for lonvick on /dev/pts/8\n " | |
-- Done " " RFC3164 {pri = PRI {severity = CRITICAL, facility = AUTH}, header = Header {timestamp = "Oct 11 22:14:15", hostName = "mymachine"}, msg = Msg {tag = Just "su", procId = Nothing, content = " 'su root' failed for lonvick on /dev/pts/8"}} | |
-- | |
-- >>> parseTest parseRFC3164 "<0>Oct 22 10:52:12 scapegoat apache[2321]: 10.1.2.3 sched[0]: That's All Folks!\n " | |
-- Done " " RFC3164 {pri = PRI {severity = EMERGENCY, facility = KERN}, header = Header {timestamp = "Oct 22 10:52:12", hostName = "scapegoat"}, msg = Msg {tag = Just "apache", procId = Just 2321, content = " 10.1.2.3 sched[0]: That's All Folks!"}} | |
-- | |
parseRFC3164 :: Parser RFC3164 | |
parseRFC3164 = do | |
pri' <- parsePRI | |
header' <- parseHeader | |
msg' <- parseMsg | |
return $ RFC3164 pri' header' msg' | |
-- PRI = '<' INT '>' | |
-- INT = 1*3 DIGIT ; range 0 .. 191 | |
-- | |
data PRI = PRI { | |
severity :: !Severity | |
, facility :: !Facility | |
} deriving (Show) | |
-- | facrity and priority check | |
-- | |
-- Example: | |
-- | |
-- >>> parseTest parsePRI "<0> " | |
-- Done " " PRI {severity = EMERGENCY, facility = KERN} | |
-- | |
-- >>> parseTest parsePRI "<191> " | |
-- Done " " PRI {severity = DEBUG, facility = LOCAL7} | |
-- | |
parsePRI :: Parser PRI | |
parsePRI = do | |
pri <- char8 '<' *> P8.decimal <* char8 '>' | |
return $ PRI (parseSeverity pri) (parseFac pri) | |
parseFac :: Int -> Facility | |
parseFac pri = facOfCode $ pri `div` 8 | |
parseSeverity :: Int -> Severity | |
parseSeverity pri = priOfCode $ pri `mod` 8 | |
-- HEADER = TIMESTAMP SP HOSTNAME | |
-- TIMESTAMP = MMM SP DD SP HH COL MM COL SS | |
-- MMM = 3PRINTUSASCII ; Jan Feb Mar Arp May Jun Jul Aug Sep Oct Nov Dev | |
-- DD = 2DIGIT ; <SP>1-28, <SP>1-29, <SP>1-30, <SP>1-31 | |
-- HH = 2DIGIT ; 00-23 | |
-- MM = 2DIGIT ; 00-59 | |
-- HOSTNAME = IPv4 | IPv6 | PRINTUSASCII/DIGIT | |
-- IPv4 = 3NONZERO-DIGIT DOT 3NONZERO-DIGIT DOT 3NONZERO-DIGIT | |
-- IPv6 = | |
data Header = Header | |
{ | |
timestamp :: !ByteString | |
, hostName :: !ByteString | |
} deriving (Show, Read) | |
-- | header parser check | |
-- | |
-- example: | |
-- | |
-- >>> parseTest parseHeader "Feb 12 19:27:01 hostname " | |
-- Done "" Header {timestamp = "Feb 12 19:27:01", hostName = "hostname"} | |
-- | |
-- >>> parseTest parseHeader "Feb 2 19:27:01 hostname " | |
-- Done "" Header {timestamp = "Feb 2 19:27:01", hostName = "hostname"} | |
-- | |
parseHeader :: Parser Header | |
parseHeader = do | |
timestamp <- P8.take 15 <* char8 ' ' | |
hostName <- takeTill P8.isHorizontalSpace <* char8 ' ' | |
return $ Header timestamp hostName | |
data Msg = Msg { | |
tag :: !(Maybe ByteString) | |
, procId :: !(Maybe Int) | |
, content :: !ByteString | |
} deriving (Show) | |
--MSG = TAG COL CONTENT | |
--TAG = 1*32 PROCNAME [ PID ]: | |
--PROCNAME = PRINTUSASCII / DIGIT | |
--TAGID = DIGIT | |
--CONTENT = PRINTUSASCII | |
--SP = %d32 | |
--PRINTUSASCII = %d33-126 | |
--NONZERO-DIGIT = %d49-57 | |
--DIGIT = %d48 / NONZERO-DIGIT | |
--DOT = %46 | |
--COL = %58 | |
--[ = %91 | |
--] = %93 | |
-- | msg parser check | |
-- | |
-- example: | |
-- | |
-- >>> parseTest parseMsg "app[12]: message starting \n" -- "12]: message starting \n" | |
-- Done "" Msg {tag = Just "app", procId = Just 12, content = " message starting "} | |
-- | |
-- >>> parseTest parseMsg "app: message starting \n" --"message starting \n" | |
-- Done "" Msg {tag = Just "app", procId = Nothing, content = " message starting "} | |
-- | |
-- >>> parseTest parseMsg "[INSPECT] LAN2[out][200100] UDP 192.168.55.254:53 > 202.231.192.120:53 (2012/06/28 22:33:49) \n" | |
-- Done "" Msg {tag = Nothing, procId = Nothing, content = "[INSPECT] LAN2[out][200100] UDP 192.168.55.254:53 > 202.231.192.120:53 (2012/06/28 22:33:49) "} | |
-- | |
parseMsg :: Parser Msg | |
parseMsg = do | |
tag <- Just <$> try (takeTill (\c -> inClass "[:" c)) <|> pure Nothing <$> char8 '[' | |
pid <- Just <$> try (char8 '[' *> P8.decimal <* char8 ']' <* char8 ':') <|> pure Nothing <$> char8 ':' | |
content <- takeTill P8.isEndOfLine <* endOfLine | |
return $ Msg tag pid content | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment