Skip to content

Commit

Permalink
Merge 79c0c22 into dc24c8b
Browse files Browse the repository at this point in the history
  • Loading branch information
andir committed May 27, 2017
2 parents dc24c8b + 79c0c22 commit c3b6b30
Show file tree
Hide file tree
Showing 6 changed files with 244 additions and 0 deletions.
5 changes: 5 additions & 0 deletions config_example.toml
Expand Up @@ -71,3 +71,8 @@ password = ""
[[database.connection.logging]]
enable = false
path = "/var/log/yanic.log"

[[database.connection.graphite]]
enable = false
address = "localhost:2003"
prefix = "freifunk"
1 change: 1 addition & 0 deletions database/all/main.go
@@ -1,6 +1,7 @@
package all

import (
_ "github.com/FreifunkBremen/yanic/database/graphite"
_ "github.com/FreifunkBremen/yanic/database/influxdb"
_ "github.com/FreifunkBremen/yanic/database/logging"
)
90 changes: 90 additions & 0 deletions database/graphite/database.go
@@ -0,0 +1,90 @@
package graphite

import (
"github.com/FreifunkBremen/yanic/database"
"github.com/fgrosse/graphigo"
"log"
"sync"
)

const (
MeasurementNode = "node" // Measurement for per-node statistics
MeasurementGlobal = "global" // Measurement for summarized global statistics
CounterMeasurementFirmware = "firmware" // Measurement for firmware statistics
CounterMeasurementModel = "model" // Measurement for model statistics
)

type Connection struct {
database.Connection
client graphigo.Client
points chan []graphigo.Metric
wg sync.WaitGroup
}

type Config map[string]interface{}

func (c Config) Address() string {
return c["address"].(string)
}

func (c Config) Prefix() string {
return c["prefix"].(string)
}

func (c Config) Enable() bool {
return c["enable"].(bool)
}

func Connect(configuration interface{}) (database.Connection, error) {
var config Config

config = configuration.(map[string]interface{})

if !config.Enable() {
return nil, nil
}

con := &Connection{
client: graphigo.Client{
Address: config.Address(),
Prefix: config.Prefix(),
},
points: make(chan []graphigo.Metric, 1000),
}

if err := con.client.Connect(); err != nil {
return nil, err
}

con.wg.Add(1)
go con.addWorker()

return con, nil
}

func (c *Connection) Close() {
close(c.points)
if c.client.Connection != nil {
c.client.Close()
}
}

func (c *Connection) addWorker() {
defer c.wg.Done()
defer c.Close()
for point := range c.points {
err := c.client.SendAll(point)
if err != nil {
log.Fatal(err)
return
}
}
}

func (c *Connection) addPoint(point []graphigo.Metric) {
c.points <- point
}

func init() {
database.RegisterAdapter("graphite", Connect)
}
33 changes: 33 additions & 0 deletions database/graphite/global.go
@@ -0,0 +1,33 @@
package graphite

import (
"time"

"github.com/FreifunkBremen/yanic/runtime"
"github.com/fgrosse/graphigo"
)

func (c *Connection) InsertGlobals(stats *runtime.GlobalStats, time time.Time) {
c.addPoint(GlobalStatsFields(stats))
c.addCounterMap(CounterMeasurementModel, stats.Models, time)
c.addCounterMap(CounterMeasurementFirmware, stats.Firmwares, time)
}

func GlobalStatsFields(stats *runtime.GlobalStats) []graphigo.Metric {
return []graphigo.Metric{
{Name: MeasurementGlobal + ".nodes", Value: stats.Nodes},
{Name: MeasurementGlobal + ".gateways", Value: stats.Gateways},
{Name: MeasurementGlobal + ".clients.total", Value: stats.Clients},
{Name: MeasurementGlobal + ".clients.wifi", Value: stats.ClientsWifi},
{Name: MeasurementGlobal + ".clients.wifi24", Value: stats.ClientsWifi24},
{Name: MeasurementGlobal + ".clients.wifi5", Value: stats.ClientsWifi5},
}
}

func (c *Connection) addCounterMap(name string, m runtime.CounterMap, t time.Time) {
var fields []graphigo.Metric
for key, count := range m {
fields = append(fields, graphigo.Metric{Name: name + `.` + key + `.count`, Value: count, Timestamp: t})
}
c.addPoint(fields)
}
109 changes: 109 additions & 0 deletions database/graphite/node.go
@@ -0,0 +1,109 @@
package graphite

import (
"strings"
"time"

"github.com/FreifunkBremen/yanic/runtime"
"github.com/fgrosse/graphigo"
)

// PruneNode implementation of database
func (c *Connection) PruneNodes(deleteAfter time.Duration) {
// we can't really delete nodes from graphite remotely :(
}

// InsertNode implementation of database
func (c *Connection) InsertNode(node *runtime.Node) {
var fields []graphigo.Metric

stats := node.Statistics

nodeinfo := node.Nodeinfo

if nodeinfo == nil {
return
}

node_prefix := MeasurementNode + `.` + stats.NodeID + `.` + strings.Replace(nodeinfo.Hostname, ".", "__", -1)

addField := func(name string, value interface{}) {
fields = append(fields, graphigo.Metric{Name: node_prefix + "." + name, Value: value})
}

if neighbours := node.Neighbours; neighbours != nil {
vpn := 0
if meshvpn := stats.MeshVPN; meshvpn != nil {
for _, group := range meshvpn.Groups {
for _, link := range group.Peers {
if link != nil && link.Established > 1 {
vpn++
}
}
}
}
addField("neighbours.vpn", vpn)
// protocol: Batman Advance
batadv := 0
for _, batadvNeighbours := range neighbours.Batadv {
batadv += len(batadvNeighbours.Neighbours)
}
addField("neighbours.batadv", batadv)

// protocol: LLDP
lldp := 0
for _, lldpNeighbours := range neighbours.LLDP {
lldp += len(lldpNeighbours)
}
addField("neighbours.lldp", lldp)

// total is the sum of all protocols
addField("neighbours.total", batadv+lldp)
}

if t := stats.Traffic.Rx; t != nil {
addField("traffic.rx.bytes", int64(t.Bytes))
addField("traffic.rx.packets", t.Packets)
}
if t := stats.Traffic.Tx; t != nil {
addField("traffic.tx.bytes", int64(t.Bytes))
addField("traffic.tx.packets", t.Packets)
addField("traffic.tx.dropped", t.Dropped)
}
if t := stats.Traffic.Forward; t != nil {
addField("traffic.forward.bytes", int64(t.Bytes))
addField("traffic.forward.packets", t.Packets)
}
if t := stats.Traffic.MgmtRx; t != nil {
addField("traffic.mgmt_rx.bytes", int64(t.Bytes))
addField("traffic.mgmt_rx.packets", t.Packets)
}
if t := stats.Traffic.MgmtTx; t != nil {
addField("traffic.mgmt_tx.bytes", int64(t.Bytes))
addField("traffic.mgmt_tx.packets", t.Packets)
}

for _, airtime := range stats.Wireless {
suffix := airtime.FrequencyName()
addField("airtime"+suffix+".chan_util", airtime.ChanUtil)
addField("airtime"+suffix+".rx_util", airtime.RxUtil)
addField("airtime"+suffix+".tx_util", airtime.TxUtil)
addField("airtime"+suffix+".noise", airtime.Noise)
addField("airtime"+suffix+".frequency", airtime.Frequency)
}

addField("load", stats.LoadAverage)
addField("time.up", int64(stats.Uptime))
addField("time.idle", int64(stats.Idletime))
addField("proc.running", stats.Processes.Running)
addField("clients.wifi", stats.Clients.Wifi)
addField("clients.wifi11a", stats.Clients.Wifi24)
addField("clients.wifi11g", stats.Clients.Wifi5)
addField("clients.total", stats.Clients.Total)
addField("memory.buffers", stats.Memory.Buffers)
addField("memory.cached", stats.Memory.Cached)
addField("memory.free", stats.Memory.Free)
addField("memory.total", stats.Memory.Total)

c.addPoint(fields)
}
6 changes: 6 additions & 0 deletions runtime/config_test.go
Expand Up @@ -30,4 +30,10 @@ func TestReadConfig(t *testing.T) {
assert.Len(dbs, 1, "more influxdb are given")
influxdb = dbs[0].(map[string]interface{})
assert.Equal(influxdb["database"], "ffhb")

var graphitedb map[string]interface{}
dbs = config.Database.Connection["graphite"]
assert.Len(dbs, 1, "more graphitedb are given")
graphitedb = dbs[0].(map[string]interface{})
assert.Equal(graphitedb["address"], "localhost:2003")
}

0 comments on commit c3b6b30

Please sign in to comment.