Skip to content

Commit

Permalink
Add PowerDNS Recursor input plugin (#4545)
Browse files Browse the repository at this point in the history
  • Loading branch information
dupondje authored and danielnelson committed Apr 23, 2019
1 parent c71827e commit a020274
Show file tree
Hide file tree
Showing 6 changed files with 856 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ For documentation on the latest development code see the [documentation index][d
* [postgresql_extensible](./plugins/inputs/postgresql_extensible)
* [postgresql](./plugins/inputs/postgresql)
* [powerdns](./plugins/inputs/powerdns)
* [powerdns_recursor](./plugins/inputs/powerdns_recursor)
* [processes](./plugins/inputs/processes)
* [procstat](./plugins/inputs/procstat)
* [prometheus](./plugins/inputs/prometheus) (can be used for [Caddy server](./plugins/inputs/prometheus/README.md#usage-for-caddy-http-server))
Expand Down
14 changes: 14 additions & 0 deletions etc/telegraf.conf
Original file line number Diff line number Diff line change
Expand Up @@ -3346,6 +3346,20 @@
# unix_sockets = ["/var/run/pdns.controlsocket"]


# # Read metrics from one or many PowerDNS recursors
# [[inputs.powerdns_recursor]]
# ## An array of sockets to gather stats about.
# ## Specify a path to unix socket.
# ##
# ## If no servers are specified, then '/var/run/pdns_recursor.controlsocket' is used as the path.
# unix_sockets = ["/var/run/pdns_recursor.controlsocket"]
#
# ## Socket for Receive
# # socket_dir = "/var/run/"
# ## Socket permissions
# # socket_mode = "0666"


# # Monitor process cpu and memory usage
# [[inputs.procstat]]
# ## PID file to monitor process
Expand Down
1 change: 1 addition & 0 deletions plugins/inputs/all/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ import (
_ "github.com/influxdata/telegraf/plugins/inputs/postgresql"
_ "github.com/influxdata/telegraf/plugins/inputs/postgresql_extensible"
_ "github.com/influxdata/telegraf/plugins/inputs/powerdns"
_ "github.com/influxdata/telegraf/plugins/inputs/powerdns_recursor"
_ "github.com/influxdata/telegraf/plugins/inputs/processes"
_ "github.com/influxdata/telegraf/plugins/inputs/procstat"
_ "github.com/influxdata/telegraf/plugins/inputs/prometheus"
Expand Down
139 changes: 139 additions & 0 deletions plugins/inputs/powerdns_recursor/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# PowerDNS Recursor Input Plugin

The powerdns recursor plugin gathers metrics about PowerDNS Recursor using unix socket.

### Configuration:

```
# Read metrics from one or many PowerDNS recursors
[[inputs.powerdns_recursor]]
## An array of sockets to gather stats about.
## Specify a path to unix socket.
##
## If no servers are specified, then '/var/run/pdns_recursor.controlsocket' is used as the path.
unix_sockets = ["/var/run/pdns_recursor.controlsocket"]
## Socket for Receive
# socket_dir = "/var/run/"
## Socket permissions
# socket_mode = "0666"
```

### Measurements & Fields:

- powerdns_recursor
- all-outqueries
- answers-slow
- answers0-1
- answers1-10
- answers10-100
- answers100-1000
- auth-zone-queries
- auth4-answers-slow
- auth4-answers0-1
- auth4-answers1-10
- auth4-answers10-100
- auth4-answers100-1000
- auth6-answers-slow
- auth6-answers0-1
- auth6-answers1-10
- auth6-answers10-100
- auth6-answers100-1000
- cache-entries
- cache-hits
- cache-misses
- case-mismatches
- chain-resends
- client-parse-errors
- concurrent-queries
- dlg-only-drops
- dnssec-queries
- dnssec-result-bogus
- dnssec-result-indeterminate
- dnssec-result-insecure
- dnssec-result-nta
- dnssec-result-secure
- dnssec-validations
- dont-outqueries
- ecs-queries
- ecs-responses
- edns-ping-matches
- edns-ping-mismatches
- failed-host-entries
- fd-usage
- ignored-packets
- ipv6-outqueries
- ipv6-questions
- malloc-bytes
- max-cache-entries
- max-mthread-stack
- max-packetcache-entries
- negcache-entries
- no-packet-error
- noedns-outqueries
- noerror-answers
- noping-outqueries
- nsset-invalidations
- nsspeeds-entries
- nxdomain-answers
- outgoing-timeouts
- outgoing4-timeouts
- outgoing6-timeouts
- over-capacity-drops
- packetcache-entries
- packetcache-hits
- packetcache-misses
- policy-drops
- policy-result-custom
- policy-result-drop
- policy-result-noaction
- policy-result-nodata
- policy-result-nxdomain
- policy-result-truncate
- qa-latency
- query-pipe-full-drops
- questions
- real-memory-usage
- resource-limits
- security-status
- server-parse-errors
- servfail-answers
- spoof-prevents
- sys-msec
- tcp-client-overflow
- tcp-clients
- tcp-outqueries
- tcp-questions
- throttle-entries
- throttled-out
- throttled-outqueries
- too-old-drops
- udp-in-errors
- udp-noport-errors
- udp-recvbuf-errors
- udp-sndbuf-errors
- unauthorized-tcp
- unauthorized-udp
- unexpected-packets
- unreachables
- uptime
- user-msec
- x-our-latency
- x-ourtime-slow
- x-ourtime0-1
- x-ourtime1-2
- x-ourtime16-32
- x-ourtime2-4
- x-ourtime4-8
- x-ourtime8-16

### Tags:

- tags: `server=socket`

### Example Output:

```
$ ./telegraf --config telegraf.conf --input-filter powerdns_recursor --test
> powerdns_recursor,server=/var/run/pdns_recursor.controlsocket all-outqueries=3631810i,answers-slow=36863i,answers0-1=179612i,answers1-10=1223305i,answers10-100=1252199i,answers100-1000=408357i,auth-zone-queries=4i,auth4-answers-slow=44758i,auth4-answers0-1=59721i,auth4-answers1-10=1766787i,auth4-answers10-100=1329638i,auth4-answers100-1000=430372i,auth6-answers-slow=0i,auth6-answers0-1=0i,auth6-answers1-10=0i,auth6-answers10-100=0i,auth6-answers100-1000=0i,cache-entries=296689i,cache-hits=150654i,cache-misses=2949682i,case-mismatches=0i,chain-resends=420004i,client-parse-errors=0i,concurrent-queries=0i,dlg-only-drops=0i,dnssec-queries=152970i,dnssec-result-bogus=0i,dnssec-result-indeterminate=0i,dnssec-result-insecure=0i,dnssec-result-nta=0i,dnssec-result-secure=47i,dnssec-validations=47i,dont-outqueries=62i,ecs-queries=0i,ecs-responses=0i,edns-ping-matches=0i,edns-ping-mismatches=0i,failed-host-entries=21i,fd-usage=32i,ignored-packets=0i,ipv6-outqueries=0i,ipv6-questions=0i,malloc-bytes=0i,max-cache-entries=1000000i,max-mthread-stack=33747i,max-packetcache-entries=500000i,negcache-entries=100019i,no-packet-error=0i,noedns-outqueries=73341i,noerror-answers=25453808i,noping-outqueries=0i,nsset-invalidations=2398i,nsspeeds-entries=3966i,nxdomain-answers=3341302i,outgoing-timeouts=44384i,outgoing4-timeouts=44384i,outgoing6-timeouts=0i,over-capacity-drops=0i,packetcache-entries=78258i,packetcache-hits=25999027i,packetcache-misses=3100179i,policy-drops=0i,policy-result-custom=0i,policy-result-drop=0i,policy-result-noaction=3100336i,policy-result-nodata=0i,policy-result-nxdomain=0i,policy-result-truncate=0i,qa-latency=6553i,query-pipe-full-drops=0i,questions=29099363i,real-memory-usage=280494080i,resource-limits=0i,security-status=1i,server-parse-errors=0i,servfail-answers=304253i,spoof-prevents=0i,sys-msec=1312600i,tcp-client-overflow=0i,tcp-clients=0i,tcp-outqueries=116i,tcp-questions=133i,throttle-entries=21i,throttled-out=13296i,throttled-outqueries=13296i,too-old-drops=2i,udp-in-errors=4i,udp-noport-errors=2918i,udp-recvbuf-errors=0i,udp-sndbuf-errors=0i,unauthorized-tcp=0i,unauthorized-udp=0i,unexpected-packets=0i,unreachables=1708i,uptime=167482i,user-msec=1282640i,x-our-latency=19i,x-ourtime-slow=642i,x-ourtime0-1=3095566i,x-ourtime1-2=3401i,x-ourtime16-32=201i,x-ourtime2-4=304i,x-ourtime4-8=198i,x-ourtime8-16=24i 1533903879000000000
```
156 changes: 156 additions & 0 deletions plugins/inputs/powerdns_recursor/powerdns_recursor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package powerdns_recursor

import (
"bufio"
"errors"
"fmt"
"log"
"math/rand"
"net"
"os"
"path/filepath"
"strconv"
"strings"
"time"

"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/inputs"
)

type PowerdnsRecursor struct {
UnixSockets []string

SocketDir string `toml:"socket_dir"`
SocketMode uint32 `toml:"socket_mode"`
}

var defaultTimeout = 5 * time.Second

var sampleConfig = `
## An array of sockets to gather stats about.
## Specify a path to unix socket.
unix_sockets = ["/var/run/pdns_recursor.controlsocket"]
## Socket for Receive
#socket_dir = "/var/run/"
## Socket permissions
#socket_mode = "0666"
`

func (p *PowerdnsRecursor) SampleConfig() string {
return sampleConfig
}

func (p *PowerdnsRecursor) Description() string {
return "Read metrics from one or many PowerDNS Recursor servers"
}

func (p *PowerdnsRecursor) Gather(acc telegraf.Accumulator) error {
if len(p.UnixSockets) == 0 {
return p.gatherServer("/var/run/pdns_recursor.controlsocket", acc)
}

for _, serverSocket := range p.UnixSockets {
if err := p.gatherServer(serverSocket, acc); err != nil {
acc.AddError(err)
}
}

return nil
}

func (p *PowerdnsRecursor) gatherServer(address string, acc telegraf.Accumulator) error {
randomNumber := rand.Int63()
recvSocket := filepath.Join("/", "var", "run", fmt.Sprintf("pdns_recursor_telegraf%d", randomNumber))
if p.SocketDir != "" {
recvSocket = filepath.Join(p.SocketDir, fmt.Sprintf("pdns_recursor_telegraf%d", randomNumber))
}

laddr, err := net.ResolveUnixAddr("unixgram", recvSocket)
if err != nil {
return err
}
defer os.Remove(recvSocket)
raddr, err := net.ResolveUnixAddr("unixgram", address)
if err != nil {
return err
}
conn, err := net.DialUnix("unixgram", laddr, raddr)
if err != nil {
return err
}
perm := uint32(0666)
if p.SocketMode > 0 {
perm = p.SocketMode
}
if err := os.Chmod(recvSocket, os.FileMode(perm)); err != nil {
return err
}
defer conn.Close()

conn.SetDeadline(time.Now().Add(defaultTimeout))

// Read and write buffer
rw := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))

// Send command
if _, err := fmt.Fprint(rw, "get-all\n"); err != nil {
return nil
}
if err := rw.Flush(); err != nil {
return err
}

// Read data
buf := make([]byte, 16384)
n, err := rw.Read(buf)
if err != nil {
return err
}
if n == 0 {
return errors.New("no data received")
}

metrics := string(buf)

// Process data
fields := parseResponse(metrics)

// Add server socket as a tag
tags := map[string]string{"server": address}

acc.AddFields("powerdns_recursor", fields, tags)

conn.Close()

return nil
}

func parseResponse(metrics string) map[string]interface{} {
values := make(map[string]interface{})

s := strings.Split(metrics, "\n")

for _, metric := range s[:len(s)-1] {
m := strings.Split(metric, "\t")
if len(m) < 2 {
continue
}

i, err := strconv.ParseInt(m[1], 10, 64)
if err != nil {
log.Printf("E! [inputs.powerdns_recursor] Error parsing integer for metric [%s] %v",
metric, err)
continue
}
values[m[0]] = i
}

return values
}

func init() {
inputs.Add("powerdns_recursor", func() telegraf.Input {
return &PowerdnsRecursor{}
})
}
Loading

0 comments on commit a020274

Please sign in to comment.