diff --git a/Makefile b/Makefile index dad759e..4342edf 100644 --- a/Makefile +++ b/Makefile @@ -2,4 +2,4 @@ lint: golangci-lint run generate-metrics-table: - sh ./scripts/metric-markdown-table.sh + go run main.go --host dummy --username dummy --password dummy mdocs > gen-metrics-table.md diff --git a/README.md b/README.md index 9db4ac8..df2e084 100644 --- a/README.md +++ b/README.md @@ -110,23 +110,32 @@ omada: ``` ## 📊 Metrics -Name|Description|Labels +| Name | Description | Labels | |--|--|--| - omada_device_uptime_seconds | Uptime of the device. | device, model, version, ip, mac, site, site_id, device_type - omada_device_cpu_percentage | Percentage of device CPU used. | device, model, version, ip, mac, site, site_id, device_type - omada_device_mem_percentage | Percentage of device Memory used. | device, model, version, ip, mac, site, site_id, device_type - omada_device_need_upgrade | A boolean on whether the device needs an upgrade. | device, model, version, ip, mac, site, site_id, device_type - omada_device_tx_rate | The tx rate of the device. | device, model, version, ip, mac, site, site_id, device_type - omada_device_rx_rate | The rx rate of the device. | device, model, version, ip, mac, site, site_id, device_type - omada_device_poe_remain_watts | The remaining amount of PoE power for the device in watts. | device, model, version, ip, mac, site, site_id, device_type - omada_client_download_activity_bytes | The current download activity for the client in bytes. | client, vendor, switch_port, vlan_id, ip, mac, site, site_id, ap_name, ssid, wifi_mode - omada_client_signal_dbm | The signal level for the wireless client in dBm. | client, vendor, ip, mac, ap_name, site, site_id, ssid, wifi_mode - omada_port_power_watts | The current PoE usage of the port in watts. | device, device_mac, client, vendor, switch_port, name, switch_mac, switch_id, vlan_id, profile, site, site_id - omada_port_link_status | A boolean representing the link status of the port. | device, device_mac, client, vendor, switch_port, name, switch_mac, switch_id, vlan_id, profile, site, site_id - omada_port_link_speed_mbps | Port link speed in mbps. This is the capability of the connection, not the active throughput. | device, device_mac, client, vendor, switch_port, name, switch_mac, switch_id, vlan_id, profile, site, site_id - omada_port_link_rx | Bytes recieved on a port. | device, device_mac, client, vendor, switch_port, name, switch_mac, switch_id, vlan_id, profile, site, site_id - omada_port_link_tx | Bytes transmitted on a port. | device, device_mac, client, vendor, switch_port, name, switch_mac, switch_id, vlan_id, profile, site, site_id - omada_controller_uptime_seconds | Uptime of the controller. | controller_name, model, controller_version, firmware_version, mac - omada_controller_storage_used_bytes | Storage used on the controller. | storage_name, controller_name, model, controller_version, firmware_version, mac - omada_controller_storage_available_bytes | Total storage available for the controller. | storage_name, controller_name, model, controller_version, firmware_version, mac - omada_client_connected_total | Total number of connected clients. | site, site_id +| omada_client_download_activity_bytes | The current download activity for the client in bytes. | client vendor ip mac host_name site site_id connection_mode wifi_mode ap_name ssid switch_port vlan_id | +| omada_client_signal_pct | The signal quality for the wireless client in percent. | client vendor ip mac host_name site site_id connection_mode wifi_mode ap_name ssid | +| omada_client_snr_dbm | The signal to noise ration for the wireless client in dBm. | client vendor ip mac host_name site site_id connection_mode wifi_mode ap_name ssid | +| omada_client_rssi_dbm | The RSSI for the wireless client in dBm. | client vendor ip mac host_name site site_id connection_mode wifi_mode ap_name ssid | +| omada_client_traffic_down_bytes | Total bytes received by wireless client. | client vendor ip mac host_name site site_id connection_mode wifi_mode ap_name ssid | +| omada_client_traffic_up_bytes | Total bytes sent by wireless client. | client vendor ip mac host_name site site_id connection_mode wifi_mode ap_name ssid | +| omada_client_tx_rate | TX rate of wireless client. | client vendor ip mac host_name site site_id connection_mode wifi_mode ap_name ssid | +| omada_client_rx_rate | RX rate of wireless client. | client vendor ip mac host_name site site_id connection_mode wifi_mode ap_name ssid | +| omada_client_connected_total | Total number of connected clients. | site site_id connection_mode wifi_mode | +| omada_controller_uptime_seconds | Uptime of the controller. | controller_name model controller_version firmware_version mac site site_id | +| omada_controller_storage_used_bytes | Storage used on the controller. | storage_name controller_name model controller_version firmware_version mac site site_id | +| omada_controller_storage_available_bytes | Total storage available for the controller. | storage_name controller_name model controller_version firmware_version mac site site_id | +| omada_device_uptime_seconds | Uptime of the device. | device model version ip mac site site_id device_type | +| omada_device_uptime_seconds | Uptime of the device. | device model version ip mac site site_id device_type | +| omada_device_cpu_percentage | Percentage of device CPU used. | device model version ip mac site site_id device_type | +| omada_device_mem_percentage | Percentage of device Memory used. | device model version ip mac site site_id device_type | +| omada_device_need_upgrade | A boolean on whether the device needs an upgrade. | device model version ip mac site site_id device_type | +| omada_device_tx_rate | The tx rate of the device. | device model version ip mac site site_id device_type | +| omada_device_rx_rate | The rx rate of the device. | device model version ip mac site site_id device_type | +| omada_device_poe_remain_watts | The remaining amount of PoE power for the device in watts. | device model version ip mac site site_id device_type | +| omada_device_download | Device download traffic. | device model version ip mac site site_id device_type | +| omada_device_upload | Device upload traffic. | device model version ip mac site site_id device_type | +| omada_port_power_watts | The current PoE usage of the port in watts. | device device_mac client vendor switch_port name switch_mac switch_id vlan_id profile site site_id | +| omada_port_link_status | A boolean representing the link status of the port. | device device_mac client vendor switch_port name switch_mac switch_id vlan_id profile site site_id | +| omada_port_link_speed_mbps | Port link speed in mbps. This is the capability of the connection, not the active throughput. | device device_mac client vendor switch_port name switch_mac switch_id vlan_id profile site site_id | +| omada_port_link_rx | Bytes recieved on a port. | device device_mac client vendor switch_port name switch_mac switch_id vlan_id profile site site_id | +| omada_port_link_tx | Bytes transmitted on a port. | device device_mac client vendor switch_port name switch_mac switch_id vlan_id profile site site_id | diff --git a/cmd/exporter.go b/cmd/exporter.go index a9dbf37..d3eaf97 100644 --- a/cmd/exporter.go +++ b/cmd/exporter.go @@ -48,6 +48,12 @@ func Run() { os.Exit(0) return nil }}, + {Name: "mdocs", Aliases: []string{"md"}, Usage: "prints the metric docs.", + Action: func(c *cli.Context) error { + mdocs() + os.Exit(0) + return nil + }}, } app.Action = run @@ -88,10 +94,9 @@ func run(c *cli.Context) error { } // register omada collectors - prometheus.MustRegister(collector.NewClientCollector(client)) - prometheus.MustRegister(collector.NewControllerCollector(client)) - prometheus.MustRegister(collector.NewDeviceCollector(client)) - prometheus.MustRegister(collector.NewPortCollector(client)) + for _, c := range collectors(client) { + prometheus.MustRegister(c) + } log.Info().Msg(fmt.Sprintf("listening on :%s", conf.Port)) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { @@ -116,3 +121,44 @@ func run(c *cli.Context) error { return nil } + +// mdocs just spits out the metrics descriptions and exits +func mdocs() { + + // Describe wants to return descriptions via a channel, so make and fill a channel. + dc := make(chan *prometheus.Desc) + go func() { + // collectors can't Collect without a client, but Describe doesn't need one. + for _, c := range collectors(nil) { + c.Describe(dc) + } + close(dc) + }() + + fmt.Fprintln(os.Stdout, "| Name | Description | Labels |\n|--|--|--|") + + // drain the channel + for { + if description := <-dc; description != nil { + // Sure would be nice if the prometheus.Desc wasn't so opaque. This is gross and fragile. + d := description.String() + d = strings.Replace(d, `Desc{fqName: "`, "| ", 1) + d = strings.Replace(d, `", help: "`, " | ", 1) + d = strings.Replace(d, `", constLabels: {}, variableLabels: [`, " | ", 1) + d = strings.Replace(d, `]}`, " | ", 1) + fmt.Fprintln(os.Stdout, d) + } else { + break + } + } +} + +// collectors returns the full complement of configured collectors. +func collectors(client *api.Client) []prometheus.Collector { + return []prometheus.Collector{ + collector.NewClientCollector(client), + collector.NewControllerCollector(client), + collector.NewDeviceCollector(client), + collector.NewPortCollector(client), + } +} diff --git a/pkg/api/client.go b/pkg/api/client.go index 606a4d7..56e5441 100644 --- a/pkg/api/client.go +++ b/pkg/api/client.go @@ -88,6 +88,7 @@ type NetworkClient struct { Vendor string `json:"vendor"` Activity float64 `json:"activity"` SignalLevel float64 `json:"signalLevel"` + SignalNoise float64 `json:"snr"` WifiMode float64 `json:"wifiMode"` Ssid string `json:"ssid"` Rssi float64 `json:"rssi"` diff --git a/pkg/collector/client.go b/pkg/collector/client.go index d2fee39..0b01d5b 100644 --- a/pkg/collector/client.go +++ b/pkg/collector/client.go @@ -10,29 +10,31 @@ import ( type clientCollector struct { omadaClientDownloadActivityBytes *prometheus.Desc - omadaClientSignalDbm *prometheus.Desc - omadaClientRssiDbm *prometheus.Desc - omadaClientTrafficDown *prometheus.Desc - omadaClientTrafficUp *prometheus.Desc - omadaClientTxRate *prometheus.Desc - omadaClientRxRate *prometheus.Desc + omadaClientSignalPct *prometheus.Desc + omadaClientSignalNoiseDbm *prometheus.Desc + omadaClientRssiDbm *prometheus.Desc + omadaClientTrafficDown *prometheus.Desc + omadaClientTrafficUp *prometheus.Desc + omadaClientTxRate *prometheus.Desc + omadaClientRxRate *prometheus.Desc omadaClientConnectedTotal *prometheus.Desc client *api.Client } func (c *clientCollector) Describe(ch chan<- *prometheus.Desc) { ch <- c.omadaClientDownloadActivityBytes - ch <- c.omadaClientSignalDbm - ch <- c.omadaClientRssiDbm - ch <- c.omadaClientTrafficDown - ch <- c.omadaClientTrafficUp - ch <- c.omadaClientTxRate - ch <- c.omadaClientRxRate + ch <- c.omadaClientSignalPct + ch <- c.omadaClientSignalNoiseDbm + ch <- c.omadaClientRssiDbm + ch <- c.omadaClientTrafficDown + ch <- c.omadaClientTrafficUp + ch <- c.omadaClientTxRate + ch <- c.omadaClientRxRate ch <- c.omadaClientConnectedTotal } func FormatWifiMode(wifiMode int) string { - mapping := map[int]string { + mapping := map[int]string{ 0: "802.11a", 1: "802.11b", 2: "802.11g", @@ -65,14 +67,16 @@ func (c *clientCollector) Collect(ch chan<- prometheus.Metric) { for _, item := range clients { vlanId := fmt.Sprintf("%.0f", item.VlanId) port := fmt.Sprintf("%.0f", item.Port) + if item.Wireless { wifiMode := FormatWifiMode(int(item.WifiMode)) CollectWirelessMetrics := func(desc *prometheus.Desc, valueType prometheus.ValueType, value float64) { ch <- prometheus.MustNewConstMetric(desc, valueType, value, - item.HostName, item.Vendor, item.Ip, item.Mac, site, client.SiteId, "wireless", wifiMode, item.ApName, item.Ssid) + item.Name, item.Vendor, item.Ip, item.Mac, item.HostName, site, client.SiteId, "wireless", wifiMode, item.ApName, item.Ssid) } - CollectWirelessMetrics(c.omadaClientSignalDbm, prometheus.GaugeValue, -item.SignalLevel) + CollectWirelessMetrics(c.omadaClientSignalPct, prometheus.GaugeValue, item.SignalLevel) + CollectWirelessMetrics(c.omadaClientSignalNoiseDbm, prometheus.GaugeValue, item.SignalNoise) CollectWirelessMetrics(c.omadaClientRssiDbm, prometheus.GaugeValue, item.Rssi) CollectWirelessMetrics(c.omadaClientTrafficDown, prometheus.CounterValue, item.TrafficDown) CollectWirelessMetrics(c.omadaClientTrafficUp, prometheus.CounterValue, item.TrafficUp) @@ -81,12 +85,12 @@ func (c *clientCollector) Collect(ch chan<- prometheus.Metric) { totals[wifiMode] += 1 ch <- prometheus.MustNewConstMetric(c.omadaClientDownloadActivityBytes, prometheus.GaugeValue, item.Activity, - item.HostName, item.Vendor, item.Ip, item.Mac, site, client.SiteId, "wireless", wifiMode, item.ApName, item.Ssid, "", "") + item.Name, item.Vendor, item.Ip, item.Mac, item.HostName, site, client.SiteId, "wireless", wifiMode, item.ApName, item.Ssid, "", "") } if !item.Wireless { totals["wired"] += 1 ch <- prometheus.MustNewConstMetric(c.omadaClientDownloadActivityBytes, prometheus.GaugeValue, item.Activity, - item.HostName, item.Vendor, item.Ip, item.Mac, site, client.SiteId, "wired", "", "", "", port, vlanId) + item.Name, item.Vendor, item.Ip, item.Mac, item.HostName, site, client.SiteId, "wired", "", "", "", port, vlanId) } } @@ -102,7 +106,7 @@ func (c *clientCollector) Collect(ch chan<- prometheus.Metric) { } func NewClientCollector(c *api.Client) *clientCollector { - client_labels := []string{"client", "vendor", "ip", "mac", "site", "site_id", "connection_mode", "wifi_mode", "ap_name", "ssid"} + client_labels := []string{"client", "vendor", "ip", "mac", "host_name", "site", "site_id", "connection_mode", "wifi_mode", "ap_name", "ssid"} wired_client_labels := append(client_labels, "switch_port", "vlan_id") return &clientCollector{ @@ -112,8 +116,14 @@ func NewClientCollector(c *api.Client) *clientCollector { nil, ), - omadaClientSignalDbm: prometheus.NewDesc("omada_client_signal_dbm", - "The noise level for the wireless client in dBm.", + omadaClientSignalPct: prometheus.NewDesc("omada_client_signal_pct", + "The signal quality for the wireless client in percent.", + client_labels, + nil, + ), + + omadaClientSignalNoiseDbm: prometheus.NewDesc("omada_client_snr_dbm", + "The signal to noise ration for the wireless client in dBm.", client_labels, nil, ), diff --git a/scripts/metric-markdown-table.sh b/scripts/metric-markdown-table.sh deleted file mode 100644 index 9882b97..0000000 --- a/scripts/metric-markdown-table.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -# Generate a markdown table for the metrics, based on the contents of ./pkg/omada/metrics.go - -header="Name|Description|Labels\n|--|--|--|\n" -printf $header > gen-metrics-table.md -while IFS='--' read -r METRIC notused # avoids the use of cut -do - METRIC_NAME="" - METRIC_DESC="" - METRIC_LABELS="" - while IFS= read -r line; do - if [[ "$line" == *"Name:"* ]]; then - METRIC_NAME=`echo -n $line | sed 's/.*Name://' | sed 's/,*$//g' | tr -d '"'` - printf "$METRIC_NAME |" >> gen-metrics-table.md - fi - if [[ "$line" == *"Help:"* ]]; then - METRIC_DESC=`echo -n $line | sed 's/.*Help://' | sed 's/,*$//g' | tr -d '"'` - printf " $METRIC_DESC |" >> gen-metrics-table.md - fi - if [[ "$line" == *"[]string{"* ]]; then - METRIC_LABELS=`echo -n $line | sed 's/.*\[\]string{//' | sed 's/,*$//g' | tr -d '"' | tr -d '})'` - printf " $METRIC_LABELS\n" >> gen-metrics-table.md - fi - done <<< "$METRIC" -done < <(cat $PWD/pkg/omada/metrics.go | grep "Name:" -A3)