Merge pull request #120 from hafkensite/master

Add capsman station metric
This commit is contained in:
Steve Brunton 2021-08-09 21:57:10 -04:00 committed by GitHub
commit 4bfa7adfef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 144 additions and 4 deletions

View File

@ -0,0 +1,127 @@
package collector
import (
"strconv"
"strings"
"github.com/prometheus/client_golang/prometheus"
log "github.com/sirupsen/logrus"
"gopkg.in/routeros.v2/proto"
)
type capsmanCollector struct {
props []string
descriptions map[string]*prometheus.Desc
}
func newCapsmanCollector() routerOSCollector {
c := &capsmanCollector{}
c.init()
return c
}
func (c *capsmanCollector) init() {
//"rx-signal", "tx-signal",
c.props = []string{"interface", "mac-address", "ssid", "uptime", "tx-signal", "rx-signal", "packets", "bytes"}
labelNames := []string{"name", "address", "interface", "mac_address", "ssid"}
c.descriptions = make(map[string]*prometheus.Desc)
for _, p := range c.props[3 : len(c.props)-2] {
c.descriptions[p] = descriptionForPropertyName("capsman_station", p, labelNames)
}
for _, p := range c.props[len(c.props)-2:] {
c.descriptions["tx_"+p] = descriptionForPropertyName("capsman_station", "tx_"+p, labelNames)
c.descriptions["rx_"+p] = descriptionForPropertyName("capsman_station", "rx_"+p, labelNames)
}
}
func (c *capsmanCollector) describe(ch chan<- *prometheus.Desc) {
for _, d := range c.descriptions {
ch <- d
}
}
func (c *capsmanCollector) 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 *capsmanCollector) fetch(ctx *collectorContext) ([]*proto.Sentence, error) {
reply, err := ctx.client.Run("/caps-man/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 *capsmanCollector) collectForStat(re *proto.Sentence, ctx *collectorContext) {
iface := re.Map["interface"]
mac := re.Map["mac-address"]
ssid := re.Map["ssid"]
for _, p := range c.props[3 : len(c.props)-2] {
c.collectMetricForProperty(p, iface, mac, ssid, re, ctx)
}
for _, p := range c.props[len(c.props)-2:] {
c.collectMetricForTXRXCounters(p, iface, mac, ssid, re, ctx)
}
}
func (c *capsmanCollector) collectMetricForProperty(property, iface, mac, ssid 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]
}
var v float64
var err error
if property != "uptime" {
v, err = strconv.ParseFloat(p, 64)
} else {
v, err = parseDuration(p)
}
if err != nil {
log.WithFields(log.Fields{
"device": ctx.device.Name,
"property": property,
"value": re.Map[property],
"error": err,
}).Error("error parsing capsman station metric value")
return
}
desc := c.descriptions[property]
ctx.ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, v, ctx.device.Name, ctx.device.Address, iface, mac, ssid)
}
func (c *capsmanCollector) collectMetricForTXRXCounters(property, iface, mac, ssid 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 capsman 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, ssid)
ctx.ch <- prometheus.MustNewConstMetric(desc_rx, prometheus.CounterValue, rx, ctx.device.Name, ctx.device.Address, iface, mac, ssid)
}

View File

@ -139,6 +139,13 @@ func WithWlanSTA() Option {
} }
} }
// WithWlanIF enables wireless interface metrics
func WithCapsman() Option {
return func(c *collector) {
c.collectors = append(c.collectors, newCapsmanCollector())
}
}
// WithWlanIF enables wireless interface metrics // WithWlanIF enables wireless interface metrics
func WithWlanIF() Option { func WithWlanIF() Option {
return func(c *collector) { return func(c *collector) {

View File

@ -13,11 +13,11 @@ import (
) )
var durationRegex *regexp.Regexp var durationRegex *regexp.Regexp
var durationParts [5]time.Duration var durationParts [6]time.Duration
func init() { func init() {
durationRegex = regexp.MustCompile(`(?:(\d*)w)?(?:(\d*)d)?(?:(\d*)h)?(?:(\d*)m)?(?:(\d*)s)?`) durationRegex = regexp.MustCompile(`(?:(\d*)w)?(?:(\d*)d)?(?:(\d*)h)?(?:(\d*)m)?(?:(\d*)s)?(?:(\d*)ms)?`)
durationParts = [5]time.Duration{time.Hour * 168, time.Hour * 24, time.Hour, time.Minute, time.Second} durationParts = [6]time.Duration{time.Hour * 168, time.Hour * 24, time.Hour, time.Minute, time.Second, time.Millisecond}
} }
func metricStringCleanup(in string) string { func metricStringCleanup(in string) string {
@ -39,7 +39,7 @@ func descriptionForPropertyNameHelpText(prefix, property string, labelNames []st
func description(prefix, name, helpText string, labelNames []string) *prometheus.Desc { func description(prefix, name, helpText string, labelNames []string) *prometheus.Desc {
return prometheus.NewDesc( return prometheus.NewDesc(
prometheus.BuildFQName(namespace, prefix, name), prometheus.BuildFQName(namespace, prefix, metricStringCleanup(name)),
helpText, helpText,
labelNames, labelNames,
nil, nil,

View File

@ -24,6 +24,7 @@ type Config struct {
Optics bool `yaml:"optics,omitempty"` Optics bool `yaml:"optics,omitempty"`
W60G bool `yaml:"w60g,omitempty"` W60G bool `yaml:"w60g,omitempty"`
WlanSTA bool `yaml:"wlansta,omitempty"` WlanSTA bool `yaml:"wlansta,omitempty"`
Capsman bool `yaml:"capsman,omitempty"`
WlanIF bool `yaml:"wlanif,omitempty"` WlanIF bool `yaml:"wlanif,omitempty"`
Monitor bool `yaml:"monitor,omitempty"` Monitor bool `yaml:"monitor,omitempty"`
Ipsec bool `yaml:"ipsec,omitempty"` Ipsec bool `yaml:"ipsec,omitempty"`

View File

@ -50,6 +50,7 @@ var (
withW60G = flag.Bool("with-w60g", false, "retrieves w60g interface metrics") withW60G = flag.Bool("with-w60g", false, "retrieves w60g interface metrics")
withWlanSTA = flag.Bool("with-wlansta", false, "retrieves connected wlan station metrics") withWlanSTA = flag.Bool("with-wlansta", false, "retrieves connected wlan station metrics")
withWlanIF = flag.Bool("with-wlanif", false, "retrieves wlan interface metrics") withWlanIF = flag.Bool("with-wlanif", false, "retrieves wlan interface metrics")
withCapsman = flag.Bool("with-capsman", false, "retrieves capsman station metrics")
withMonitor = flag.Bool("with-monitor", false, "retrieves ethernet interface monitor info") withMonitor = flag.Bool("with-monitor", false, "retrieves ethernet interface monitor info")
withIpsec = flag.Bool("with-ipsec", false, "retrieves ipsec metrics") withIpsec = flag.Bool("with-ipsec", false, "retrieves ipsec metrics")
withLte = flag.Bool("with-lte", false, "retrieves lte metrics") withLte = flag.Bool("with-lte", false, "retrieves lte metrics")
@ -238,6 +239,10 @@ func collectorOptions() []collector.Option {
opts = append(opts, collector.WithWlanSTA()) opts = append(opts, collector.WithWlanSTA())
} }
if *withCapsman || cfg.Features.Capsman {
opts = append(opts, collector.WithCapsman())
}
if *withWlanIF || cfg.Features.WlanIF { if *withWlanIF || cfg.Features.WlanIF {
opts = append(opts, collector.WithWlanIF()) opts = append(opts, collector.WithWlanIF())
} }