161 lines
8.8 KiB
Ruby
161 lines
8.8 KiB
Ruby
class Collector::Dovecot
|
|
class Sieve
|
|
def initialize store, prometheus
|
|
@store = store
|
|
@stored_into_mailbox = prometheus.counter :stored_into_mailbox_total, docstring: 'A counter of mails stored in mailbox by sieve', labels: %i[process]
|
|
@forwards = prometheus.counter :forwared_mails_total, docstring: 'A counter of mails forwareded to other address', labels: %i[process]
|
|
@discarded_duplicate_forward = prometheus.counter :discarded_duplicate_forward_total, docstring: 'A counter of discarded duplicates, which will not be forwarded.', labels: %i[process]
|
|
%w[lmtp deliver].each do |p|
|
|
@stored_into_mailbox.increment by: 0, labels: {process: p}
|
|
@forwards.increment by: 0, labels: {process: p}
|
|
@discarded_duplicate_forward.increment by: 0, labels: {process: p}
|
|
end
|
|
end
|
|
|
|
def collect entry, process, msg
|
|
case msg
|
|
when / stored mail into mailbox /
|
|
# dovecot.service dovecot lmtp sieve: lmtp(dillo@nfotex.com)<935639><hhtGGv2ZVmLXRg4AQx2OcA>: sieve: msgid=<1649842684455734173.18148473471766045120@vlmpaymp001.at.inside>: stored mail into mailbox
|
|
@stored_into_mailbox.increment labels: {process: process}
|
|
when / forwarded to /
|
|
@forwards.increment labels: {process: process}
|
|
when / discarded duplicate forward to /
|
|
@discarded_duplicate_forward.increment labels: {process: process}
|
|
else
|
|
STDERR.puts "# #{entry._systemd_unit} #{entry.syslog_identifier} sieve| #{entry.message}"
|
|
end
|
|
end
|
|
end
|
|
|
|
class Delivery
|
|
def initialize store, prometheus, sieve, saved_mailbox, process
|
|
@store, @sieve, @process = store, sieve, process
|
|
@connect = prometheus.counter "#{process}_connect_total", docstring: "A counter of connection via #{process}"
|
|
@disconnect = prometheus.counter "#{process}_disconnect_total", docstring: "A counter of disconnect at #{process}"
|
|
@saved_mail_to_mailbox = saved_mailbox
|
|
end
|
|
|
|
def collect entry, msg
|
|
case msg
|
|
when /\AConnect from / then @connect.increment
|
|
when /\ADisconnect from / then @disconnect.increment
|
|
when /saved mail to / then @saved_mail_to_mailbox.increment labels: {process: @process}
|
|
when /\Asieve: (.*)/ then @sieve.collect entry, @process, $1
|
|
else STDERR.puts "# #{entry._systemd_unit} #{entry.syslog_identifier} delivery| #{entry.message}"
|
|
end
|
|
end
|
|
end
|
|
|
|
class Imap
|
|
def initialize store, prometheus
|
|
@connection_closed = prometheus.counter :connection_closed_total, docstring: 'A counter of closed connection on dovecot'
|
|
@inactivity = prometheus.counter :disconnected_inactivity_total, docstring: 'A counter for disconnect for inactivity.'
|
|
@connection_stats = prometheus.counter :connection_stats_total, docstring: 'A counter for observed statistics after disconnected.', labels: %i[disconnect_reason]
|
|
@logged_out = prometheus.counter :logged_out_total, docstring: 'A counter of logouts on dovecot'
|
|
@maildir_scanning_took_long = prometheus.summary :maildir_scanning_took_long_total, docstring: 'A summary of long taken maildir scanning by reason (why).', labels: %i[why]
|
|
@maildir_scanning_took_long_rename = prometheus.counter :maildir_scanning_took_long_renames_total, docstring: 'A counter of rename()-calls while long taken mail dir scanning'
|
|
@maildir_scanning_took_long_readdir = prometheus.counter :maildir_scanning_took_long_readdirs_total, docstring: 'A counter of readdir()-calls while long taken mail dir scanning'
|
|
disconnect_reasons = ['logged out', 'connection closed', 'inactivity']
|
|
disconnect_reasons.each {|r| @connection_stats.increment by: 0, labels: {disconnect_reason: r} }
|
|
@connection_stats =
|
|
Hash[ *%i[in out deleted expunged trashed hdr_count hdr_bytes body_count body_bytes].flat_map {|t|
|
|
[t, prometheus.counter( :"connection_stats_#{t}_total", docstring: "Counter for #{t} statistics observed after disconnected")]
|
|
}]
|
|
end
|
|
|
|
def collect entry, msg
|
|
case msg
|
|
when /\ALogged out (.*)/
|
|
# imap(srv_rt0@nfotex.com)<936759><IXxbn4bc4roqAQGQAGoGAWAUP//++Cw+>: Logged out in=38 out=804 deleted=0 expunged=0 trashed=0 hdr_count=0 hdr_bytes=0 body_count=0 body_bytes=0
|
|
@logged_out.increment
|
|
$1.split( ' ').each {|x| t, v = x.split('='); @connection_stats[t.to_sym]&.increment by: v.to_f }
|
|
when /\AConnection closed \([^)]+\) (.*)/
|
|
# imap(johannes@nfotex.com)<936668><R4OTgIbcCKRQbb9l>: Connection closed (EXAMINE finished 0.041 secs ago) in=5253 out=390971 deleted=0 expunged=0 trashed=0 hdr_count=14 hdr_bytes=6569 body_count=14 body_bytes=336589
|
|
@connection_closed.increment
|
|
$1.split( ' ').each {|x| t, v = x.split('='); @connection_stats[t.to_sym]&.increment by: v.to_f }
|
|
when /\AConnection closed: .* failed: \([^)]+\) (.*)/
|
|
# imap(wiz@nfotex.com)<1447340><0OOGu+XeasMqAoOIC8CCAHA59y+2iMag>: Connection closed: read(size=6100) failed: Connection reset by peer (UID FETCH finished 0.159 secs ago) in=2982 out=17044659 deleted=0 expunged=0 trashed=0 hdr_count=1 hdr_bytes=3724 body_count=169 body_bytes=16970415
|
|
@connection_closed.increment
|
|
$1.split( ' ').each {|x| t, v = x.split('='); @connection_stats[t.to_sym]&.increment by: v.to_f }
|
|
when /\ADisconnected for inactivity (.*)/
|
|
@inactivity.increment
|
|
$1.split( ' ').each {|x| t, v = x.split('='); @connection_stats[t.to_sym]&.increment by: v.to_f }
|
|
when /\AWarning: Maildir: Scanning .+? took (?<took>\d+) seconds \((?<readdir>\d+) readdir\(\)s, (?<rename>\d+) rename\(\)s to cur\/, why=0x(?<why>[0-9a-fA-F]+)\)/
|
|
# Warning: Maildir: Scanning /var/mail/nfotex.com/wiz/mails/.Updates/cur took 49 seconds (86044 readdir()s, 0 rename()s to cur/, why=0x80)
|
|
m = $~
|
|
@maildir_scanning_took_long.observe m[:took].to_i, labels: m[:why].to_i(16)
|
|
@maildir_scanning_took_long_rename.increment by: m[:rename].to_i
|
|
@maildir_scanning_took_long_readdir.increment by: m[:readdir].to_i
|
|
else
|
|
STDERR.puts "# #{entry._systemd_unit} #{entry.syslog_identifier} imap| #{entry.message}"
|
|
end
|
|
end
|
|
end
|
|
|
|
class ImapLogin
|
|
def initialize store, prometheus
|
|
@store = store
|
|
@logged_in = prometheus.counter :logged_in_total, docstring: 'A counter of successfull logins to dovecot'
|
|
@aborted = prometheus.counter :login_aborted_total, docstring: 'A counter of aborted logins'
|
|
@disconnected = prometheus.counter :login_disconnected_total, docstring: 'A counter of disconnections before successfully logged in', labels: %i[reason]
|
|
end
|
|
|
|
def collect entry, msg
|
|
case msg
|
|
when /\ALogin: user=/
|
|
@logged_in.increment
|
|
when /\ADisconnected:? \((.*?)\): user=</
|
|
case $1
|
|
when /\Ano auth attempts/
|
|
@disconnected.increment labels: {reason: 'no auth attempts'}
|
|
when /\Aauth failed/
|
|
@disconnected.increment labels: {reason: 'auth failed'}
|
|
when /\AToo many invalid commands /
|
|
@disconnected.increment labels: {reason: 'too many invalid commands'}
|
|
when /\AInactivity /
|
|
@disconnected.increment labels: {reason: 'inactivity'}
|
|
when /\ADisconnected /
|
|
@disconnected.increment labels: {reason: 'disconnected'}
|
|
else
|
|
@disconnected.increment labels: {reason: '<any>'}
|
|
STDERR.puts "# #{entry._systemd_unit} #{entry.syslog_identifier} Disconnected before login| #{entry.message}"
|
|
end
|
|
when /\AAborted login/
|
|
@aborted.increment
|
|
else
|
|
STDERR.puts "# #{entry._systemd_unit} #{entry.syslog_identifier} imap-login| #{entry.message}"
|
|
end
|
|
end
|
|
end
|
|
|
|
def initialize store, prometheus
|
|
@store = store
|
|
@saved_mail_to_mailbox = prometheus.counter :saved_mail_to_mailbox_total, docstring: "A counter of saved mails to mailbox directly", labels: %i[process]
|
|
@auth_errors = prometheus.counter :auth_errors_total, docstring: "A counter of dovecot auth errors by type.", labels: %i[error]
|
|
@sieve = Sieve.new store, Collector::PrefixProxy.new( prometheus, :sieve)
|
|
@lmtp = Delivery.new store, prometheus, @sieve, @saved_mail_to_mailbox, :lmtp
|
|
@deliver = Delivery.new store, prometheus, @sieve, @saved_mail_to_mailbox, :deliver
|
|
@imap_login = ImapLogin.new store, prometheus
|
|
@imap = Imap.new store, prometheus
|
|
end
|
|
|
|
def collect entry
|
|
# STDERR.puts "dovecot| #{entry.message}"
|
|
case entry.message
|
|
when /\Aimap-login: (.*)/ then @imap_login.collect entry, $1
|
|
when /\Aimap\([^)]+\)(?:<[^ ]+>)?: (.*)/ then @imap.collect entry, $1
|
|
when /\Almtp\([^ ]+\)<[^ ]+>: (.*)/ then @lmtp.collect entry, $1
|
|
when /\Almtp\([^ ]+\): (.*)/ then @lmtp.collect entry, $1
|
|
when /\Adeliver(?:[^:]+): (.*)/ then @deliver.collect entry, $1
|
|
when /\Aauth: Error: (.*)/
|
|
case $1
|
|
when /\ALDAP: Connection lost to LDAP server, /
|
|
@auth_errors.increment labels: {error: "ldap connection lost"}
|
|
else
|
|
STDERR.puts "# #{entry._systemd_unit} #{entry.syslog_identifier}| #{entry.message}"
|
|
@auth_errors.increment labels: {error: "<any>"}
|
|
end
|
|
else STDERR.puts "# #{entry._systemd_unit} #{entry.syslog_identifier}| #{entry.message}"
|
|
end
|
|
end
|
|
end
|