packages feed

pan-os-syslog-0.2.0.0: src/Panos/Syslog/Internal/System.hs

{-# language BangPatterns #-}
{-# language DerivingStrategies #-}
{-# language DuplicateRecordFields #-}
{-# language GeneralizedNewtypeDeriving #-}
{-# language LambdaCase #-}
{-# language MagicHash #-}
{-# language NamedFieldPuns #-}
{-# language NumericUnderscores #-}
{-# language ScopedTypeVariables #-}
module Panos.Syslog.Internal.System
  ( System(..)
  , parserSystem
  ) where

import Panos.Syslog.Internal.Common

import Chronos (Datetime)
import Data.Bytes.Parser (Parser)
import Data.Bytes.Types (Bytes(..))
import Data.Primitive (ByteArray)
import Data.Word (Word64)

import qualified Data.Bytes.Parser.Latin as Latin
import qualified Data.Bytes.Parser.Unsafe as Unsafe

-- | A PAN-OS system log. Read-only accessors are found in
-- @Panos.Syslog.System@.
data System = System
  { message :: {-# UNPACK #-} !ByteArray
    -- The original log
  , syslogHost :: {-# UNPACK #-} !Bounds
    -- The host as presented in the syslog preamble that
    -- prefixes the message.
  , receiveTime :: {-# UNPACK #-} !Datetime
    -- In log, presented as: 2019/06/18 15:10:20
  , serialNumber :: {-# UNPACK #-} !Bounds
    -- In log, presented as: 002610378847
  , subtype :: {-# UNPACK #-} !Bounds
    -- Presented as: dhcp, dnsproxy, dos, general, etc.
  , timeGenerated :: {-# UNPACK #-} !Datetime
    -- Presented as: 2019/11/04 08:39:05
  , virtualSystem :: {-# UNPACK #-} !Bounds
  , eventId :: {-# UNPACK #-} !Bounds
  , object :: {-# UNPACK #-} !Bounds
  , module_ :: {-# UNPACK #-} !Bounds
  , severity :: {-# UNPACK #-} !Bounds
  , descriptionBounds :: {-# UNPACK #-} !Bounds
  , descriptionByteArray :: {-# UNPACK #-} !ByteArray
  , sequenceNumber :: {-# UNPACK #-} !Word64
  , actionFlags :: {-# UNPACK #-} !Word64
  , deviceGroupHierarchyLevel1 :: {-# UNPACK #-} !Word64
  , deviceGroupHierarchyLevel2 :: {-# UNPACK #-} !Word64
  , deviceGroupHierarchyLevel3 :: {-# UNPACK #-} !Word64
  , deviceGroupHierarchyLevel4 :: {-# UNPACK #-} !Word64
  , virtualSystemName :: {-# UNPACK #-} !Bounds
  , deviceName :: {-# UNPACK #-} !Bounds
  }

parserSystem :: Bounds -> Datetime -> Bounds -> Parser Field s System
parserSystem syslogHost receiveTime serialNumber = do
  subtype <- untilComma subtypeField
  skipThroughComma futureUseAField
  -- The datetime parser consumes the trailing comma
  timeGenerated <- parserDatetime timeGeneratedDateField timeGeneratedTimeField
  virtualSystem <- untilComma virtualSystemField
  eventId <- untilComma eventIdField
  object <- untilComma objectField
  skipThroughComma futureUseBField
  skipThroughComma futureUseCField
  module_ <- untilComma moduleField
  severity <- untilComma severityField
  Bytes{array=descriptionByteArray,offset=descrOff,length=descrLen} <-
    parserOptionallyQuoted descriptionField
  let descriptionBounds = Bounds descrOff descrLen
  sequenceNumber <- w64Comma sequenceNumberField
  -- TODO: handle action flags
  Latin.char actionFlagsField '0'
  Latin.char actionFlagsField 'x'
  _ <- untilComma actionFlagsField
  let actionFlags = 0
  deviceGroupHierarchyLevel1 <- w64Comma deviceGroupHierarchyLevel1Field
  deviceGroupHierarchyLevel2 <- w64Comma deviceGroupHierarchyLevel2Field
  deviceGroupHierarchyLevel3 <- w64Comma deviceGroupHierarchyLevel3Field
  deviceGroupHierarchyLevel4 <- w64Comma deviceGroupHierarchyLevel4Field
  virtualSystemName <- untilComma virtualSystemNameField
  deviceName <- finalField
  message <- Unsafe.expose
  pure System
    { subtype , timeGenerated
    , sequenceNumber 
    , deviceGroupHierarchyLevel1 , deviceGroupHierarchyLevel2 
    , deviceGroupHierarchyLevel3 , deviceGroupHierarchyLevel4 
    , virtualSystemName , deviceName , receiveTime
    , serialNumber, actionFlags, message
    , syslogHost, virtualSystem, eventId, object, module_
    , severity, descriptionBounds, descriptionByteArray
    }

-- There should not be any more commas left in the input.
-- This takes until it finds a comma or until end of input
-- is reached.
finalField :: Parser e s Bounds
{-# inline finalField #-}
finalField = do
  start <- Unsafe.cursor
  Latin.skipUntil ','
  end <- Unsafe.cursor
  pure (Bounds start (end - start))