Prometheus metrics for Dovecot

This commit is contained in:
Julian Rother 2025-02-09 02:01:45 +01:00
parent 71eb192c73
commit b1ce5b3e84
Signed by: julian
GPG key ID: C19B924C0CD13341
5 changed files with 106 additions and 0 deletions

View file

@ -136,6 +136,7 @@ service quota-status {
client_limit = 1
}
# Metrics
service stats {
unix_listener stats-reader {
user = vmail
@ -149,6 +150,31 @@ service stats {
# 0666 instead of 0660, so postfixadmin can call doveadm pw without errors
mode = 0666
}
inet_listener http {
port = 9900
}
}
metric auths {
filter = event=auth_request_finished
}
metric auth_successes {
filter = event=auth_request_finished AND success=yes
}
metric imap_commands {
filter = event=imap_command_finished
group_by = cmd_name tagged_reply_state duration:exponential:1:9:10
}
metric sieve_actions {
filter = event=sieve_action_finished
group_by = action_name
}
metric mail_deliveries {
filter = event=mail_delivery_finished
}
# Postfix delivers incoming mails via lda (transport "dovecot")

View file

@ -0,0 +1,47 @@
#!/usr/bin/python3
import time
import subprocess
import json
from prometheus_client import start_http_server, PROCESS_COLLECTOR, PLATFORM_COLLECTOR, GC_COLLECTOR
from prometheus_client.core import GaugeMetricFamily, CounterMetricFamily, REGISTRY
from prometheus_client.registry import Collector
class CustomCollector(Collector):
def collect(self):
service_status = json.loads(subprocess.run(['doveadm', '-f', 'json', 'service', 'status'], check=True, capture_output=True).stdout.decode())
process_status = json.loads(subprocess.run(['doveadm', '-f', 'json', 'process', 'status'], check=True, capture_output=True).stdout.decode())
dovecot_processes_count = GaugeMetricFamily('dovecot_processes_count', 'Number of running processes per service', labels=['service'])
dovecot_processes_total = CounterMetricFamily('dovecot_processes_total', 'Total count of started processes per service', labels=['service'])
dovecot_processes_limit = GaugeMetricFamily('dovecot_processes_limit', 'Process limit per service', labels=['service'])
dovecot_clients_count = GaugeMetricFamily('dovecot_clients_count', 'Number of connected clients per service', labels=['service'])
dovecot_clients_total = CounterMetricFamily('dovecot_clients_total', 'Total count of clients per service', labels=['service'])
dovecot_clients_per_process_limit = GaugeMetricFamily('dovecot_clients_per_process_limit', 'Client limit per process', labels=['service'])
for line in service_status:
dovecot_processes_count.add_metric([line['name']], int(line['process_count']))
dovecot_processes_total.add_metric([line['name']], int(line['process_total']))
dovecot_processes_limit.add_metric([line['name']], int(line['process_limit']))
dovecot_clients_count.add_metric(
[line['name']],
sum(int(line['client_limit'])-int(proc['available_count']) for proc in process_status if proc['name'] == line['name'])
)
dovecot_clients_total.add_metric(
[line['name']],
sum(int(proc['total_count']) for proc in process_status if proc['name'] == line['name'])
)
dovecot_clients_per_process_limit.add_metric([line['name']], int(line['client_limit']))
yield dovecot_processes_count
yield dovecot_processes_total
yield dovecot_processes_limit
yield dovecot_clients_count
yield dovecot_clients_total
yield dovecot_clients_per_process_limit
REGISTRY.unregister(PROCESS_COLLECTOR)
REGISTRY.unregister(PLATFORM_COLLECTOR)
REGISTRY.unregister(GC_COLLECTOR)
REGISTRY.register(CustomCollector())
if __name__ == '__main__':
start_http_server(addr='127.0.0.1', port=9162)
while True:
time.sleep(100)

View file

@ -0,0 +1,12 @@
[Unit]
Description=Dovecot master prometheus exporter
After=dovecot.service
Requisite=dovecot.service
[Install]
WantedBy=multi-user.target
[Service]
ExecStart=/usr/bin/python3 /usr/local/sbin/prometheus-dovecot-master-exporter
Environment=PYTHONUNBUFFERED=1
Restart=always