# vim:ts=2:sw=2:et:ai:sts=2:cinoptions=(0
# Copyright 2017 Martín Ferrari <tincho@tincho.org>. All Rights Reserved.
# This file is available under the Apache license.

# Syslog parser for Postfix, based on the parsing rules from:
# https://github.com/kumina/postfix_exporter
# Copyright 2017 Kumina, https://kumina.nl/
# Available under the Apache license.

const DELIVERY_DELAY_LINE /.*, relay=(?P<relay>\S+), .*,/ +
  / delays=(?P<bqm>[0-9\.]+)\/(?P<qm>[0-9\.]+)\/(?P<cs>[0-9\.]+)\/(?P<tx>[0-9\.]+),\s/
const SMTP_TLS_LINE /(\S+) TLS connection established to \S+: (\S+) with cipher (\S+) \((\d+)\/(\d+) bits\)/
const SMTPD_TLS_LINE /(\S+) TLS connection established from \S+: (\S+) with cipher (\S+) \((\d+)\/(\d+) bits\)/
const QMGR_INSERT_LINE /:.*, size=(?P<size>\d+), nrcpt=(?P<nrcpt>\d+)/
const QMGR_REMOVE_LINE /: removed$/

/^(?P<date>(?P<legacy_date>\w+\s+\d+\s+\d+:\d+:\d+)|(?P<rfc3339_date>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d+[+-]\d{2}:\d{2}))/ +
/\s+(?:\w+@)?(?P<hostname>[\w\.-]+)\s+postfix\/(?P<application>[\w\.-\/]+)(?:\[(?P<pid>\d+)\])?:\s+(?P<message>.*)/ {
  len($legacy_date) > 0 {
    strptime($2, "Jan _2 15:04:05")
  }
  len($rfc3339_date) > 0 {
    strptime($rfc3339_date, "2006-01-02T03:04:05-0700")
  }
  # Total number of messages processed by cleanup.
  counter postfix_cleanup_messages_processed_total

  # Total number of messages rejected by cleanup.
  counter postfix_cleanup_messages_rejected_total

  $application == "cleanup" {
    /: message-id=</ {
      postfix_cleanup_messages_processed_total++
      }
    /: reject: / {
      postfix_cleanup_messages_rejected_total++
      }
    }

  # LMTP message processing time in seconds.
  histogram postfix_lmtp_delivery_delay_seconds by stage buckets 0.001, 0.01, 0.1, 10, 1e2, 1e3
  # buckets: 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3

  $application == "lmtp" {
    // + DELIVERY_DELAY_LINE {
      # 1st field: before_queue_manager
      postfix_lmtp_delivery_delay_seconds["before_queue_manager"] = $bqm

      # 2nd field: queue_manager
      postfix_lmtp_delivery_delay_seconds["queue_manager"] = $qm

      # 3rd field: connection_setup
      postfix_lmtp_delivery_delay_seconds["connection_setup"] = $cs

      # 4th field: transmission
      postfix_lmtp_delivery_delay_seconds["transmission"] = $tx
    }
  }

  # Pipe message processing time in seconds.
  histogram postfix_pipe_delivery_delay_seconds by relay, stage buckets 0.001, 0.01, 0.1, 1, 10, 100, 1e3
  # buckets: 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3

  $application == "pipe" {
    // + DELIVERY_DELAY_LINE {
      # 1st field: before_queue_manager
      postfix_pipe_delivery_delay_seconds[$relay]["before_queue_manager"] = $bqm

      # 2nd field: queue_manager
      postfix_pipe_delivery_delay_seconds[$relay]["queue_manager"] = $qm

      # 3rd field: connection_setup
      postfix_pipe_delivery_delay_seconds[$relay]["connection_setup"] = $cs

      # 4th field: transmission
      postfix_pipe_delivery_delay_seconds[$relay]["transmission"] = $tx
    }
  }

  # Number of recipients per message inserted into the mail queues.
  histogram postfix_qmgr_messages_inserted_recipients buckets 1, 2, 4, 7, 16, 32, 64, 128
  # buckets: 1, 2, 4, 8, 16, 32, 64, 128

  # Size of messages inserted into the mail queues in bytes.
  histogram postfix_qmgr_messages_inserted_size_bytes buckets 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9
  # buckets: 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9

  # Total number of messages removed from mail queues.
  counter postfix_qmgr_messages_removed_total

  $application == "qmgr" {
    // + QMGR_INSERT_LINE {
      postfix_qmgr_messages_inserted_recipients = $nrcpt
      postfix_qmgr_messages_inserted_size_bytes = $size
      }
    // + QMGR_REMOVE_LINE {
      postfix_qmgr_messages_removed_total++
      }
    }

  # SMTP message processing time in seconds.
  histogram postfix_smtp_delivery_delay_seconds by stage buckets 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3
  # buckets: 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3

  # Total number of outgoing TLS connections.
  counter postfix_smtp_tls_connections_total by trust, protocol, cipher, secret_bits, algorithm_bits

  $application == "smtp" {
      // + DELIVERY_DELAY_LINE {
        # 1st field: before_queue_manager
        postfix_smtp_delivery_delay_seconds["before_queue_manager"] = $bqm

        # 2nd field: queue_manager
        postfix_smtp_delivery_delay_seconds["queue_manager"] = $qm

      # 3rd field: connection_setup
      postfix_smtp_delivery_delay_seconds["connection_setup"] = $cs

      # 4th field: transmission
      postfix_smtp_delivery_delay_seconds["transmission"] = $tx
      }

      // + SMTP_TLS_LINE {
        postfix_smtp_tls_connections_total[$1][$2][$3][$4][$5]++
      }
    }

  # Total number of incoming connections.
  counter postfix_smtpd_connects_total

  # Total number of incoming disconnections.
  counter postfix_smtpd_disconnects_total

  # Total number of connections for which forward-confirmed DNS cannot be resolved.
  counter postfix_smtpd_forward_confirmed_reverse_dns_errors_total

  # Total number of connections lost.
  counter postfix_smtpd_connections_lost_total by after_stage

  # Total number of messages processed.
  counter postfix_smtpd_messages_processed_total by sasl_username

  # Total number of NOQUEUE rejects.
  counter postfix_smtpd_messages_rejected_total by code

  # Total number of SASL authentication failures.
  counter postfix_smtpd_sasl_authentication_failures_total

  # Total number of incoming TLS connections.
  counter postfix_smtpd_tls_connections_total by trust, protocol, cipher, secret_bits, algorithm_bits

  $application =~ /smtpd/ {
    / connect from / {
      postfix_smtpd_connects_total++
      }
    / disconnect from / {
      postfix_smtpd_disconnects_total++
      }
    / warning: hostname \S+ does not resolve to address / {
      postfix_smtpd_forward_confirmed_reverse_dns_errors_total++
      }
    / lost connection after (\w+) from / {
      postfix_smtpd_connections_lost_total[$1]++
      }
    /: client=/ {
      /, sasl_username=(\S+)/ {
        postfix_smtpd_messages_processed_total[$1]++
        } else {
        postfix_smtpd_messages_processed_total[""]++
        }
      }
    /NOQUEUE: reject: RCPT from \S+: (\d+) / {
      postfix_smtpd_messages_rejected_total[$1]++
      }
    /warning: \S+: SASL \S+ authentication failed: / {
      postfix_smtpd_sasl_authentication_failures_total++
      }
    // + SMTPD_TLS_LINE {
      postfix_smtpd_tls_connections_total[$1][$2][$3][$4][$5]++
      }
    }
  }
