module Colog.Syslog.Priority ( -- * Priority Priority (..) , priorityValue -- * Severity , Severity (..) , severityCode -- * Facility , Facility (..) , facilityCode ) where import Universum import Data.Aeson (FromJSON(..), ToJSON(..), Value (..), withText, withObject, (.:), (.=), object) import Data.Bits ((.|.), shiftL) import Fmt (Buildable (build), fmt, (+|), (|+)) import Text.Show (Show (show)) -- | Represents the priority of a syslog message, as per RFC5424 data Priority = Priority Facility Severity deriving (Eq, Read) -- NOTE: the angular parenthesis are important: they are required by the protocol instance Buildable Priority where build p = "<"+|(priorityValue p)|+">" instance Show Priority where show = fmt . build instance FromJSON Priority where parseJSON = withObject "Priority" $ \v -> Priority <$> v .: "facility" <*> v .: "severity" instance ToJSON Priority where toJSON (Priority facility severity) = object [ "facility" .= facility , "severity" .= severity ] -- | Calculate the 'Priority' value of a message, as per RFC5424 priorityValue :: Priority -> Int priorityValue (Priority fac sev) = facilityCode fac .|. severityCode sev -- | Represents the severity of a syslog message, as per RFC5424 data Severity = Emergency -- ^ System is unusable | Alert -- ^ Action must be taken immediately | Critical -- ^ Critical conditions | Error -- ^ Error conditions | Warning -- ^ Warning conditions | Notice -- ^ Normal but significant condition | Info -- ^ Informational messages | Debug -- ^ Debug-level messages deriving (Eq, Show, Read, Bounded, Enum) -- | 'Ord' instance uses the 'Enum' instance reversed, so Severities can be -- ordered correctly and 'Enum' can give us the right 'severityCode' instance Ord Severity where compare l r = compare (fromEnum r) (fromEnum l) instance Buildable Severity where build = \case Emergency -> "[Emergency] " Alert -> "[Alert] " Critical -> "[Critical] " Error -> "[Error] " Warning -> "[Warning] " Notice -> "[Notice] " Info -> "[Info] " Debug -> "[Debug] " instance FromJSON Severity where parseJSON = withText "Severity" $ \t -> maybe (fail $ "Unknown Severity: \""+|t|+"\"") pure . readMaybe $ toString t instance ToJSON Severity where toJSON = String . Universum.show -- | Numerical code for a 'Severity'. Used to calculate the 'priorityValue'. severityCode :: Severity -> Int severityCode = fromEnum -- | Represents the machine process that created a syslog event, as per RFC5424 data Facility = Kernel -- ^ Kernel messages | User -- ^ User-level messages. Unless something else applies, this should be your first choice. | Mail -- ^ Mail system | Daemon -- ^ System daemons | Auth -- ^ Security/Authorization messages | Syslog -- ^ Messages generated internally by syslogd | Lpr -- ^ Line printer subsystem | News -- ^ Network news subsystem | Uucp -- ^ UUCP subsystem | Cron -- ^ Cron messages | AuthPriv -- ^ Private Security/Authorization messages | Ftp -- ^ FTP daemon | Ntp -- ^ NTP subsystem | LogAudit -- ^ Log audit | LogAlert -- ^ Log alert | Clock -- ^ Clock daemon | Local0 -- ^ LOCAL 0 to 7 are not used by UNIX and can be used freely | Local1 | Local2 | Local3 | Local4 | Local5 | Local6 | Local7 deriving (Eq, Show, Read, Bounded, Enum) instance FromJSON Facility where parseJSON = withText "Facility" $ \t -> maybe (fail $ "Unknown Facility: \""+|t|+"\"") pure . readMaybe $ toString t instance ToJSON Facility where toJSON = String . Universum.show -- | Numerical code for a 'Facility'. Used to calculate the 'priorityValue'. facilityCode :: Facility -> Int facilityCode fac = shiftL (fromEnum fac) 3