Add new experimental metrics (#4)

This commit is contained in:
Tomy Guichard 2023-04-21 18:58:34 +02:00 committed by GitHub
parent 4bac289600
commit 136f95a9b7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 592 additions and 18 deletions

View file

@ -0,0 +1,9 @@
package poller
import "math"
const maxMbits = 2150
func sanitizeMbits(mbits float64) float64 {
return math.Min(mbits, maxMbits)
}

View file

@ -6,6 +6,7 @@ import (
"github.com/Tomy2e/livebox-api-client"
"github.com/Tomy2e/livebox-api-client/api/request"
"github.com/Tomy2e/livebox-exporter/pkg/bitrate"
"github.com/prometheus/client_golang/prometheus"
)
@ -44,10 +45,6 @@ func (im *InterfaceMbits) Collectors() []prometheus.Collector {
return []prometheus.Collector{im.txMbits, im.rxMbits}
}
func bitsPer30SecsToMbitsPerSec(v int) float64 {
return float64(v) / 30000000
}
// Poll polls the current bandwidth usage.
func (im *InterfaceMbits) Poll(ctx context.Context) error {
var counters struct {
@ -87,10 +84,10 @@ func (im *InterfaceMbits) Poll(ctx context.Context) error {
im.rxMbits.
With(prometheus.Labels{"interface": iface}).
Set(bitsPer30SecsToMbitsPerSec(rxCounter))
Set(bitrate.BitsPer30SecsToMbits(rxCounter))
im.txMbits.
With(prometheus.Labels{"interface": iface}).
Set(bitsPer30SecsToMbitsPerSec(txCounter))
Set(bitrate.BitsPer30SecsToMbits(txCounter))
}
return nil

View file

@ -0,0 +1,110 @@
package poller
import (
"context"
"fmt"
"time"
"github.com/Tomy2e/livebox-api-client"
"github.com/Tomy2e/livebox-api-client/api/request"
"github.com/Tomy2e/livebox-exporter/pkg/bitrate"
exporterLivebox "github.com/Tomy2e/livebox-exporter/pkg/livebox"
"github.com/prometheus/client_golang/prometheus"
)
// InterfaceHomeLanMbitsMinDelay set the minimum delay between each poll.
// Polling must only be done once every 30 seconds as Livebox updates data
// only every 30 seconds.
const InterfaceHomeLanMbitsMinDelay = 30 * time.Second
var _ Poller = &InterfaceHomeLanMbits{}
// InterfaceHomeLanMbits is an experimental poller to get the current bandwidth
// usage on the Livebox interfaces.
type InterfaceHomeLanMbits struct {
client livebox.Client
interfaces []*exporterLivebox.Interface
bitrate *bitrate.Bitrate
txMbits, rxMbits *prometheus.GaugeVec
}
// NewInterfaceHomeLanMbits returns a new InterfaceMbits poller.
func NewInterfaceHomeLanMbits(client livebox.Client, interfaces []*exporterLivebox.Interface) *InterfaceHomeLanMbits {
return &InterfaceHomeLanMbits{
client: client,
interfaces: interfaces,
bitrate: bitrate.New(InterfaceHomeLanMbitsMinDelay),
txMbits: prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: "livebox_interface_homelan_tx_mbits",
Help: "Transmitted Mbits per second.",
}, []string{
// Name of the interface.
"interface",
}),
rxMbits: prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: "livebox_interface_homelan_rx_mbits",
Help: "Received Mbits per second.",
}, []string{
// Name of the interface.
"interface",
}),
}
}
// Collectors returns all metrics.
func (im *InterfaceHomeLanMbits) Collectors() []prometheus.Collector {
return []prometheus.Collector{
im.txMbits,
im.rxMbits,
}
}
// Poll polls the current bandwidth usage.
func (im *InterfaceHomeLanMbits) Poll(ctx context.Context) error {
for _, itf := range im.interfaces {
// Enforce InterfaceHomeLanMbitsMinDelay.
if !im.bitrate.ShouldMeasure(itf.Name) {
continue
}
var stats struct {
Status struct {
BytesReceived uint64 `json:"BytesReceived"`
BytesSent uint64 `json:"BytesSent"`
} `json:"status"`
}
if err := im.client.Request(ctx, request.New(
fmt.Sprintf("HomeLan.Interface.%s.Stats", itf.Name),
"get",
nil,
), &stats); err != nil {
return err
}
counters := &bitrate.Counters{
Tx: stats.Status.BytesSent,
Rx: stats.Status.BytesReceived,
}
if !itf.IsWAN() {
counters.Swap()
}
bitrates := im.bitrate.Measure(itf.Name, counters)
if bitrates.Rx != nil && !bitrates.Rx.Reset {
im.rxMbits.
With(prometheus.Labels{"interface": itf.Name}).
Set(sanitizeMbits(bitrates.Rx.Value))
}
if bitrates.Tx != nil && !bitrates.Tx.Reset {
im.txMbits.
With(prometheus.Labels{"interface": itf.Name}).
Set(sanitizeMbits(bitrates.Tx.Value))
}
}
return nil
}

View file

@ -0,0 +1,99 @@
package poller
import (
"context"
"fmt"
"github.com/Tomy2e/livebox-api-client"
"github.com/Tomy2e/livebox-api-client/api/request"
"github.com/Tomy2e/livebox-exporter/pkg/bitrate"
exporterLivebox "github.com/Tomy2e/livebox-exporter/pkg/livebox"
"github.com/prometheus/client_golang/prometheus"
)
var _ Poller = &InterfaceNetDevMbits{}
// InterfaceNetDevMbits is an experimental poller to get the current bandwidth
// usage on the Livebox interfaces.
type InterfaceNetDevMbits struct {
client livebox.Client
interfaces []*exporterLivebox.Interface
bitrate *bitrate.Bitrate
txMbits, rxMbits *prometheus.GaugeVec
}
// NewInterfaceNetDevMbits returns a new InterfaceNetDevMbits poller.
func NewInterfaceNetDevMbits(client livebox.Client, interfaces []*exporterLivebox.Interface) *InterfaceNetDevMbits {
return &InterfaceNetDevMbits{
client: client,
interfaces: interfaces,
bitrate: bitrate.New(0),
txMbits: prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: "livebox_interface_netdev_tx_mbits",
Help: "Transmitted Mbits per second.",
}, []string{
// Name of the interface.
"interface",
}),
rxMbits: prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: "livebox_interface_netdev_rx_mbits",
Help: "Received Mbits per second.",
}, []string{
// Name of the interface.
"interface",
}),
}
}
// Collectors returns all metrics.
func (im *InterfaceNetDevMbits) Collectors() []prometheus.Collector {
return []prometheus.Collector{
im.txMbits,
im.rxMbits,
}
}
// Poll polls the current bandwidth usage.
func (im *InterfaceNetDevMbits) Poll(ctx context.Context) error {
for _, itf := range im.interfaces {
var stats struct {
Status struct {
RxBytes uint64 `json:"RxBytes"`
TxBytes uint64 `json:"TxBytes"`
} `json:"status"`
}
if err := im.client.Request(ctx, request.New(
fmt.Sprintf("NeMo.Intf.%s", itf.Name),
"getNetDevStats",
nil,
), &stats); err != nil {
return err
}
counters := &bitrate.Counters{
Tx: stats.Status.TxBytes,
Rx: stats.Status.RxBytes,
}
if !itf.IsWAN() {
counters.Swap()
}
bitrates := im.bitrate.Measure(itf.Name, counters)
if bitrates.Rx != nil && !bitrates.Rx.Reset {
im.rxMbits.
With(prometheus.Labels{"interface": itf.Name}).
Set(sanitizeMbits(bitrates.Rx.Value))
}
if bitrates.Tx != nil && !bitrates.Tx.Reset {
im.txMbits.
With(prometheus.Labels{"interface": itf.Name}).
Set(sanitizeMbits(bitrates.Tx.Value))
}
}
return nil
}

81
internal/poller/wan.go Normal file
View file

@ -0,0 +1,81 @@
package poller
import (
"context"
"github.com/Tomy2e/livebox-api-client"
"github.com/Tomy2e/livebox-api-client/api/request"
"github.com/Tomy2e/livebox-exporter/pkg/bitrate"
"github.com/prometheus/client_golang/prometheus"
)
var _ Poller = &WANMbits{}
// WANMbits is an experimental poller to get the current bandwidth usage on the
// WAN interface of the Livebox.
type WANMbits struct {
client livebox.Client
bitrate *bitrate.Bitrate
txMbits, rxMbits prometheus.Gauge
}
// NewWANMbits returns a new WANMbits poller.
func NewWANMbits(client livebox.Client) *WANMbits {
return &WANMbits{
client: client,
bitrate: bitrate.New(InterfaceHomeLanMbitsMinDelay),
txMbits: prometheus.NewGauge(prometheus.GaugeOpts{
Name: "livebox_wan_tx_mbits",
Help: "Transmitted Mbits per second on the WAN interface.",
}),
rxMbits: prometheus.NewGauge(prometheus.GaugeOpts{
Name: "livebox_wan_rx_mbits",
Help: "Received Mbits per second on the WAN interface.",
}),
}
}
// Collectors returns all metrics.
func (im *WANMbits) Collectors() []prometheus.Collector {
return []prometheus.Collector{
im.txMbits,
im.rxMbits,
}
}
// Poll polls the current bandwidth usage on the WAN interface.
func (im *WANMbits) Poll(ctx context.Context) error {
var stats struct {
Status struct {
BytesReceived uint64 `json:"BytesReceived"`
BytesSent uint64 `json:"BytesSent"`
} `json:"status"`
}
if err := im.client.Request(
ctx,
request.New("HomeLan", "getWANCounters", nil),
&stats,
); err != nil {
return err
}
counters := &bitrate.Counters{
Tx: stats.Status.BytesSent,
Rx: stats.Status.BytesReceived,
}
counters.Swap()
bitrates := im.bitrate.Measure("WAN", counters)
if bitrates.Rx != nil && !bitrates.Rx.Reset {
im.rxMbits.Set(sanitizeMbits(bitrates.Rx.Value))
}
if bitrates.Tx != nil && !bitrates.Tx.Reset {
im.txMbits.Set(sanitizeMbits(bitrates.Tx.Value))
}
return nil
}