class Collector attr_reader :journal, :prometheus, :settings class PrefixProxy attr_reader :prometheus, :prefix def initialize prometheus, prefix @prometheus, @prefix = prometheus, prefix.dup.freeze end def counter name, **options @prometheus.counter :"#{prefix}_#{name}", **options end def gauge name, **options @prometheus.gauge :"#{prefix}_#{name}", **options end def histogram name, **options @prometheus.histogram :"#{prefix}_#{name}", **options end def summary name, **options @prometheus.summary :"#{prefix}_#{name}", **options end def prefix_proxy prefix PrefixProxy.new @prometheus, "#{@prefix}_#{prefix}" end end def self.start prometheus: nil, journal: nil self.new( prometheus: prometheus, journal: journal).start end def initialize prometheus: nil, journal: nil, settings: nil @settings = settings @journal = journal || Systemd::Journal.new( flags: Systemd::Journal::Flags::SYSTEM_ONLY) @prometheus = prometheus || Prometheus::Client.registry def @prometheus.prefix_proxy prefix PrefixProxy.new self, prefix end @store = {} @errors = @prometheus.counter :postfix_exporter_errors_total, docstring: 'Count internal errors/exceptions' @dovecot = Dovecot.new @store, PrefixProxy.new( @prometheus, :dovecot) @postfix = Postfix.new @store, PrefixProxy.new( @prometheus, :postfix) end def run @journal.seek :tail @journal.move_previous @journal.watch do |entry| case entry._systemd_unit when 'dovecot.service' @dovecot.collect entry when 'postfix@-.service' @postfix.collect entry else if @settings.nil? or @settings.development? STDERR.puts "# unit: #{entry._systemd_unit}: #{entry.syslog_identifier} #{entry.message}" end end end end def start Thread.abort_on_exception = true Thread.new do begin run rescue SystemExit, Interrupt raise rescue Object @errors.increment STDERR.puts "#$! (#{$!.class})", $!.backtrace.map {|x| " in #{x}"} retry end end end end require_relative 'collector/postfix' require_relative 'collector/dovecot'