Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PowerDNS Recursor input plugin #4545

Merged
merged 2 commits into from
Apr 23, 2019
Merged
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,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