Skip to content

Instantly share code, notes, and snippets.

@markuskont
Last active April 6, 2016 12:56
Show Gist options
  • Save markuskont/44cd787dd0ebe3dda43b to your computer and use it in GitHub Desktop.
Save markuskont/44cd787dd0ebe3dda43b to your computer and use it in GitHub Desktop.
Use go to parse bind nameserver XML stats output (statistics-channel)
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="/bind9.xsl"?>
<isc version="1.0">
<bind>
<statistics version="2.2">
<views>
<view>
<name>_default</name>
<resstat>
<name>Queryv4</name>
<counter>123</counter>
</resstat>
<cache name="_default"/>
</view>
<view>
<name>_bind</name>
<zones>
<zone>
<name>authors.bind/CH</name>
<rdataclass>CH</rdataclass>
<serial>0</serial>
</zone>
</zones>
<resstat>
<name>Queryv4</name>
<counter>0</counter>
</resstat>
<resstat>
<name>Queryv6</name>
<counter>0</counter>
</resstat>
<cache name="_bind"/>
</view>
</views>
<server>
<nsstat>
<name>Requestv4</name>
<counter>0</counter>
</nsstat>
<nsstat>
<name>Requestv6</name>
<counter>0</counter>
</nsstat>
</server>
</statistics>
</bind>
</isc>
package bind9
import (
"net/http"
"encoding/xml"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/inputs"
)
type Bind9 struct {
Host string `toml:"host"`
Port string `toml:"port"`
}
func (s *Bind9) Description() string {
return "a bind9 plugin"
}
func (s *Bind9) SampleConfig() string {
return `
# bind9 stats channel
host = "127.0.0.1"
# bind9 stats port
port = 8080
`
}
type Root struct {
IscVersion string `xml:"version,attr"`
ViewList []View `xml:"bind>statistics>views>view"`
ServerStats []Server `xml:"bind>statistics>server"`
}
type View struct {
Name string `xml:"name"`
QueryStat []Stat `xml:"resstat"`
RRStat []Stat `xml:"rdtype"`
}
type Server struct {
NameServerStat []Stat `xml:"nsstat"`
ZoneStat []Stat `xml:"zonestat"`
SocketStat []Stat `xml:"sockstat"`
}
type Stat struct {
Name string `xml:"name"`
Counter int `xml:"counter"`
}
func (s *Bind9) Gather(acc telegraf.Accumulator) error {
c := "http://" + s.Host + ":" + s.Port
r, e := http.Get(c)
if e != nil {
return e
} else {
defer r.Body.Close()
var q Root
fields := make(map[string]interface{})
tags := make(map[string]string)
xml.NewDecoder(r.Body).Decode(&q)
for _, v := range q.ServerStats {
for _, vv := range v.NameServerStat {
fields[vv.Name] = vv.Counter
}
for _, vv := range v.ZoneStat {
fields[vv.Name] = vv.Counter
}
for _, vv := range v.SocketStat {
fields[vv.Name] = vv.Counter
}
acc.AddFields("bind9", fields, nil)
}
for k := range fields { delete(fields, k) }
for _, v := range q.ViewList {
tags["view"] = v.Name
for _, vv := range v.QueryStat {
fields[vv.Name] = vv.Counter
}
for _, vv := range v.RRStat {
fields[vv.Name] = vv.Counter
}
acc.AddFields("bind9", fields, tags)
for k := range fields { delete(fields, k) }
}
}
return nil
}
func init() {
inputs.Add("bind9", func() telegraf.Input {
return &Bind9{}
})
}
package main
import (
"os"
"fmt"
"encoding/xml"
"strconv"
)
type Root struct {
IscVersion string `xml:"version,attr"`
ViewList []View `xml:"bind>statistics>views>view"`
ServerStats []Server `xml:"bind>statistics>server"`
}
type View struct {
Name string `xml:"name"`
QueryStat []Stat `xml:"resstat"`
RRStat []Stat `xml:"rdtype"`
}
type Server struct {
NameServerStat []Stat `xml:"nsstat"`
ZoneStat []Stat `xml:"zonestat"`
SocketStat []Stat `xml:"sockstat"`
}
type Stat struct {
Name string `xml:"name"`
Counter int `xml:"counter"`
}
func main() {
xmlFile, err := os.Open("index.html")
if err != nil {
fmt.Println("Error opening file:", err)
return
}
defer xmlFile.Close()
var query Root
xml.NewDecoder(xmlFile).Decode(&query)
// Print for debug
fmt.Println(query.IscVersion)
fmt.Println(query.ViewList)
for _, view := range query.ViewList {
fmt.Printf("\t%s\n", view.Name)
for _, stat := range view.QueryStat {
c := strconv.Itoa(stat.Counter)
fmt.Printf("\t\t%s:%s\n", stat.Name, c)
}
for _, stat := range view.RRStat {
c := strconv.Itoa(stat.Counter)
fmt.Printf("\t\t%s:%s\n", stat.Name, c)
}
}
fmt.Println("Server stats")
for _, statType := range query.ServerStats {
for _, stat := range statType.NameServerStat {
c := strconv.Itoa(stat.Counter)
fmt.Printf("\t\t%s:%s\n", stat.Name, c)
}
for _, stat := range statType.ZoneStat {
c := strconv.Itoa(stat.Counter)
fmt.Printf("\t\t%s:%s\n", stat.Name, c)
}
for _, stat := range statType.SocketStat {
c := strconv.Itoa(stat.Counter)
fmt.Printf("\t\t%s:%s\n", stat.Name, c)
}
}
}
package main
import (
"fmt"
"net/http"
"encoding/xml"
"os"
"strconv"
)
type Root struct {
IscVersion string `xml:"version,attr"`
ViewList []View `xml:"bind>statistics>views>view"`
ServerStats []Server `xml:"bind>statistics>server"`
}
type View struct {
Name string `xml:"name"`
QueryStat []Stat `xml:"resstat"`
RRStat []Stat `xml:"rdtype"`
}
type Server struct {
NameServerStat []Stat `xml:"nsstat"`
ZoneStat []Stat `xml:"zonestat"`
SocketStat []Stat `xml:"sockstat"`
}
type Stat struct {
Name string `xml:"name"`
Counter int `xml:"counter"`
}
func main() {
response, err := http.Get("http://127.0.0.1:8080")
if err != nil {
fmt.Printf("%s", err)
os.Exit(1)
} else {
defer response.Body.Close()
if err != nil {
fmt.Printf("%s", err)
os.Exit(1)
}
var query Root
xml.NewDecoder(response.Body).Decode(&query)
// Print for debug
fmt.Println(query.IscVersion)
fmt.Println(query.ViewList)
for _, view := range query.ViewList {
fmt.Printf("\t%s\n", view.Name)
for _, stat := range view.QueryStat {
c := strconv.Itoa(stat.Counter)
fmt.Printf("\t\t%s:%s\n", stat.Name, c)
}
for _, stat := range view.RRStat {
c := strconv.Itoa(stat.Counter)
fmt.Printf("\t\t%s:%s\n", stat.Name, c)
}
}
fmt.Println("Server stats")
for _, statType := range query.ServerStats {
for _, stat := range statType.NameServerStat {
c := strconv.Itoa(stat.Counter)
fmt.Printf("\t\t%s:%s\n", stat.Name, c)
}
for _, stat := range statType.ZoneStat {
c := strconv.Itoa(stat.Counter)
fmt.Printf("\t\t%s:%s\n", stat.Name, c)
}
for _, stat := range statType.SocketStat {
c := strconv.Itoa(stat.Counter)
fmt.Printf("\t\t%s:%s\n", stat.Name, c)
}
}
}
}
# -*- mode: ruby -*-
# vi: set ft=ruby :
$NS = <<SCRIPT
sudo cat <<REPO >> /etc/apt/sources.list
deb http://http.us.debian.org/debian/ testing non-free contrib main
REPO
sudo apt-get update
sudo apt-get install -y bind9 vim htop tmux git golang/testing < /dev/null
sudo cat <<BASHRC | sudo tee -a /root/.bashrc /home/vagrant/.bashrc
alias ls='ls $LS_OPTIONS'
alias ll='ls $LS_OPTIONS -la'
export GOPATH=/home/vagrant
BASHRC
sudo cat <<VIMRC | sudo tee -a /root/.vimrc /home/vagrant/.vimrc
syntax on
VIMRC
sudo cat <<STATS >> /etc/bind/named.conf.local
statistics-channels {
inet 127.0.0.1 port 8080 allow { 127.0.0.1; };
};
STATS
sudo service bind9 restart
wget -q -O influx.deb https://s3.amazonaws.com/influxdb/influxdb_0.11.1-1_amd64.deb
sudo dpkg -i influx.deb
sudo service influxdb start
#wget -q -O telegraf.deb http://get.influxdb.org/telegraf/telegraf_0.12.0-1_amd64.deb
#sudo dpkg -i telegraf.deb
#sudo service telegraf start
sudo chown -R vagrant:vagrant /home/vagrant/
SCRIPT
boxes = [
{
:name => "ns1",
:mem => "2048",
:cpu => "4",
:ip => "192.168.56.199"
},
]
Vagrant.configure(2) do |config|
config.vm.box = "debian/jessie64"
boxes.each do |opts|
config.vm.define opts[:name] do |config|
config.vm.hostname = opts[:name]
config.vm.network 'private_network', ip: opts[:ip]
config.vm.provider "virtualbox" do |v|
v.customize ["modifyvm", :id, "--memory", opts[:mem]]
v.customize ["modifyvm", :id, "--cpus", opts[:cpu]]
end
config.vm.provision "shell", inline: $NS
config.vm.synced_folder ".", "/home/vagrant/src/github.com/influxdata/telegraf"
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment