2021-02-26 08:15:12 +01:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"os"
|
2021-03-11 22:31:30 +01:00
|
|
|
"reflect"
|
2021-02-26 08:15:12 +01:00
|
|
|
"strconv"
|
2021-02-26 22:33:39 +01:00
|
|
|
"strings"
|
2021-02-26 08:15:12 +01:00
|
|
|
"sync"
|
2023-03-04 22:44:07 +01:00
|
|
|
"fmt"
|
2021-02-26 08:15:12 +01:00
|
|
|
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
|
|
"github.com/trazfr/freebox-exporter/fbx"
|
|
|
|
"github.com/trazfr/freebox-exporter/log"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
metricPrefix = "freebox_"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2021-03-11 22:31:30 +01:00
|
|
|
promDescExporterInfo = prometheus.NewDesc(
|
|
|
|
metricPrefix+"exporter_info",
|
|
|
|
"constant metric with value=1. Information about the Freebox Exporter",
|
|
|
|
[]string{"url", "api_version"}, nil)
|
2021-02-26 08:15:12 +01:00
|
|
|
promDescInfo = prometheus.NewDesc(
|
|
|
|
metricPrefix+"info",
|
2021-02-27 11:15:08 +01:00
|
|
|
"constant metric with value=1. Various information about the Freebox",
|
2023-03-04 22:44:07 +01:00
|
|
|
[]string{"firmware", "mac", "serial", "boardname", "box_flavor", "connection_type", "connection_state", "connection_media", "ipv4", "ipv6", "ipv4_port_range"}, nil)
|
2021-02-26 08:15:12 +01:00
|
|
|
|
|
|
|
promDescSystemUptime = prometheus.NewDesc(
|
|
|
|
metricPrefix+"system_uptime",
|
|
|
|
"freebox uptime (in seconds)",
|
|
|
|
nil, nil)
|
|
|
|
promDescSystemTemp = prometheus.NewDesc(
|
|
|
|
metricPrefix+"system_temp_degrees",
|
|
|
|
"temperature (°C)",
|
|
|
|
[]string{"id"}, nil)
|
|
|
|
promDescSystemFanRpm = prometheus.NewDesc(
|
|
|
|
metricPrefix+"system_fan_rpm",
|
|
|
|
"fan rpm",
|
|
|
|
[]string{"id"}, nil)
|
2023-03-04 22:07:11 +01:00
|
|
|
promDescConnectionRatesBytes = prometheus.NewDesc(
|
|
|
|
metricPrefix+"connection_rates_bytes",
|
|
|
|
"current upload/download rates in bytes/s",
|
|
|
|
[]string{"dir"}, nil) // rx/tx
|
2021-03-11 22:31:30 +01:00
|
|
|
promDescConnectionBandwidthBytes = prometheus.NewDesc(
|
2022-09-27 22:45:37 +02:00
|
|
|
metricPrefix+"connection_bandwidth_bytes",
|
2021-03-11 22:31:30 +01:00
|
|
|
"available upload/download bandwidth in bytes/s",
|
2022-09-27 22:45:37 +02:00
|
|
|
[]string{"dir"}, nil) // rx/tx
|
2021-02-26 08:15:12 +01:00
|
|
|
promDescConnectionBytes = prometheus.NewDesc(
|
|
|
|
metricPrefix+"connection_bytes",
|
|
|
|
"total uploaded/downloaded bytes since last connection",
|
2022-09-27 22:45:37 +02:00
|
|
|
[]string{"dir"}, nil) // rx/tx
|
2021-02-26 22:33:39 +01:00
|
|
|
|
2021-02-26 08:15:12 +01:00
|
|
|
promDescConnectionXdslInfo = prometheus.NewDesc(
|
|
|
|
metricPrefix+"connection_xdsl_info",
|
2021-02-27 11:15:08 +01:00
|
|
|
"constant metric with value=1. Various information about the XDSL connection",
|
2021-02-26 08:15:12 +01:00
|
|
|
[]string{"status", "protocol", "modulation"}, nil)
|
|
|
|
promDescConnectionXdslUptime = prometheus.NewDesc(
|
|
|
|
metricPrefix+"connection_xdsl_uptime",
|
|
|
|
"uptime in seconds",
|
|
|
|
nil, nil)
|
2021-03-11 22:31:30 +01:00
|
|
|
promDescConnectionXdslMaxRateBytes = prometheus.NewDesc(
|
|
|
|
metricPrefix+"connection_xdsl_maxrate_bytes",
|
|
|
|
"ATM max rate in bytes/s",
|
2022-09-27 22:45:37 +02:00
|
|
|
[]string{"dir"}, nil) // rx/tx
|
2021-03-11 22:31:30 +01:00
|
|
|
promDescConnectionXdslRateBytes = prometheus.NewDesc(
|
|
|
|
metricPrefix+"connection_xdsl_rate_bytes",
|
|
|
|
"ATM rate in bytes/s",
|
2022-09-27 22:45:37 +02:00
|
|
|
[]string{"dir"}, nil) // rx/tx
|
2021-02-26 08:15:12 +01:00
|
|
|
promDescConnectionXdslSnr = prometheus.NewDesc(
|
|
|
|
metricPrefix+"connection_xdsl_snr_db",
|
|
|
|
"in Db",
|
2022-09-27 22:45:37 +02:00
|
|
|
[]string{"dir"}, nil) // rx/tx
|
2021-02-26 08:15:12 +01:00
|
|
|
promDescConnectionXdslAttn = prometheus.NewDesc(
|
|
|
|
metricPrefix+"connection_xdsl_attn_db",
|
|
|
|
"in Db",
|
2022-09-27 22:45:37 +02:00
|
|
|
[]string{"dir"}, nil) // rx/tx
|
2021-02-26 22:33:39 +01:00
|
|
|
|
2021-02-28 12:34:59 +01:00
|
|
|
promDescConnectionFtthSfpPresent = prometheus.NewDesc(
|
|
|
|
metricPrefix+"connection_ftth_sfp_present",
|
|
|
|
"value=1 if the SFP is present",
|
|
|
|
[]string{"sfp_serial", "sfp_model", "sfp_vendor"}, nil)
|
|
|
|
promDescConnectionFtthSfpAlimOk = prometheus.NewDesc(
|
|
|
|
metricPrefix+"connection_ftth_sfp_alim_ok",
|
|
|
|
"value=1 if the SFP's alimentation is OK",
|
|
|
|
[]string{"sfp_serial", "sfp_model", "sfp_vendor"}, nil)
|
|
|
|
promDescConnectionFtthSfpHasPowerReport = prometheus.NewDesc(
|
|
|
|
metricPrefix+"connection_ftth_sfp_has_power_report",
|
|
|
|
"value=1 if the SFP has a power report ("+metricPrefix+"connection_fttp_sfp_pwr_dbm)",
|
|
|
|
[]string{"sfp_serial", "sfp_model", "sfp_vendor"}, nil)
|
|
|
|
promDescConnectionFtthSfpHasSignal = prometheus.NewDesc(
|
|
|
|
metricPrefix+"connection_ftth_sfp_has_signal",
|
|
|
|
"value=1 if the SFP has a signal",
|
|
|
|
[]string{"sfp_serial", "sfp_model", "sfp_vendor"}, nil)
|
|
|
|
promDescConnectionFtthLink = prometheus.NewDesc(
|
|
|
|
metricPrefix+"connection_ftth_link",
|
|
|
|
"value=1 if the link is OK",
|
|
|
|
[]string{"sfp_serial", "sfp_model", "sfp_vendor"}, nil)
|
2021-02-26 08:15:12 +01:00
|
|
|
promDescConnectionFtthSfpPwr = prometheus.NewDesc(
|
|
|
|
metricPrefix+"connection_fttp_sfp_pwr_dbm",
|
2021-02-28 12:34:59 +01:00
|
|
|
"SFP power report in Dbm",
|
|
|
|
[]string{"sfp_serial", "sfp_model", "sfp_vendor", "dir"}, nil) // rx/tx
|
2021-02-26 22:33:39 +01:00
|
|
|
|
2021-02-28 12:14:20 +01:00
|
|
|
promDescSwitchPortConnectedTotal = prometheus.NewDesc(
|
|
|
|
metricPrefix+"switch_port_connected_total",
|
2021-02-27 11:15:08 +01:00
|
|
|
"number of ports connnected",
|
2021-02-26 22:33:39 +01:00
|
|
|
nil, nil)
|
2021-03-11 22:31:30 +01:00
|
|
|
promDescSwitchPortBandwidthBytes = prometheus.NewDesc(
|
|
|
|
metricPrefix+"switch_port_bandwidth_bytes",
|
|
|
|
"in bytes/s",
|
2021-02-26 22:33:39 +01:00
|
|
|
[]string{"id", "link", "duplex"}, nil) // rx/tx
|
2021-03-11 22:31:30 +01:00
|
|
|
promDescSwitchPortPackets = prometheus.NewDesc(
|
|
|
|
metricPrefix+"switch_port_packets",
|
|
|
|
"total rx/tx packets",
|
|
|
|
[]string{"id", "dir", "state"}, nil) // rx/tx, good/bad
|
2021-02-26 22:33:39 +01:00
|
|
|
promDescSwitchPortBytes = prometheus.NewDesc(
|
|
|
|
metricPrefix+"switch_port_bytes",
|
|
|
|
"total rx/tx bytes",
|
|
|
|
[]string{"id", "dir", "state"}, nil) // rx/tx, good/bad
|
2021-02-28 12:14:20 +01:00
|
|
|
promDescSwitchHostTotal = prometheus.NewDesc(
|
|
|
|
metricPrefix+"switch_host_total",
|
2021-02-27 21:36:56 +01:00
|
|
|
"number of hosts connected to the switch",
|
|
|
|
[]string{"id"}, nil)
|
2021-02-26 22:33:39 +01:00
|
|
|
promDescSwitchHost = prometheus.NewDesc(
|
|
|
|
metricPrefix+"switch_host",
|
2021-02-27 11:15:08 +01:00
|
|
|
"constant metric with value=1. List of MAC addresses connected to the switch",
|
2021-02-27 21:36:56 +01:00
|
|
|
[]string{"id", "mac", "hostname"}, nil)
|
|
|
|
|
2021-02-28 12:14:20 +01:00
|
|
|
promDescWifiBssInfo = prometheus.NewDesc(
|
|
|
|
metricPrefix+"wifi_bss_info",
|
|
|
|
"constant metric with value=1. Various information about the BSS",
|
2021-03-11 22:31:30 +01:00
|
|
|
[]string{"bssid", "ap_id", "state", "enabled", "ssid", "hide_ssid", "encryption", "eapol_version"}, nil)
|
2021-02-28 12:14:20 +01:00
|
|
|
promDescWifiBssStationTotal = prometheus.NewDesc(
|
|
|
|
metricPrefix+"wifi_bss_station_total",
|
|
|
|
"number of stations on this BSS",
|
|
|
|
[]string{"bssid", "ap_id"}, nil)
|
|
|
|
promDescWifiBssAuthorizedStationTotal = prometheus.NewDesc(
|
|
|
|
metricPrefix+"wifi_bss_authorized_station_total",
|
|
|
|
"number of stations authorized on this BSS",
|
|
|
|
[]string{"bssid", "ap_id"}, nil)
|
|
|
|
|
2021-02-27 21:36:56 +01:00
|
|
|
promDescWifiApChannel = prometheus.NewDesc(
|
2021-03-11 22:31:30 +01:00
|
|
|
metricPrefix+"wifi_channel",
|
|
|
|
"channel number use by the AP",
|
2021-02-28 11:44:31 +01:00
|
|
|
[]string{"ap_id", "ap_band", "ap_name", "channel_type"}, nil)
|
2021-02-28 12:14:20 +01:00
|
|
|
promDescWifiApStationTotal = prometheus.NewDesc(
|
|
|
|
metricPrefix+"wifi_station_total",
|
2021-02-27 21:36:56 +01:00
|
|
|
"number of stations connected to the AP",
|
|
|
|
[]string{"ap_id", "ap_band", "ap_name"}, nil)
|
2021-03-11 22:31:30 +01:00
|
|
|
promDescWifiApStationInfo = prometheus.NewDesc(
|
|
|
|
metricPrefix+"wifi_station_info",
|
2021-02-27 21:36:56 +01:00
|
|
|
"1 if active, 0 if not",
|
|
|
|
[]string{"ap_id", "ap_band", "ap_name", "id", "bssid", "ssid", "encryption", "hostname", "mac"}, nil)
|
|
|
|
promDescWifiApStationBytes = prometheus.NewDesc(
|
|
|
|
metricPrefix+"wifi_station_bytes",
|
|
|
|
"total rx/tx bytes",
|
2021-03-01 11:00:39 +01:00
|
|
|
[]string{"id", "dir"}, nil)
|
2021-03-11 22:31:30 +01:00
|
|
|
promDescWifiApStationSignalDbm = prometheus.NewDesc(
|
|
|
|
metricPrefix+"wifi_station_signal_dbm", // written dB in the doc... but I have some doubts
|
|
|
|
"signal attenuation in dBm",
|
2021-03-01 11:00:39 +01:00
|
|
|
[]string{"id"}, nil)
|
2021-02-27 11:15:08 +01:00
|
|
|
|
2021-02-28 12:14:20 +01:00
|
|
|
promDescLanHostTotal = prometheus.NewDesc(
|
|
|
|
metricPrefix+"lan_host_total",
|
2021-02-27 11:15:08 +01:00
|
|
|
"number of hosts detected",
|
|
|
|
[]string{"interface", "active"}, nil)
|
2021-02-27 21:36:56 +01:00
|
|
|
promDescLanHostActiveL2 = prometheus.NewDesc(
|
|
|
|
metricPrefix+"lan_host_active_l2",
|
|
|
|
"1 if active, 0 if not. Various information about the l2 addresses",
|
|
|
|
[]string{"interface", "vendor_name", "primary_name", "host_type", "l2_type", "l2_id"}, nil)
|
|
|
|
promDescLanHostActiveL3 = prometheus.NewDesc(
|
|
|
|
metricPrefix+"lan_host_active_l3",
|
|
|
|
"1 if active, 0 if not. Various information about the l3 addresses",
|
|
|
|
[]string{"interface", "vendor_name", "primary_name", "host_type", "l2_type", "l2_id", "l3_type", "l3_address"}, nil)
|
2021-02-26 08:15:12 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
// Collector is the prometheus collector for the freebox exporter
|
|
|
|
type Collector struct {
|
2021-02-27 11:15:08 +01:00
|
|
|
hostDetails bool
|
|
|
|
freebox *fbx.FreeboxConnection
|
2021-02-26 08:15:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Collector) Describe(ch chan<- *prometheus.Desc) {
|
|
|
|
log.Debug.Println("Describe")
|
|
|
|
ch2 := make(chan prometheus.Metric)
|
|
|
|
go func() {
|
|
|
|
c.Collect(ch2)
|
|
|
|
close(ch2)
|
|
|
|
}()
|
|
|
|
for v := range ch2 {
|
|
|
|
ch <- v.Desc()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Collector) Collect(ch chan<- prometheus.Metric) {
|
|
|
|
log.Debug.Println("Collect")
|
|
|
|
wg := sync.WaitGroup{}
|
2021-02-27 21:36:56 +01:00
|
|
|
wg.Add(5)
|
2021-02-26 08:15:12 +01:00
|
|
|
|
2021-03-11 22:31:30 +01:00
|
|
|
getMetricSuccessful := true
|
2021-02-26 08:15:12 +01:00
|
|
|
var firmwareVersion string
|
|
|
|
var mac string
|
|
|
|
var serial string
|
|
|
|
var boardName string
|
|
|
|
var boxFlavor string
|
|
|
|
go func() {
|
|
|
|
defer wg.Done()
|
|
|
|
log.Debug.Println("Collect system")
|
2021-02-26 22:33:39 +01:00
|
|
|
|
2021-02-26 08:15:12 +01:00
|
|
|
if m, err := c.freebox.GetMetricsSystem(); err == nil {
|
|
|
|
firmwareVersion = m.FirmwareVersion
|
2021-03-01 11:00:39 +01:00
|
|
|
mac = strings.ToLower(m.Mac)
|
2021-02-26 08:15:12 +01:00
|
|
|
serial = m.Serial
|
|
|
|
boardName = m.BoardName
|
|
|
|
boxFlavor = m.BoxFlavor
|
|
|
|
|
|
|
|
c.collectCounter(ch, m.UptimeValue, promDescSystemUptime)
|
|
|
|
for _, sensor := range m.Sensors {
|
|
|
|
c.collectGauge(ch, sensor.Value, promDescSystemTemp, sensor.ID)
|
|
|
|
}
|
|
|
|
if len(m.Sensors) == 0 {
|
|
|
|
c.collectGauge(ch, m.TempCPUM, promDescSystemTemp, "temp_cpum")
|
|
|
|
c.collectGauge(ch, m.TempCPUB, promDescSystemTemp, "temp_cpub")
|
|
|
|
c.collectGauge(ch, m.TempSW, promDescSystemTemp, "temp_sw")
|
|
|
|
}
|
|
|
|
for _, fan := range m.Fans {
|
|
|
|
c.collectGauge(ch, fan.Value, promDescSystemFanRpm, fan.ID)
|
|
|
|
}
|
|
|
|
if len(m.Fans) == 0 {
|
|
|
|
c.collectGauge(ch, m.FanRpm, promDescSystemFanRpm, "fan")
|
|
|
|
}
|
|
|
|
} else {
|
2021-03-11 22:31:30 +01:00
|
|
|
getMetricSuccessful = false
|
2021-02-26 08:15:12 +01:00
|
|
|
log.Error.Println(err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
var cnxType string
|
|
|
|
var cnxState string
|
|
|
|
var cnxMedia string
|
|
|
|
var cnxIPv4 string
|
|
|
|
var cnxIPv6 string
|
2023-03-04 22:44:07 +01:00
|
|
|
var cnxIPv4PortRange string
|
2021-02-26 08:15:12 +01:00
|
|
|
go func() {
|
|
|
|
defer wg.Done()
|
|
|
|
log.Debug.Println("Collect connection")
|
2021-02-26 22:33:39 +01:00
|
|
|
|
2021-02-26 08:15:12 +01:00
|
|
|
if m, err := c.freebox.GetMetricsConnection(); err == nil {
|
|
|
|
cnxType = m.Type
|
|
|
|
cnxState = m.State
|
|
|
|
cnxMedia = m.Media
|
|
|
|
cnxIPv4 = m.IPv4
|
|
|
|
cnxIPv6 = m.IPv6
|
2023-03-04 22:44:07 +01:00
|
|
|
cnxIPv4PortRange = fmt.Sprintf("%d-%d", m.IPv4PortRange[0], m.IPv4PortRange[1])
|
2021-02-26 08:15:12 +01:00
|
|
|
|
2023-03-04 22:07:11 +01:00
|
|
|
c.collectCounter(ch, m.RateUp, promDescConnectionRatesBytes, "tx")
|
|
|
|
c.collectCounter(ch, m.RateDown, promDescConnectionRatesBytes, "rx")
|
2022-09-27 22:45:37 +02:00
|
|
|
c.collectGaugeWithFactor(ch, m.BandwidthUp, 1./8, promDescConnectionBandwidthBytes, "tx")
|
|
|
|
c.collectGaugeWithFactor(ch, m.BandwidthDown, 1./8, promDescConnectionBandwidthBytes, "rx")
|
|
|
|
c.collectCounter(ch, m.BytesUp, promDescConnectionBytes, "tx")
|
|
|
|
c.collectCounter(ch, m.BytesDown, promDescConnectionBytes, "rx")
|
2021-02-26 08:15:12 +01:00
|
|
|
if m.Xdsl != nil {
|
|
|
|
if m.Xdsl.Status != nil {
|
2021-02-27 11:15:08 +01:00
|
|
|
ch <- prometheus.MustNewConstMetric(promDescConnectionXdslInfo, prometheus.GaugeValue, 1,
|
2021-02-26 08:15:12 +01:00
|
|
|
m.Xdsl.Status.Status,
|
|
|
|
m.Xdsl.Status.Protocol,
|
|
|
|
m.Xdsl.Status.Modulation)
|
|
|
|
|
|
|
|
c.collectCounter(ch, m.Xdsl.Status.Uptime, promDescConnectionXdslUptime)
|
|
|
|
}
|
2022-09-27 22:45:37 +02:00
|
|
|
c.collectXdslStats(ch, m.Xdsl.Up, "tx")
|
|
|
|
c.collectXdslStats(ch, m.Xdsl.Down, "rx")
|
2021-02-26 08:15:12 +01:00
|
|
|
}
|
|
|
|
if m.Ftth != nil {
|
2021-02-28 12:34:59 +01:00
|
|
|
c.collectBool(ch, m.Ftth.SfpPresent, promDescConnectionFtthSfpPresent,
|
2021-02-26 08:15:12 +01:00
|
|
|
m.Ftth.SfpSerial,
|
|
|
|
m.Ftth.SfpModel,
|
|
|
|
m.Ftth.SfpVendor)
|
2021-02-28 12:34:59 +01:00
|
|
|
c.collectBool(ch, m.Ftth.SfpAlimOk, promDescConnectionFtthSfpAlimOk,
|
|
|
|
m.Ftth.SfpSerial,
|
|
|
|
m.Ftth.SfpModel,
|
|
|
|
m.Ftth.SfpVendor)
|
|
|
|
c.collectBool(ch, m.Ftth.SfpHasPowerReport, promDescConnectionFtthSfpHasPowerReport,
|
|
|
|
m.Ftth.SfpSerial,
|
|
|
|
m.Ftth.SfpModel,
|
|
|
|
m.Ftth.SfpVendor)
|
|
|
|
c.collectBool(ch, m.Ftth.SfpHasSignal, promDescConnectionFtthSfpHasSignal,
|
|
|
|
m.Ftth.SfpSerial,
|
|
|
|
m.Ftth.SfpModel,
|
|
|
|
m.Ftth.SfpVendor)
|
|
|
|
c.collectBool(ch, m.Ftth.Link, promDescConnectionFtthLink,
|
|
|
|
m.Ftth.SfpSerial,
|
|
|
|
m.Ftth.SfpModel,
|
|
|
|
m.Ftth.SfpVendor)
|
|
|
|
c.collectGaugeWithFactor(ch, m.Ftth.SfpPwrTx, 0.01, promDescConnectionFtthSfpPwr,
|
|
|
|
m.Ftth.SfpSerial,
|
|
|
|
m.Ftth.SfpModel,
|
|
|
|
m.Ftth.SfpVendor,
|
|
|
|
"tx")
|
|
|
|
c.collectGaugeWithFactor(ch, m.Ftth.SfpPwrRx, 0.01, promDescConnectionFtthSfpPwr,
|
|
|
|
m.Ftth.SfpSerial,
|
|
|
|
m.Ftth.SfpModel,
|
|
|
|
m.Ftth.SfpVendor,
|
|
|
|
"rx")
|
2021-02-26 08:15:12 +01:00
|
|
|
}
|
|
|
|
} else {
|
2021-03-11 22:31:30 +01:00
|
|
|
getMetricSuccessful = false
|
2021-02-26 08:15:12 +01:00
|
|
|
log.Error.Println(err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2021-02-26 22:33:39 +01:00
|
|
|
go func() {
|
|
|
|
defer wg.Done()
|
|
|
|
log.Debug.Println("Collect switch")
|
|
|
|
|
|
|
|
if m, err := c.freebox.GetMetricsSwitch(); err == nil {
|
|
|
|
numPortsConnected := 0
|
|
|
|
|
|
|
|
for _, port := range m.Ports {
|
|
|
|
if port.Link == "up" {
|
|
|
|
numPortsConnected++
|
|
|
|
}
|
|
|
|
|
|
|
|
speed, _ := strconv.Atoi(port.Speed)
|
2021-03-11 22:31:30 +01:00
|
|
|
portID := c.toString(port.ID)
|
|
|
|
ch <- prometheus.MustNewConstMetric(promDescSwitchPortBandwidthBytes, prometheus.GaugeValue, float64(speed)/8,
|
2021-02-26 22:33:39 +01:00
|
|
|
portID,
|
|
|
|
port.Link,
|
|
|
|
port.Duplex)
|
|
|
|
if port.Stats != nil {
|
|
|
|
c.collectCounter(ch, port.Stats.RxGoodBytes, promDescSwitchPortBytes, portID, "rx", "good")
|
|
|
|
c.collectCounter(ch, port.Stats.RxBadBytes, promDescSwitchPortBytes, portID, "rx", "bad")
|
|
|
|
c.collectCounter(ch, port.Stats.TxBytes, promDescSwitchPortBytes, portID, "tx", "")
|
2021-03-11 22:31:30 +01:00
|
|
|
|
|
|
|
c.collectCounter(ch, port.Stats.RxGoodPackets, promDescSwitchPortPackets, portID, "rx", "good")
|
|
|
|
c.collectCounter(ch, port.Stats.RxBroadcastPackets, promDescSwitchPortPackets, portID, "rx", "bad")
|
|
|
|
c.collectCounter(ch, port.Stats.TxBroadcastPackets, promDescSwitchPortPackets, portID, "tx", "")
|
2021-02-26 22:33:39 +01:00
|
|
|
}
|
2021-02-27 21:36:56 +01:00
|
|
|
|
2021-02-28 12:14:20 +01:00
|
|
|
ch <- prometheus.MustNewConstMetric(promDescSwitchHostTotal, prometheus.GaugeValue, float64(len(port.MacList)), portID)
|
2021-02-27 11:15:08 +01:00
|
|
|
if c.hostDetails {
|
2021-02-26 22:33:39 +01:00
|
|
|
for _, mac := range port.MacList {
|
2021-02-27 11:15:08 +01:00
|
|
|
ch <- prometheus.MustNewConstMetric(promDescSwitchHost, prometheus.GaugeValue, 1,
|
2021-02-26 22:33:39 +01:00
|
|
|
portID,
|
|
|
|
strings.ToLower(mac.Mac),
|
|
|
|
mac.Hostname)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-28 12:14:20 +01:00
|
|
|
ch <- prometheus.MustNewConstMetric(promDescSwitchPortConnectedTotal, prometheus.GaugeValue, float64(numPortsConnected))
|
2021-02-26 22:33:39 +01:00
|
|
|
} else {
|
2021-03-11 22:31:30 +01:00
|
|
|
getMetricSuccessful = false
|
2021-02-26 22:33:39 +01:00
|
|
|
log.Error.Println(err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2021-02-27 21:36:56 +01:00
|
|
|
go func() {
|
|
|
|
defer wg.Done()
|
|
|
|
log.Debug.Println("Collect wifi")
|
|
|
|
if m, err := c.freebox.GetMetricsWifi(); err == nil {
|
2021-02-28 12:14:20 +01:00
|
|
|
|
|
|
|
for _, bss := range m.Bss {
|
|
|
|
phyID := strconv.FormatInt(bss.PhyID, 10)
|
2021-03-01 11:00:39 +01:00
|
|
|
bssid := strings.ToLower(bss.ID)
|
2021-03-11 22:31:30 +01:00
|
|
|
|
2021-02-28 12:14:20 +01:00
|
|
|
ch <- prometheus.MustNewConstMetric(promDescWifiBssInfo, prometheus.GaugeValue, 1,
|
2021-03-01 11:00:39 +01:00
|
|
|
bssid,
|
2021-02-28 12:14:20 +01:00
|
|
|
phyID,
|
|
|
|
bss.Status.State,
|
|
|
|
c.toString(bss.Config.Enabled),
|
|
|
|
bss.Config.Ssid,
|
|
|
|
c.toString(bss.Config.HideSsid),
|
2021-03-11 22:31:30 +01:00
|
|
|
bss.Config.Encryption,
|
|
|
|
c.toString(bss.Config.EapolVersion))
|
2021-03-01 11:00:39 +01:00
|
|
|
c.collectGauge(ch, bss.Status.StaCount, promDescWifiBssStationTotal, bssid, phyID)
|
|
|
|
c.collectGauge(ch, bss.Status.AuthorizedStaCount, promDescWifiBssAuthorizedStationTotal, bssid, phyID)
|
2021-02-28 12:14:20 +01:00
|
|
|
}
|
|
|
|
|
2021-02-27 21:36:56 +01:00
|
|
|
for _, ap := range m.Ap {
|
|
|
|
apID := strconv.FormatInt(ap.ID, 10)
|
|
|
|
|
|
|
|
if capabilities, ok := ap.Capabilities[ap.Config.Band]; ok {
|
|
|
|
labels := prometheus.Labels{}
|
2021-02-28 11:44:31 +01:00
|
|
|
labels["ap_id"] = apID
|
|
|
|
labels["ap_band"] = ap.Config.Band
|
|
|
|
labels["ap_name"] = ap.Name
|
|
|
|
labels["ap_state"] = ap.Status.State
|
2021-02-27 21:36:56 +01:00
|
|
|
|
|
|
|
for k, v := range capabilities {
|
2021-03-11 22:31:30 +01:00
|
|
|
labels[k] = c.toString(v)
|
2021-02-27 21:36:56 +01:00
|
|
|
}
|
|
|
|
|
2021-03-11 22:31:30 +01:00
|
|
|
promDescWifiApInfo := prometheus.NewDesc(
|
|
|
|
metricPrefix+"wifi_ap_info",
|
2021-02-27 21:36:56 +01:00
|
|
|
"constant metric with value=1. List of AP capabilities",
|
|
|
|
nil, labels)
|
2021-03-11 22:31:30 +01:00
|
|
|
ch <- prometheus.MustNewConstMetric(promDescWifiApInfo, prometheus.GaugeValue, 1)
|
2021-02-27 21:36:56 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
c.collectGauge(ch, ap.Status.PrimaryChannel, promDescWifiApChannel,
|
|
|
|
apID,
|
|
|
|
ap.Config.Band,
|
|
|
|
ap.Name,
|
|
|
|
"primary")
|
|
|
|
c.collectGauge(ch, ap.Status.SecondaryChannel, promDescWifiApChannel,
|
|
|
|
apID,
|
|
|
|
ap.Config.Band,
|
|
|
|
ap.Name,
|
|
|
|
"secondary")
|
2021-02-28 12:14:20 +01:00
|
|
|
ch <- prometheus.MustNewConstMetric(promDescWifiApStationTotal, prometheus.GaugeValue, float64(len(ap.Stations)),
|
2021-02-27 21:36:56 +01:00
|
|
|
apID,
|
|
|
|
ap.Config.Band,
|
|
|
|
ap.Name)
|
|
|
|
if c.hostDetails {
|
|
|
|
for _, station := range ap.Stations {
|
2021-03-11 22:31:30 +01:00
|
|
|
stationActive := c.toFloat(station.Host != nil && c.toBool(station.Host.Active))
|
2021-03-01 11:00:39 +01:00
|
|
|
bssid := strings.ToLower(station.Bssid)
|
|
|
|
mac := strings.ToLower(station.Mac)
|
|
|
|
stationID := strings.ToLower(station.ID)
|
2021-02-27 21:36:56 +01:00
|
|
|
ssid := ""
|
|
|
|
encryption := ""
|
|
|
|
if station.Bss != nil {
|
|
|
|
ssid = station.Bss.Config.Ssid
|
|
|
|
encryption = station.Bss.Config.Encryption
|
|
|
|
}
|
|
|
|
|
2021-03-11 22:31:30 +01:00
|
|
|
ch <- prometheus.MustNewConstMetric(promDescWifiApStationInfo, prometheus.GaugeValue, stationActive,
|
2021-02-27 21:36:56 +01:00
|
|
|
apID,
|
|
|
|
ap.Config.Band,
|
|
|
|
ap.Name,
|
2021-03-01 11:00:39 +01:00
|
|
|
stationID,
|
|
|
|
bssid,
|
2021-02-27 21:36:56 +01:00
|
|
|
ssid,
|
|
|
|
encryption,
|
|
|
|
station.Hostname,
|
2021-03-01 11:00:39 +01:00
|
|
|
mac)
|
2021-02-27 21:36:56 +01:00
|
|
|
c.collectCounter(ch, station.RxBytes, promDescWifiApStationBytes,
|
2021-03-01 11:00:39 +01:00
|
|
|
stationID,
|
2021-02-27 21:36:56 +01:00
|
|
|
"rx",
|
|
|
|
)
|
|
|
|
c.collectCounter(ch, station.TxBytes, promDescWifiApStationBytes,
|
2021-03-01 11:00:39 +01:00
|
|
|
stationID,
|
2021-02-27 21:36:56 +01:00
|
|
|
"tx",
|
|
|
|
)
|
2021-03-11 22:31:30 +01:00
|
|
|
c.collectGauge(ch, station.Signal, promDescWifiApStationSignalDbm,
|
2021-03-01 11:00:39 +01:00
|
|
|
stationID)
|
2021-02-27 21:36:56 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2021-03-11 22:31:30 +01:00
|
|
|
getMetricSuccessful = false
|
2021-02-27 21:36:56 +01:00
|
|
|
log.Error.Println(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
}()
|
|
|
|
|
2021-02-27 11:15:08 +01:00
|
|
|
go func() {
|
|
|
|
defer wg.Done()
|
|
|
|
log.Debug.Println("Collect lan")
|
|
|
|
|
|
|
|
if m, err := c.freebox.GetMetricsLan(); err == nil {
|
|
|
|
for name, hosts := range m.Hosts {
|
|
|
|
hostsUnknown := 0
|
|
|
|
hostsActive := 0
|
|
|
|
hostsInactive := 0
|
|
|
|
|
|
|
|
for _, host := range hosts {
|
|
|
|
if host != nil {
|
|
|
|
active := c.toBool(host.Active)
|
|
|
|
if active {
|
|
|
|
hostsActive++
|
|
|
|
} else {
|
|
|
|
hostsInactive++
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.hostDetails {
|
2021-03-11 22:31:30 +01:00
|
|
|
ch <- prometheus.MustNewConstMetric(promDescLanHostActiveL2, prometheus.GaugeValue, c.toFloat(active),
|
2021-02-27 21:36:56 +01:00
|
|
|
name,
|
|
|
|
host.VendorName,
|
|
|
|
host.PrimaryName,
|
|
|
|
host.HostType,
|
|
|
|
host.L2Ident.Type,
|
|
|
|
strings.ToLower(host.L2Ident.ID))
|
|
|
|
|
2021-02-27 11:15:08 +01:00
|
|
|
for _, l3 := range host.L3Connectivities {
|
2021-03-11 22:31:30 +01:00
|
|
|
ch <- prometheus.MustNewConstMetric(promDescLanHostActiveL3, prometheus.GaugeValue, c.toFloat(c.toBool(l3.Active)),
|
2021-02-27 11:15:08 +01:00
|
|
|
name,
|
|
|
|
host.VendorName,
|
|
|
|
host.PrimaryName,
|
2021-02-27 21:36:56 +01:00
|
|
|
host.HostType,
|
2021-02-27 11:15:08 +01:00
|
|
|
host.L2Ident.Type,
|
|
|
|
strings.ToLower(host.L2Ident.ID),
|
|
|
|
l3.Af,
|
|
|
|
l3.Addr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
hostsUnknown += len(hosts)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-28 12:14:20 +01:00
|
|
|
ch <- prometheus.MustNewConstMetric(promDescLanHostTotal, prometheus.GaugeValue, float64(hostsActive), name, "true")
|
|
|
|
ch <- prometheus.MustNewConstMetric(promDescLanHostTotal, prometheus.GaugeValue, float64(hostsInactive), name, "false")
|
2021-02-27 11:15:08 +01:00
|
|
|
if hostsUnknown > 0 {
|
|
|
|
// there should not be any
|
2021-02-28 12:14:20 +01:00
|
|
|
ch <- prometheus.MustNewConstMetric(promDescLanHostTotal, prometheus.GaugeValue, float64(hostsUnknown), name, "unknown")
|
2021-02-27 11:15:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2021-03-11 22:31:30 +01:00
|
|
|
getMetricSuccessful = false
|
2021-02-27 11:15:08 +01:00
|
|
|
log.Error.Println(err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2021-02-26 08:15:12 +01:00
|
|
|
wg.Wait()
|
2021-03-11 22:31:30 +01:00
|
|
|
|
|
|
|
apiVersion := c.freebox.GetAPIVersion()
|
|
|
|
url, _ := apiVersion.GetURL("")
|
|
|
|
ch <- prometheus.MustNewConstMetric(promDescExporterInfo, prometheus.GaugeValue, c.toFloat(getMetricSuccessful),
|
|
|
|
url,
|
|
|
|
apiVersion.APIVersion)
|
|
|
|
|
2021-02-27 11:15:08 +01:00
|
|
|
ch <- prometheus.MustNewConstMetric(promDescInfo, prometheus.GaugeValue, 1,
|
2021-02-26 08:15:12 +01:00
|
|
|
firmwareVersion,
|
2021-03-01 11:00:39 +01:00
|
|
|
mac,
|
2021-02-26 08:15:12 +01:00
|
|
|
serial,
|
|
|
|
boardName,
|
|
|
|
boxFlavor,
|
|
|
|
cnxType,
|
|
|
|
cnxState,
|
|
|
|
cnxMedia,
|
|
|
|
cnxIPv4,
|
2023-03-04 22:44:07 +01:00
|
|
|
cnxIPv6,
|
|
|
|
cnxIPv4PortRange)
|
2021-02-26 08:15:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Collector) collectXdslStats(ch chan<- prometheus.Metric, stats *fbx.MetricsFreeboxConnectionXdslStats, dir string) {
|
|
|
|
if stats != nil {
|
2021-03-11 22:31:30 +01:00
|
|
|
c.collectGaugeWithFactor(ch, stats.Maxrate, 1000./8, promDescConnectionXdslMaxRateBytes)
|
|
|
|
c.collectGaugeWithFactor(ch, stats.Rate, 1000./8, promDescConnectionXdslRateBytes)
|
2021-02-26 08:15:12 +01:00
|
|
|
if stats.Snr10 != nil {
|
|
|
|
c.collectGaugeWithFactor(ch, stats.Snr10, 0.1, promDescConnectionXdslSnr)
|
|
|
|
} else {
|
|
|
|
c.collectGauge(ch, stats.Snr, promDescConnectionXdslSnr, dir)
|
|
|
|
}
|
|
|
|
if stats.Attn10 != nil {
|
|
|
|
c.collectGaugeWithFactor(ch, stats.Attn10, 0.1, promDescConnectionXdslAttn)
|
|
|
|
} else {
|
|
|
|
c.collectGauge(ch, stats.Attn, promDescConnectionXdslAttn, dir)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-28 12:34:59 +01:00
|
|
|
func (c *Collector) collectBool(ch chan<- prometheus.Metric, value *bool, desc *prometheus.Desc, labels ...string) {
|
|
|
|
if value != nil {
|
2021-03-11 22:31:30 +01:00
|
|
|
ch <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, c.toFloat(*value), labels...)
|
2021-02-28 12:34:59 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-26 08:15:12 +01:00
|
|
|
func (c *Collector) collectGauge(ch chan<- prometheus.Metric, value *int64, desc *prometheus.Desc, labels ...string) {
|
|
|
|
c.collectConst(ch, prometheus.GaugeValue, value, desc, labels...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Collector) collectCounter(ch chan<- prometheus.Metric, value *int64, desc *prometheus.Desc, labels ...string) {
|
|
|
|
c.collectConst(ch, prometheus.CounterValue, value, desc, labels...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Collector) collectConst(ch chan<- prometheus.Metric, valueType prometheus.ValueType, value *int64, desc *prometheus.Desc, labels ...string) {
|
|
|
|
if value != nil {
|
|
|
|
ch <- prometheus.MustNewConstMetric(desc, valueType, float64(*value), labels...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Collector) collectGaugeWithFactor(ch chan<- prometheus.Metric, value *int64, factor float64, desc *prometheus.Desc, labels ...string) {
|
|
|
|
c.collectConstWithFactor(ch, prometheus.GaugeValue, value, factor, desc, labels...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Collector) collectConstWithFactor(ch chan<- prometheus.Metric, valueType prometheus.ValueType, value *int64, factor float64, desc *prometheus.Desc, labels ...string) {
|
|
|
|
if value != nil {
|
|
|
|
ch <- prometheus.MustNewConstMetric(desc, valueType, float64(*value)*factor, labels...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-11 22:31:30 +01:00
|
|
|
func (c *Collector) toString(i interface{}) string {
|
|
|
|
if val := reflect.ValueOf(i); val.Kind() == reflect.Ptr {
|
2022-09-30 22:12:59 +02:00
|
|
|
if !val.IsNil() {
|
2021-03-11 22:31:30 +01:00
|
|
|
return c.toString(val.Elem().Interface())
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
switch v := i.(type) {
|
|
|
|
case bool:
|
|
|
|
return strconv.FormatBool(v)
|
|
|
|
case int:
|
|
|
|
return strconv.FormatInt(int64(v), 10)
|
|
|
|
case int8:
|
|
|
|
return strconv.FormatInt(int64(v), 10)
|
|
|
|
case int16:
|
|
|
|
return strconv.FormatInt(int64(v), 10)
|
|
|
|
case int32:
|
|
|
|
return strconv.FormatInt(int64(v), 10)
|
|
|
|
case int64:
|
|
|
|
return strconv.FormatInt(v, 10)
|
|
|
|
case uint:
|
|
|
|
return strconv.FormatUint(uint64(v), 10)
|
|
|
|
case uint8:
|
|
|
|
return strconv.FormatUint(uint64(v), 10)
|
|
|
|
case uint16:
|
|
|
|
return strconv.FormatUint(uint64(v), 10)
|
|
|
|
case uint32:
|
|
|
|
return strconv.FormatUint(uint64(v), 10)
|
|
|
|
case uint64:
|
|
|
|
return strconv.FormatUint(v, 10)
|
|
|
|
case float32:
|
|
|
|
return strconv.FormatFloat(float64(v), 'E', -1, 32)
|
|
|
|
case float64:
|
|
|
|
return strconv.FormatFloat(float64(v), 'E', -1, 64)
|
|
|
|
case string:
|
|
|
|
return v
|
2021-02-26 08:15:12 +01:00
|
|
|
}
|
2021-02-27 11:15:08 +01:00
|
|
|
return "unknown"
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Collector) toBool(b *bool) bool {
|
|
|
|
return b != nil && *b
|
2021-02-26 08:15:12 +01:00
|
|
|
}
|
|
|
|
|
2021-03-11 22:31:30 +01:00
|
|
|
func (c *Collector) toFloat(b bool) float64 {
|
|
|
|
if b {
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2022-09-30 22:08:14 +02:00
|
|
|
func NewCollector(filename string, discovery fbx.FreeboxDiscovery, forceApiVersion int, hostDetails, debug bool) *Collector {
|
2021-02-26 22:33:39 +01:00
|
|
|
result := &Collector{
|
2021-02-27 11:15:08 +01:00
|
|
|
hostDetails: hostDetails,
|
2021-02-26 22:33:39 +01:00
|
|
|
}
|
2021-02-26 08:15:12 +01:00
|
|
|
newConfig := false
|
|
|
|
if r, err := os.Open(filename); err == nil {
|
|
|
|
log.Info.Println("Use configuration file", filename)
|
|
|
|
defer r.Close()
|
2022-09-30 22:08:14 +02:00
|
|
|
result.freebox, err = fbx.NewFreeboxConnectionFromConfig(r, forceApiVersion)
|
2021-02-26 08:15:12 +01:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
log.Info.Println("Could not find the configuration file", filename)
|
|
|
|
newConfig = true
|
2022-09-30 22:08:14 +02:00
|
|
|
result.freebox, err = fbx.NewFreeboxConnectionFromServiceDiscovery(discovery, forceApiVersion)
|
2021-02-26 08:15:12 +01:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if newConfig {
|
|
|
|
log.Info.Println("Write the configuration file", filename)
|
|
|
|
w, err := os.Create(filename)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
defer w.Close()
|
|
|
|
if err := result.freebox.WriteConfig(w); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Collector) Close() {
|
|
|
|
c.freebox.Close()
|
|
|
|
}
|