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

@ -1,6 +1,13 @@
- name: restart dovecot - name: restart dovecot
service: name=dovecot state=restarted service: name=dovecot state=restarted
- name: restart prometheus-dovecot-master-exporter
ansible.builtin.systemd_service:
name: prometheus-dovecot-master-exporter
state: restarted
enabled: true
daemon_reload: true
- name: restart postfix - name: restart postfix
service: name=postfix state=restarted service: name=postfix state=restarted

View file

@ -127,6 +127,20 @@
ansible.builtin.shell: "sievec '{{ item.dest }}'" ansible.builtin.shell: "sievec '{{ item.dest }}'"
loop: "{{ mailserver_sieve_scripts.results }}" loop: "{{ mailserver_sieve_scripts.results }}"
- name: copy prometheus-dovecot-master-exporter
ansible.builtin.template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
mode: "{{ item.mode }}"
loop:
- src: dovecot/prometheus-dovecot-master-exporter.j2
dest: /usr/local/sbin/prometheus-dovecot-master-exporter
mode: "0755"
- src: dovecot/prometheus-dovecot-master-exporter.service.j2
dest: /etc/systemd/system/prometheus-dovecot-master-exporter.service
mode: "0644"
notify: restart prometheus-dovecot-master-exporter
# prometheus-postfix-exporter # prometheus-postfix-exporter
- name: configure prometheus postfix exporter - name: configure prometheus postfix exporter
ansible.builtin.template: ansible.builtin.template:

View file

@ -136,6 +136,7 @@ service quota-status {
client_limit = 1 client_limit = 1
} }
# Metrics
service stats { service stats {
unix_listener stats-reader { unix_listener stats-reader {
user = vmail user = vmail
@ -149,6 +150,31 @@ service stats {
# 0666 instead of 0660, so postfixadmin can call doveadm pw without errors # 0666 instead of 0660, so postfixadmin can call doveadm pw without errors
mode = 0666 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") # 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