Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 146 additions & 0 deletions doc/Extensions/Applications/Dovecot.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# Dovecot

[Dovecot](https://www.dovecot.org/) is an open-source IMAP and POP3 server.

!!! note
This integration requires **Dovecot 2.4** or later. The statistics
system was redesigned in 2.4 and the metric definitions below are
not compatible with earlier versions.

## Dovecot configuration

Dovecot 2.4 requires metrics to be explicitly defined before
`doveadm stats dump` will return data. Add the following to your
Dovecot configuration (e.g. `/etc/dovecot/conf.d/10-stats.conf`):

```
##
## Statistics and metrics
##
## In Dovecot 2.4, metrics must be explicitly defined for
## doveadm stats dump to return data.
##

metric auth_success {
filter = event=auth_request_finished AND success=yes
}

metric auth_failures {
filter = event=auth_request_finished AND NOT success=yes
}

metric imap_command {
filter = event=imap_command_finished
}

metric smtp_command {
filter = event=smtp_server_command_finished
}

metric sieve_action {
filter = event=sieve_action_finished
}

metric mail_delivery {
filter = event=mail_delivery_finished
}
```

Reload Dovecot after making changes:

```bash
doveadm reload
```

Verify that statistics are being collected:

```bash
doveadm stats dump
```

## SNMP Extend

=== "SNMP Extend"

1. Install the collection script to the target host:

```bash
wget https://raw.githubusercontent.com/librenms/librenms-agent/master/snmp/dovecot-stats-snmp.sh \
-O /usr/local/bin/dovecot-stats-snmp.sh
```

2. Make the script executable:

```bash
chmod +x /usr/local/bin/dovecot-stats-snmp.sh
```

3. The script calls `doveadm stats dump` and `doveadm who`. The
`snmpd` daemon typically runs as an unprivileged user and may not
have permission to run `doveadm`. Grant access via sudo:

```bash
# /etc/sudoers.d/snmpd-dovecot
Debian-snmp ALL = NOPASSWD: /usr/bin/doveadm
```

Adjust the username to match the user `snmpd` runs as on your
system (e.g. `snmpd` on RHEL/Rocky, `Debian-snmp` on
Debian/Ubuntu). Then update the script to use sudo:

```bash
# At the top of /usr/local/bin/dovecot-stats-snmp.sh, set:
DOVEADM="sudo /usr/bin/doveadm"
```

4. Edit your snmpd configuration (usually `/etc/snmp/snmpd.conf`)
and add:

```bash
extend dovecot /usr/local/bin/dovecot-stats-snmp.sh
```

5. Restart snmpd:

=== "Systemd"

```bash
sudo systemctl restart snmpd
```

=== "Xinetd"

```bash
sudo service snmpd restart
```

6. Verify the extend is working:

```bash
snmpget -v2c -c <community> <host> \
'NET-SNMP-EXTEND-MIB::nsExtendOutputFull."dovecot"'
```

You should see a JSON array containing the collected metrics.

The application should be auto-discovered the next time LibreNMS
runs discovery against the host. If it is not, follow the steps
under the *Enable the application(s) to be discovered* section at
the top of the [Applications](../Applications.md) page.

## Graphs

The following graphs are available once the application is discovered
and polled:

| Graph | Description |
|-------|-------------|
| Connected Users & Sessions | Current number of connected users and active sessions |
| Authentication (rate) | Rate of successful and failed authentication attempts |
| Authentication Duration | Auth response times — avg, median, 95th percentile (µs) |
| IMAP Commands | IMAP command throughput and latency |
| SMTP Commands | SMTP command throughput and latency |
| Mail Delivery | Mail delivery throughput and latency |
| Sieve Actions | Sieve script action throughput and latency |

All duration values are in **microseconds**.
29 changes: 29 additions & 0 deletions includes/html/graphs/application/dovecot_auth.inc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

require 'includes/html/graphs/common.inc.php';

$scale_min = 0;
$nototal = 1;
$unit_text = 'Auth/s';
$unitlen = 10;
$bigdescrlen = 15;
$smalldescrlen = 15;
$colours = 'mixed';

$rrd_filename = Rrd::name($device['hostname'], ['app', 'dovecot', $app->app_id, 'auth']);

$array = [
'success' => 'Auth Success',
'failures' => 'Auth Failures',
];

$rrd_list = [];
$i = 0;
foreach ($array as $ds => $descr) {
$rrd_list[$i]['filename'] = $rrd_filename;
$rrd_list[$i]['descr'] = $descr;
$rrd_list[$i]['ds'] = $ds;
$i++;
}

require 'includes/html/graphs/generic_multi_line_exact_numbers.inc.php';
33 changes: 33 additions & 0 deletions includes/html/graphs/application/dovecot_auth_duration.inc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

require 'includes/html/graphs/common.inc.php';

$scale_min = 0;
$nototal = 1;
$unit_text = 'µs';
$unitlen = 10;
$bigdescrlen = 20;
$smalldescrlen = 15;
$colours = 'mixed';

$rrd_filename = Rrd::name($device['hostname'], ['app', 'dovecot', $app->app_id, 'auth_duration']);

$array = [
'succ_avg' => 'Success avg',
'succ_median' => 'Success median',
'succ_p95' => 'Success p95',
'fail_avg' => 'Failure avg',
'fail_median' => 'Failure median',
'fail_p95' => 'Failure p95',
];

$rrd_list = [];
$i = 0;
foreach ($array as $ds => $descr) {
$rrd_list[$i]['filename'] = $rrd_filename;
$rrd_list[$i]['descr'] = $descr;
$rrd_list[$i]['ds'] = $ds;
$i++;
}

require 'includes/html/graphs/generic_multi_line_exact_numbers.inc.php';
29 changes: 29 additions & 0 deletions includes/html/graphs/application/dovecot_connections.inc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

require 'includes/html/graphs/common.inc.php';

$scale_min = 0;
$nototal = 1;
$unit_text = 'Count';
$unitlen = 10;
$bigdescrlen = 15;
$smalldescrlen = 15;
$colours = 'mixed';

$rrd_filename = Rrd::name($device['hostname'], ['app', 'dovecot', $app->app_id, 'connections']);

$array = [
'users' => 'Connected Users',
'sessions' => 'Connected Sessions',
];

$rrd_list = [];
$i = 0;
foreach ($array as $ds => $descr) {
$rrd_list[$i]['filename'] = $rrd_filename;
$rrd_list[$i]['descr'] = $descr;
$rrd_list[$i]['ds'] = $ds;
$i++;
}

require 'includes/html/graphs/generic_multi_line_exact_numbers.inc.php';
31 changes: 31 additions & 0 deletions includes/html/graphs/application/dovecot_delivery.inc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

require 'includes/html/graphs/common.inc.php';

$scale_min = 0;
$nototal = 1;
$unit_text = 'Delivery';
$unitlen = 10;
$bigdescrlen = 20;
$smalldescrlen = 15;
$colours = 'mixed';

$rrd_filename = Rrd::name($device['hostname'], ['app', 'dovecot', $app->app_id, 'delivery']);

$array = [
'count' => 'Deliveries/s',
'avg' => 'Duration avg (µs)',
'median' => 'Duration median (µs)',
'p95' => 'Duration p95 (µs)',
];

$rrd_list = [];
$i = 0;
foreach ($array as $ds => $descr) {
$rrd_list[$i]['filename'] = $rrd_filename;
$rrd_list[$i]['descr'] = $descr;
$rrd_list[$i]['ds'] = $ds;
$i++;
}

require 'includes/html/graphs/generic_multi_line_exact_numbers.inc.php';
31 changes: 31 additions & 0 deletions includes/html/graphs/application/dovecot_imap.inc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

require 'includes/html/graphs/common.inc.php';

$scale_min = 0;
$nototal = 1;
$unit_text = 'IMAP';
$unitlen = 10;
$bigdescrlen = 20;
$smalldescrlen = 15;
$colours = 'mixed';

$rrd_filename = Rrd::name($device['hostname'], ['app', 'dovecot', $app->app_id, 'imap']);

$array = [
'count' => 'Commands/s',
'avg' => 'Duration avg (µs)',
'median' => 'Duration median (µs)',
'p95' => 'Duration p95 (µs)',
];

$rrd_list = [];
$i = 0;
foreach ($array as $ds => $descr) {
$rrd_list[$i]['filename'] = $rrd_filename;
$rrd_list[$i]['descr'] = $descr;
$rrd_list[$i]['ds'] = $ds;
$i++;
}

require 'includes/html/graphs/generic_multi_line_exact_numbers.inc.php';
31 changes: 31 additions & 0 deletions includes/html/graphs/application/dovecot_sieve.inc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

require 'includes/html/graphs/common.inc.php';

$scale_min = 0;
$nototal = 1;
$unit_text = 'Sieve';
$unitlen = 10;
$bigdescrlen = 20;
$smalldescrlen = 15;
$colours = 'mixed';

$rrd_filename = Rrd::name($device['hostname'], ['app', 'dovecot', $app->app_id, 'sieve']);

$array = [
'count' => 'Actions/s',
'avg' => 'Duration avg (µs)',
'median' => 'Duration median (µs)',
'p95' => 'Duration p95 (µs)',
];

$rrd_list = [];
$i = 0;
foreach ($array as $ds => $descr) {
$rrd_list[$i]['filename'] = $rrd_filename;
$rrd_list[$i]['descr'] = $descr;
$rrd_list[$i]['ds'] = $ds;
$i++;
}

require 'includes/html/graphs/generic_multi_line_exact_numbers.inc.php';
31 changes: 31 additions & 0 deletions includes/html/graphs/application/dovecot_smtp.inc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

require 'includes/html/graphs/common.inc.php';

$scale_min = 0;
$nototal = 1;
$unit_text = 'SMTP';
$unitlen = 10;
$bigdescrlen = 20;
$smalldescrlen = 15;
$colours = 'mixed';

$rrd_filename = Rrd::name($device['hostname'], ['app', 'dovecot', $app->app_id, 'smtp']);

$array = [
'count' => 'Commands/s',
'avg' => 'Duration avg (µs)',
'median' => 'Duration median (µs)',
'p95' => 'Duration p95 (µs)',
];

$rrd_list = [];
$i = 0;
foreach ($array as $ds => $descr) {
$rrd_list[$i]['filename'] = $rrd_filename;
$rrd_list[$i]['descr'] = $descr;
$rrd_list[$i]['ds'] = $ds;
$i++;
}

require 'includes/html/graphs/generic_multi_line_exact_numbers.inc.php';
9 changes: 9 additions & 0 deletions includes/html/pages/apps.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,15 @@
'peers',
'total_bytes',
];
$graphs['dovecot'] = [
'connections',
'auth',
'auth_duration',
'imap',
'smtp',
'delivery',
'sieve',
];

echo '<div class="panel panel-default">';
echo '<div class="panel-heading">';
Expand Down
Loading