mirror of
https://github.com/nshttpd/mikrotik-exporter.git
synced 2024-11-24 11:37:04 +01:00
aa5ef26ed3
signal-strength-ch0 is only accurate for devices with one antenna. Many mikrotik devices have two, or even three channels, and just looking at ch0 is not helpful in those cases. Instead, look at the property 'signal-strength'. Annoyingly, it is does come as a string with the negotiated bandwidth attached (e.g., signal-strength=-66dBm@HT20-7) which needs to be parsed out.
120 lines
3.4 KiB
Go
120 lines
3.4 KiB
Go
package collector
|
|
|
|
import (
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
log "github.com/sirupsen/logrus"
|
|
"gopkg.in/routeros.v2/proto"
|
|
)
|
|
|
|
type wlanSTACollector struct {
|
|
props []string
|
|
descriptions map[string]*prometheus.Desc
|
|
}
|
|
|
|
func newWlanSTACollector() routerOSCollector {
|
|
c := &wlanSTACollector{}
|
|
c.init()
|
|
return c
|
|
}
|
|
|
|
func (c *wlanSTACollector) init() {
|
|
c.props = []string{"interface", "mac-address", "signal-to-noise", "signal-strength", "packets", "bytes", "frames"}
|
|
labelNames := []string{"name", "address", "interface", "mac_address"}
|
|
c.descriptions = make(map[string]*prometheus.Desc)
|
|
for _, p := range c.props[:len(c.props)-3] {
|
|
c.descriptions[p] = descriptionForPropertyName("wlan_station", p, labelNames)
|
|
}
|
|
for _, p := range c.props[len(c.props)-3:] {
|
|
c.descriptions["tx_"+p] = descriptionForPropertyName("wlan_station", "tx_"+p, labelNames)
|
|
c.descriptions["rx_"+p] = descriptionForPropertyName("wlan_station", "rx_"+p, labelNames)
|
|
}
|
|
}
|
|
|
|
func (c *wlanSTACollector) describe(ch chan<- *prometheus.Desc) {
|
|
for _, d := range c.descriptions {
|
|
ch <- d
|
|
}
|
|
}
|
|
|
|
func (c *wlanSTACollector) collect(ctx *collectorContext) error {
|
|
stats, err := c.fetch(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, re := range stats {
|
|
c.collectForStat(re, ctx)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *wlanSTACollector) fetch(ctx *collectorContext) ([]*proto.Sentence, error) {
|
|
reply, err := ctx.client.Run("/interface/wireless/registration-table/print", "=.proplist="+strings.Join(c.props, ","))
|
|
if err != nil {
|
|
log.WithFields(log.Fields{
|
|
"device": ctx.device.Name,
|
|
"error": err,
|
|
}).Error("error fetching wlan station metrics")
|
|
return nil, err
|
|
}
|
|
|
|
return reply.Re, nil
|
|
}
|
|
|
|
func (c *wlanSTACollector) collectForStat(re *proto.Sentence, ctx *collectorContext) {
|
|
iface := re.Map["interface"]
|
|
mac := re.Map["mac-address"]
|
|
|
|
for _, p := range c.props[2 : len(c.props)-3] {
|
|
c.collectMetricForProperty(p, iface, mac, re, ctx)
|
|
}
|
|
for _, p := range c.props[len(c.props)-3:] {
|
|
c.collectMetricForTXRXCounters(p, iface, mac, re, ctx)
|
|
}
|
|
}
|
|
|
|
func (c *wlanSTACollector) collectMetricForProperty(property, iface, mac string, re *proto.Sentence, ctx *collectorContext) {
|
|
if re.Map[property] == "" {
|
|
return
|
|
}
|
|
p := re.Map[property]
|
|
i := strings.Index(p, "@")
|
|
if i > -1 {
|
|
p = p[:i]
|
|
}
|
|
v, err := strconv.ParseFloat(p, 64)
|
|
if err != nil {
|
|
log.WithFields(log.Fields{
|
|
"device": ctx.device.Name,
|
|
"property": property,
|
|
"value": re.Map[property],
|
|
"error": err,
|
|
}).Error("error parsing wlan station metric value")
|
|
return
|
|
}
|
|
|
|
desc := c.descriptions[property]
|
|
ctx.ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, v, ctx.device.Name, ctx.device.Address, iface, mac)
|
|
}
|
|
|
|
func (c *wlanSTACollector) collectMetricForTXRXCounters(property, iface, mac string, re *proto.Sentence, ctx *collectorContext) {
|
|
tx, rx, err := splitStringToFloats(re.Map[property])
|
|
if err != nil {
|
|
log.WithFields(log.Fields{
|
|
"device": ctx.device.Name,
|
|
"property": property,
|
|
"value": re.Map[property],
|
|
"error": err,
|
|
}).Error("error parsing wlan station metric value")
|
|
return
|
|
}
|
|
desc_tx := c.descriptions["tx_"+property]
|
|
desc_rx := c.descriptions["rx_"+property]
|
|
ctx.ch <- prometheus.MustNewConstMetric(desc_tx, prometheus.CounterValue, tx, ctx.device.Name, ctx.device.Address, iface, mac)
|
|
ctx.ch <- prometheus.MustNewConstMetric(desc_rx, prometheus.CounterValue, rx, ctx.device.Name, ctx.device.Address, iface, mac)
|
|
}
|