postfix-exporter 2.0.3 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +17 -2
  3. data/bin/postfix-exporter +65 -4
  4. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d6e9b995c8c56b28d9500d51b20a8857b3fdcc44
4
- data.tar.gz: 34c495ffd68b19de2c65c5297e58a7d197a0f705
3
+ metadata.gz: 59a89aac9e188bb3a7a5cf1617425bd797ebf68f
4
+ data.tar.gz: d7fd70f12daadfd79a90c66efce6c862afd31b00
5
5
  SHA512:
6
- metadata.gz: 1483d066cc63929f244a0337f0c61ab2740d9d105fcc1af92881b79c0a5a819da42e81b64d82cccf5855853f3ef04342a4f09836d89e66fac545f48f0754e224
7
- data.tar.gz: 8a1f46107f17a18d6d9ca6b64c2e6b6ad6e0a4b7f2e489495640af5ec82b8b08f371f741c31438b46fa39b935cf76c7304f98db1c58c9606a9369efac71052c2
6
+ metadata.gz: 0e51b58b74c279e81a3a88f9e3322f95f363571a6e959d14a8f3ebf1b3d77a5f899821f0673a9b347c1a9906574983bbc8ba297667917238a18eb933da55daed
7
+ data.tar.gz: 6e6ecffdb49e584e2592ba7d69bdc08fb67efd1abc4162024b7511a5e97a393ef6bc643ca8d44993744b0230d26d434b3eda8adff91d143b5c224ba3c12d9a02
data/README.md CHANGED
@@ -7,8 +7,18 @@ server.
7
7
  * Examines mail queue periodically and exports `postfix_mail_queue_size`;
8
8
 
9
9
  * Reads syslog entries as they happen, and exports disposition status
10
- counters (`postfix_disposition`) per DSN, as well as delay summaries per
11
- DSN;
10
+ counters (`postfix_delivery_delays_count`) per DSN, as well as delay summaries per
11
+ DSN (`postfix_delivery_delays{quantile="..."}`);
12
+
13
+ * Total number of SMTP connections (`postfix_smtpd_connections_total`) and
14
+ currently-active connections (`postfix_smtpd_active_connections`);
15
+
16
+ * Count how many delivery attempts were received
17
+ (`postfix_incoming_delivery_attempts_total`), split out by whether we
18
+ accepted or rejected the message (`status`) and the exact DSN provided to
19
+ the client (`dsn`);
20
+
21
+ * Whether or not the Postfix `master` process is running (`postfix_up`);
12
22
 
13
23
  * Drinks from the syslog stream directly.
14
24
 
@@ -21,6 +31,11 @@ available in the container as `/var/spool/postfix`), and some env
21
31
  vars. You can also run it directly (via the gem), with the same env vars,
22
32
  and with the expectation that `/var/spool/postfix` is in the usual place.
23
33
 
34
+ If you configure the postfix-exporter to run in the same PID namespace as
35
+ whatever it is that's running Postfix itself (either `--pid=host` or in the
36
+ same NS namespace, a la k8s pods), then the `postfix_up` metric will be
37
+ valid, otherwise it'll be random (but unlikely to be correct).
38
+
24
39
 
25
40
  ## Environment Variables
26
41
 
@@ -8,7 +8,11 @@ require 'logger'
8
8
 
9
9
  prometheus = Prometheus::Client.registry
10
10
 
11
+ prometheus.gauge(:postfix_exporter_start_time_seconds, "When this process started up").set({}, Time.now.to_f)
12
+
11
13
  mailq = prometheus.gauge(:postfix_queue_size, "Number of messages in the mail queue")
14
+ q_err = prometheus.counter(:postfix_queue_processing_error_total, "Exceptions raised whilst scanning the Postfix queue")
15
+ up = prometheus.gauge(:postfix_up, "Whether the master process is running or not")
12
16
 
13
17
  Thread.abort_on_exception = true
14
18
 
@@ -22,18 +26,49 @@ Thread.new do
22
26
  # deferred is special, because it's often hueg it gets sharded into
23
27
  # multiple subdirectories
24
28
  mailq.set({ queue: 'deferred' }, Dir["/var/spool/postfix/deferred/*/*"].size)
25
-
26
- sleep 5
27
29
  rescue StandardError => ex
28
30
  $stderr.puts "Error while monitoring queue sizes: #{ex.message} (#{ex.class})"
29
31
  $stderr.puts ex.backtrace.map { |l| " #{l}" }.join("\n")
30
- sleep 1
32
+ q_err.increment(class: ex.class.to_s, phase: "scan")
31
33
  end
34
+
35
+ begin
36
+ master_pid = File.read("/var/spool/postfix/pid/master.pid").to_i
37
+
38
+ if master_pid > 1
39
+ Process.kill(0, master_pid)
40
+ # If we get here, then the process exists, and
41
+ # that'll do for our purposes
42
+ up.set({}, 1)
43
+ else
44
+ up.set({}, 0)
45
+ end
46
+ rescue Errno::ENOENT, Errno::ESRCH, Errno::EACCES
47
+ up.set({}, 0)
48
+ rescue Errno::EPERM
49
+ # Ironically, we don't need to be able to *actually*
50
+ # signal the process; EPERM means it exists and is running
51
+ # as someone more privileged than us, which is enough
52
+ # for our purposes
53
+ up.set({}, 1)
54
+ rescue StandardError => ex
55
+ $stderr.puts "Error while checking master process: #{ex.message} (#{ex.class})"
56
+ $stderr.puts ex.backtrace.map { |l| " #{l}" }.join("\n")
57
+ q_err.increment(class: ex.class.to_s, phase: "up")
58
+ end
59
+
60
+ sleep 5
61
+
32
62
  end
33
63
  end
34
64
 
35
65
  if ENV["SYSLOG_SOCKET"]
36
- delays = prometheus.summary(:postfix_delivery_delays, "Distribution of time taken to deliver (or bounce) messages")
66
+ delays = prometheus.summary(:postfix_delivery_delays, "Distribution of time taken to deliver (or bounce) messages")
67
+ connects = prometheus.counter(:postfix_smtpd_connections_total, "Connections to smtpd")
68
+ active = prometheus.gauge(:postfix_smtpd_active_connections, "Current connections to smtpd")
69
+ incoming = prometheus.counter(:postfix_incoming_delivery_attempts_total, "Delivery attempts, labelled by dsn and status")
70
+ messages = prometheus.counter(:postfix_log_messages_total, "Syslog messages received, labelled by how it was handled")
71
+ log_errors = prometheus.counter(:postfix_log_processing_error_total, "Exceptions raised whilst processing log messages")
37
72
 
38
73
  Thread.new do
39
74
  begin
@@ -55,10 +90,36 @@ if ENV["SYSLOG_SOCKET"]
55
90
  if status == "bounced" or status == "sent"
56
91
  delays.observe({dsn: dsn, status: status}, delay)
57
92
  end
93
+
94
+ messages.increment(type: "delay")
95
+ elsif msg =~ %r{postfix/smtpd\[\d+\]: connect from }
96
+ connects.increment({})
97
+ active.send(:synchronize) { active.set({}, active.get({}) || 0 + 1) }
98
+ messages.increment(type: "connect")
99
+ elsif msg =~ %r{postfix/smtpd\[\d+\]: disconnect from }
100
+ active.send(:synchronize) do
101
+ new = (active.get({}) || 0) - 1
102
+ # If we start running mid-stream,
103
+ # we might end up seeing more
104
+ # disconnects than connections,
105
+ # which would be confusing
106
+ new = 0 if new < 0
107
+ active.set({}, new)
108
+ end
109
+ messages.increment(type: "disconnect")
110
+ elsif msg =~ %r{postfix/smtpd\[\d+\]: [A-F0-9]+: client=}
111
+ incoming.increment(dsn: "2.0.0", status: "queued")
112
+ messages.increment(type: "queued")
113
+ elsif msg =~ %r{postfix/smtpd\[\d+\]: NOQUEUE: reject: RCPT from \S+: \d{3} (\d+\.\d+\.\d+) }
114
+ incoming.increment(dsn: $1, status: "rejected")
115
+ messages.increment(type: "noqueue")
116
+ else
117
+ messages.increment(type: "ignored")
58
118
  end
59
119
  rescue StandardError => ex
60
120
  $stderr.puts "Error while receiving postfix logs: #{ex.message} (#{ex.class})"
61
121
  $stderr.puts ex.backtrace.map { |l| " #{l}" }.join("\n")
122
+ log_errors.increment(class: ex.class.to_s)
62
123
  sleep 1
63
124
  end
64
125
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: postfix-exporter
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Palmer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-07-05 00:00:00.000000000 Z
11
+ date: 2018-01-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: prometheus-client
@@ -118,7 +118,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
118
118
  version: '0'
119
119
  requirements: []
120
120
  rubyforge_project:
121
- rubygems_version: 2.5.2
121
+ rubygems_version: 2.6.13
122
122
  signing_key:
123
123
  specification_version: 4
124
124
  summary: Export Prometheus statistics for a Postfix server