Add postfix input plugin (#2553)
This commit is contained in:
parent
2681be7caa
commit
2ae35591a0
|
@ -180,6 +180,7 @@ configuration options.
|
||||||
* [phpfpm](./plugins/inputs/phpfpm)
|
* [phpfpm](./plugins/inputs/phpfpm)
|
||||||
* [phusion passenger](./plugins/inputs/passenger)
|
* [phusion passenger](./plugins/inputs/passenger)
|
||||||
* [ping](./plugins/inputs/ping)
|
* [ping](./plugins/inputs/ping)
|
||||||
|
* [postfix](./plugins/inputs/postfix)
|
||||||
* [postgresql](./plugins/inputs/postgresql)
|
* [postgresql](./plugins/inputs/postgresql)
|
||||||
* [postgresql_extensible](./plugins/inputs/postgresql_extensible)
|
* [postgresql_extensible](./plugins/inputs/postgresql_extensible)
|
||||||
* [powerdns](./plugins/inputs/powerdns)
|
* [powerdns](./plugins/inputs/powerdns)
|
||||||
|
|
|
@ -64,6 +64,7 @@ import (
|
||||||
_ "github.com/influxdata/telegraf/plugins/inputs/passenger"
|
_ "github.com/influxdata/telegraf/plugins/inputs/passenger"
|
||||||
_ "github.com/influxdata/telegraf/plugins/inputs/phpfpm"
|
_ "github.com/influxdata/telegraf/plugins/inputs/phpfpm"
|
||||||
_ "github.com/influxdata/telegraf/plugins/inputs/ping"
|
_ "github.com/influxdata/telegraf/plugins/inputs/ping"
|
||||||
|
_ "github.com/influxdata/telegraf/plugins/inputs/postfix"
|
||||||
_ "github.com/influxdata/telegraf/plugins/inputs/postgresql"
|
_ "github.com/influxdata/telegraf/plugins/inputs/postgresql"
|
||||||
_ "github.com/influxdata/telegraf/plugins/inputs/postgresql_extensible"
|
_ "github.com/influxdata/telegraf/plugins/inputs/postgresql_extensible"
|
||||||
_ "github.com/influxdata/telegraf/plugins/inputs/powerdns"
|
_ "github.com/influxdata/telegraf/plugins/inputs/powerdns"
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
# Postfix Input Plugin
|
||||||
|
|
||||||
|
The postfix plugin reports metrics on the postfix queues.
|
||||||
|
|
||||||
|
For each of the active, hold, incoming, maildrop, and deferred queues (http://www.postfix.org/QSHAPE_README.html#queues), it will report the queue length (number of items), size (bytes used by items), and age (age of oldest item in seconds).
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[[inputs.postfix]]
|
||||||
|
## Postfix queue directory. If not provided, telegraf will try to use
|
||||||
|
## 'postconf -h queue_directory' to determine it.
|
||||||
|
# queue_directory = "/var/spool/postfix"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Measurements & Fields:
|
||||||
|
|
||||||
|
- postfix_queue
|
||||||
|
- length (integer)
|
||||||
|
- size (integer, bytes)
|
||||||
|
- age (integer, seconds)
|
||||||
|
|
||||||
|
### Tags:
|
||||||
|
|
||||||
|
- postfix_queue
|
||||||
|
- queue
|
||||||
|
|
||||||
|
### Example Output
|
||||||
|
|
||||||
|
```
|
||||||
|
postfix_queue,queue=active length=3,size=12345,age=9
|
||||||
|
postfix_queue,queue=hold length=0,size=0,age=0
|
||||||
|
postfix_queue,queue=maildrop length=1,size=2000,age=2
|
||||||
|
postfix_queue,queue=incoming length=1,size=1020,age=0
|
||||||
|
postfix_queue,queue=deferred length=400,size=76543210,age=3600
|
||||||
|
```
|
|
@ -0,0 +1,119 @@
|
||||||
|
package postfix
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/influxdata/telegraf"
|
||||||
|
"github.com/influxdata/telegraf/plugins/inputs"
|
||||||
|
)
|
||||||
|
|
||||||
|
const sampleConfig = `
|
||||||
|
## Postfix queue directory. If not provided, telegraf will try to use
|
||||||
|
## 'postconf -h queue_directory' to determine it.
|
||||||
|
# queue_directory = "/var/spool/postfix"
|
||||||
|
`
|
||||||
|
|
||||||
|
const description = "Measure postfix queue statistics"
|
||||||
|
|
||||||
|
func getQueueDirectory() (string, error) {
|
||||||
|
qd, err := exec.Command("postconf", "-h", "queue_directory").Output()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(string(qd)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func qScan(path string) (int64, int64, int64, error) {
|
||||||
|
f, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
finfos, err := f.Readdir(-1)
|
||||||
|
f.Close()
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var length, size int64
|
||||||
|
var oldest time.Time
|
||||||
|
for _, finfo := range finfos {
|
||||||
|
length++
|
||||||
|
size += finfo.Size()
|
||||||
|
if oldest.IsZero() || finfo.ModTime().Before(oldest) {
|
||||||
|
oldest = finfo.ModTime()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var age time.Duration
|
||||||
|
if !oldest.IsZero() {
|
||||||
|
age = time.Now().Sub(oldest) / time.Second
|
||||||
|
}
|
||||||
|
return length, size, int64(age), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Postfix struct {
|
||||||
|
QueueDirectory string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Postfix) Gather(acc telegraf.Accumulator) error {
|
||||||
|
if p.QueueDirectory == "" {
|
||||||
|
var err error
|
||||||
|
p.QueueDirectory, err = getQueueDirectory()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to determine queue directory: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, q := range []string{"active", "hold", "incoming", "maildrop"} {
|
||||||
|
length, size, age, err := qScan(path.Join(p.QueueDirectory, q))
|
||||||
|
if err != nil {
|
||||||
|
acc.AddError(fmt.Errorf("error scanning queue %s: %s", q, err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fields := map[string]interface{}{"length": length, "size": size, "age": age}
|
||||||
|
acc.AddFields("postfix_queue", fields, map[string]string{"queue": q})
|
||||||
|
}
|
||||||
|
|
||||||
|
var dLength, dSize, dAge int64
|
||||||
|
for _, q := range []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"} {
|
||||||
|
length, size, age, err := qScan(path.Join(p.QueueDirectory, "deferred", q))
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
// the directories are created on first use
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
acc.AddError(fmt.Errorf("error scanning queue deferred/%s: %s", q, err))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
dLength += length
|
||||||
|
dSize += size
|
||||||
|
if age > dAge {
|
||||||
|
dAge = age
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fields := map[string]interface{}{"length": dLength, "size": dSize, "age": dAge}
|
||||||
|
acc.AddFields("postfix_queue", fields, map[string]string{"queue": "deferred"})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Postfix) SampleConfig() string {
|
||||||
|
return sampleConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Postfix) Description() string {
|
||||||
|
return description
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
inputs.Add("postfix", func() telegraf.Input {
|
||||||
|
return &Postfix{
|
||||||
|
QueueDirectory: "/var/spool/postfix",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
package postfix
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/influxdata/telegraf/testutil"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGather(t *testing.T) {
|
||||||
|
td, err := ioutil.TempDir("", "")
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer os.RemoveAll(td)
|
||||||
|
|
||||||
|
for _, q := range []string{"active", "hold", "incoming", "maildrop", "deferred"} {
|
||||||
|
require.NoError(t, os.Mkdir(path.Join(td, q), 0755))
|
||||||
|
}
|
||||||
|
for _, q := range []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "F"} { // "E" deliberately left off
|
||||||
|
require.NoError(t, os.Mkdir(path.Join(td, "deferred", q), 0755))
|
||||||
|
}
|
||||||
|
|
||||||
|
require.NoError(t, ioutil.WriteFile(path.Join(td, "active", "01"), []byte("abc"), 0644))
|
||||||
|
require.NoError(t, ioutil.WriteFile(path.Join(td, "active", "02"), []byte("defg"), 0644))
|
||||||
|
require.NoError(t, os.Chtimes(path.Join(td, "active", "02"), time.Now(), time.Now().Add(-time.Hour)))
|
||||||
|
require.NoError(t, ioutil.WriteFile(path.Join(td, "hold", "01"), []byte("abc"), 0644))
|
||||||
|
require.NoError(t, ioutil.WriteFile(path.Join(td, "incoming", "01"), []byte("abcd"), 0644))
|
||||||
|
require.NoError(t, ioutil.WriteFile(path.Join(td, "deferred", "0", "01"), []byte("abc"), 0644))
|
||||||
|
require.NoError(t, ioutil.WriteFile(path.Join(td, "deferred", "F", "F1"), []byte("abc"), 0644))
|
||||||
|
|
||||||
|
p := Postfix{
|
||||||
|
QueueDirectory: td,
|
||||||
|
}
|
||||||
|
|
||||||
|
var acc testutil.Accumulator
|
||||||
|
require.NoError(t, p.Gather(&acc))
|
||||||
|
|
||||||
|
metrics := map[string]*testutil.Metric{}
|
||||||
|
for _, m := range acc.Metrics {
|
||||||
|
metrics[m.Tags["queue"]] = m
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, int64(2), metrics["active"].Fields["length"])
|
||||||
|
assert.Equal(t, int64(7), metrics["active"].Fields["size"])
|
||||||
|
assert.InDelta(t, int64(time.Hour/time.Second), metrics["active"].Fields["age"], 10)
|
||||||
|
|
||||||
|
assert.Equal(t, int64(1), metrics["hold"].Fields["length"])
|
||||||
|
assert.Equal(t, int64(3), metrics["hold"].Fields["size"])
|
||||||
|
|
||||||
|
assert.Equal(t, int64(1), metrics["incoming"].Fields["length"])
|
||||||
|
assert.Equal(t, int64(4), metrics["incoming"].Fields["size"])
|
||||||
|
|
||||||
|
assert.Equal(t, int64(0), metrics["maildrop"].Fields["length"])
|
||||||
|
assert.Equal(t, int64(0), metrics["maildrop"].Fields["size"])
|
||||||
|
assert.Equal(t, int64(0), metrics["maildrop"].Fields["age"])
|
||||||
|
|
||||||
|
assert.Equal(t, int64(2), metrics["deferred"].Fields["length"])
|
||||||
|
assert.Equal(t, int64(6), metrics["deferred"].Fields["size"])
|
||||||
|
}
|
Loading…
Reference in New Issue