diff --git a/utils/prometheus-node-exporter-lua/Makefile b/utils/prometheus-node-exporter-lua/Makefile index 696ab99b4..e59413da0 100644 --- a/utils/prometheus-node-exporter-lua/Makefile +++ b/utils/prometheus-node-exporter-lua/Makefile @@ -4,7 +4,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=prometheus-node-exporter-lua -PKG_VERSION:=2022.04.18 +PKG_VERSION:=2022.04.30 PKG_RELEASE:=1 PKG_MAINTAINER:=Etienne CHAMPETIER @@ -23,7 +23,7 @@ endef define Package/prometheus-node-exporter-lua $(call Package/prometheus-node-exporter-lua/Default) - DEPENDS:=+luasocket +lua + DEPENDS:=+luasocket +lua +uhttpd +uhttpd-mod-lua endef define Package/prometheus-node-exporter-lua/install @@ -43,6 +43,7 @@ define Package/prometheus-node-exporter-lua/install $(INSTALL_BIN) ./files/usr/lib/lua/prometheus-collectors/netdev.lua $(1)/usr/lib/lua/prometheus-collectors/ $(INSTALL_BIN) ./files/usr/lib/lua/prometheus-collectors/time.lua $(1)/usr/lib/lua/prometheus-collectors/ $(INSTALL_BIN) ./files/usr/lib/lua/prometheus-collectors/uname.lua $(1)/usr/lib/lua/prometheus-collectors/ + $(INSTALL_BIN) ./files/usr/lib/lua/prometheus-collectors/netclass.lua $(1)/usr/lib/lua/prometheus-collectors/ endef define Package/prometheus-node-exporter-lua/conffiles diff --git a/utils/prometheus-node-exporter-lua/files/etc/config/prometheus-node-exporter-lua b/utils/prometheus-node-exporter-lua/files/etc/config/prometheus-node-exporter-lua index 585e29b33..d424fe632 100644 --- a/utils/prometheus-node-exporter-lua/files/etc/config/prometheus-node-exporter-lua +++ b/utils/prometheus-node-exporter-lua/files/etc/config/prometheus-node-exporter-lua @@ -1,4 +1,3 @@ config prometheus-node-exporter-lua 'main' option listen_interface 'loopback' - option listen_ipv6 '0' option listen_port '9100' diff --git a/utils/prometheus-node-exporter-lua/files/etc/init.d/prometheus-node-exporter-lua b/utils/prometheus-node-exporter-lua/files/etc/init.d/prometheus-node-exporter-lua index 582e21161..57440d5ef 100644 --- a/utils/prometheus-node-exporter-lua/files/etc/init.d/prometheus-node-exporter-lua +++ b/utils/prometheus-node-exporter-lua/files/etc/init.d/prometheus-node-exporter-lua @@ -11,34 +11,31 @@ _log() { start_service() { . /lib/functions/network.sh - local interface ipv6 port bind + local interface port bind config_load prometheus-node-exporter-lua.main + config_get keepalive "main" http_keepalive 70 config_get interface "main" listen_interface "loopback" - config_get_bool ipv6 "main" listen_ipv6 0 config_get port "main" listen_port 9100 + procd_open_instance + + procd_set_param command /usr/sbin/uhttpd -f -c /dev/null -l / -L /usr/bin/prometheus-node-exporter-lua + [ $keepalive -gt 0 ] && procd_append_param command -k $keepalive + if [ "$interface" = "*" ]; then - [ "$ipv6" = 1 ] && bind="::" || bind="0.0.0.0" + procd_append_param command -p $port else - if [ "$ipv6" = 1 ]; then - network_get_ipaddr6 bind "$interface" - else - network_get_ipaddr bind "$interface" - fi - - network_is_up "$interface" && [ -n "$bind" ] || { + network_is_up "$interface" || { _log "defering start until listen interface $interface becomes ready" return 0 } + network_get_ipaddr6 bind "$interface" + [ -n "$bind" ] && procd_append_param command -p [$bind]:$port + network_get_ipaddr bind "$interface" + [ -n "$bind" ] && procd_append_param command -p $bind:$port fi - procd_open_instance - - procd_set_param command /usr/bin/prometheus-node-exporter-lua - procd_append_param command --bind ${bind} - procd_append_param command --port ${port} - procd_set_param stdout 1 procd_set_param stderr 1 procd_set_param respawn diff --git a/utils/prometheus-node-exporter-lua/files/usr/bin/prometheus-node-exporter-lua b/utils/prometheus-node-exporter-lua/files/usr/bin/prometheus-node-exporter-lua index dec55baa1..36f064c5b 100755 --- a/utils/prometheus-node-exporter-lua/files/usr/bin/prometheus-node-exporter-lua +++ b/utils/prometheus-node-exporter-lua/files/usr/bin/prometheus-node-exporter-lua @@ -59,7 +59,7 @@ function timed_scrape(collector) local status, err = pcall(collector.scrape) if not status then success = 0 - print(err) + io.stderr:write(err) end return (socket.gettime() - start_time), success end @@ -79,22 +79,18 @@ end -- Web server-specific functions -function http_ok_header() - output("HTTP/1.0 200 OK\r\nServer: lua-metrics\r\nContent-Type: text/plain; version=0.0.4\r\n\r") -end - -function http_not_found() - output("HTTP/1.0 404 Not Found\r\nServer: lua-metrics\r\nContent-Type: text/plain\r\n\r\nERROR: File Not Found.") -end - -function serve(request) - local q = request:match("^GET /metrics%??([^ ]*) HTTP/1%.[01]$") - if q == nil then - http_not_found() +function handle_request(env) + if env.PATH_INFO ~= '/metrics' then + uhttpd.send("Status: 404 Not Found\r\n") + uhttpd.send("Server: lua-metrics\r\n") + uhttpd.send("Content-Type: text/plain\r\n\r\n") + uhttpd.send("ERROR: File Not Found.") else - http_ok_header() + uhttpd.send("Status: 200 OK\r\n") + uhttpd.send("Server: lua-metrics\r\n") + uhttpd.send("Content-Type: text/plain; version=0.0.4\r\n\r\n") local cols = {} - for c in q:gmatch("collect[^=]*=([^&]+)") do + for c in env.QUERY_STRING:gmatch("collect[^=]*=([^&]+)") do cols[#cols+1] = c end if #cols == 0 then @@ -102,21 +98,10 @@ function serve(request) end run_all_collectors(cols) end - client:close() - return true end -- Main program -for k,v in ipairs(arg) do - if (v == "-p") or (v == "--port") then - port = arg[k+1] - end - if (v == "-b") or (v == "--bind") then - bind = arg[k+1] - end -end - col_mods = {} col_names = {} ls_fd = io.popen("ls -1 /usr/lib/lua/prometheus-collectors/*.lua") @@ -127,22 +112,9 @@ for c in ls_fd:lines() do end ls_fd:close() -if port then - server = assert(socket.bind(bind, port)) - - while 1 do - client = server:accept() - client:settimeout(60) - local request, err = client:receive() +output = function (str) uhttpd.send(str.."\n") end - if not err then - output = function (str) client:send(str.."\n") end - if not serve(request) then - break - end - end - end -else +if arg ~= nil then output = print run_all_collectors(col_names) end diff --git a/utils/prometheus-node-exporter-lua/files/usr/lib/lua/prometheus-collectors/hostapd_ubus_stations.lua b/utils/prometheus-node-exporter-lua/files/usr/lib/lua/prometheus-collectors/hostapd_ubus_stations.lua index 88a993c54..3ae441474 100644 --- a/utils/prometheus-node-exporter-lua/files/usr/lib/lua/prometheus-collectors/hostapd_ubus_stations.lua +++ b/utils/prometheus-node-exporter-lua/files/usr/lib/lua/prometheus-collectors/hostapd_ubus_stations.lua @@ -1,14 +1,13 @@ local ubus = require "ubus" local bit = require "bit" -local function get_wifi_interfaces() -- based on hostapd_stations.lua - local u = ubus.connect() - local status = u:call("network.wireless", "status", {}) +local function get_wifi_hostapd_interfaces(u) + local ubuslist = u:objects() local interfaces = {} - for _, dev_table in pairs(status) do - for _, intf in ipairs(dev_table['interfaces']) do - table.insert(interfaces, intf['ifname']) + for _,net in ipairs(ubuslist) do + if net.find(net,"hostapd.") then + table.insert(interfaces, net) end end @@ -16,6 +15,7 @@ local function get_wifi_interfaces() -- based on hostapd_stations.lua end local function scrape() + local u = ubus.connect() local metric_hostapd_ubus_station_rrm_caps_link_measurement = metric("hostapd_ubus_station_rrm_caps_link_measurement", "gauge") local metric_hostapd_ubus_station_rrm_caps_neighbor_report = @@ -55,14 +55,15 @@ local function scrape() metric_hostapd_ubus_station_rrm_caps_ftm_range_report(label_station, rrm_caps_ftm_range_report) end - for _, ifname in ipairs(get_wifi_interfaces()) do - local u = ubus.connect() - local clients_call = u:call("hostapd." .. ifname, "get_clients", {}) + for _, hostapd_int in ipairs(get_wifi_hostapd_interfaces(u)) do + local clients_call = u:call(hostapd_int, "get_clients", {}) + local ifname = hostapd_int:gsub("hostapd.", "") for client, client_table in pairs(clients_call['clients']) do evaluate_metrics(ifname, clients_call['freq'], client, client_table) end end + u:close() end return { scrape = scrape } diff --git a/utils/prometheus-node-exporter-lua/files/usr/lib/lua/prometheus-collectors/netclass.lua b/utils/prometheus-node-exporter-lua/files/usr/lib/lua/prometheus-collectors/netclass.lua new file mode 100644 index 000000000..f1bcf577e --- /dev/null +++ b/utils/prometheus-node-exporter-lua/files/usr/lib/lua/prometheus-collectors/netclass.lua @@ -0,0 +1,77 @@ +local ubus = require "ubus" + +-- reference/further reading: +-- - node_exporter netclass_linux (upstream metrics): https://github.com/prometheus/node_exporter/blob/master/collector/netclass_linux.go +-- - relevant sysfs files: https://github.com/prometheus/procfs/blob/5f46783c017ef6a934fc8cfa6d1a2206db21401b/sysfs/net_class.go#L121 +-- - get devices / read files: https://github.com/openwrt/packages/blob/openwrt-21.02/utils/prometheus-node-exporter-lua/files/usr/lib/lua/prometheus-collectors/snmp6.lua + +local function get_devices() -- based on hostapd_stations.lua + local u = ubus.connect() + local status = u:call("network.device", "status", {}) + local devices = {} + + for dev, dev_table in pairs(status) do + table.insert(devices, dev) + end + return devices +end + +local function load(device, file) -- load a single sysfs file, trim trailing newline, return nil on error + local success, data = pcall(function () return string.gsub(get_contents("/sys/class/net/" .. device .. "/" .. file), "\n$", "") end) + if success then + return data + else + return nil + end +end + +local function file_gauge(name, device, file) + local value = load(device, file) + if value ~= nil then + metric("node_network_" .. name, "gauge", {device = device}, tonumber(value)) + end +end + +local function file_counter(name, device, file) + local value = load(device, file) + if value ~= nil then + metric("node_network_" .. name, "counter", {device = device}, tonumber(value)) + end +end + +local function get_metric(device) + local address = load(device, "address") + local broadcast = load(device, "broadcast") + local duplex = load(device, "duplex") + local operstate = load(device, "operstate") + local ifalias = load(device, "ifalias") + metric("node_network_info", "gauge", {device = device, address = address, broadcast = broadcast, duplex = duplex, operstate = operstate, ifalias = ifalias}, 1) + file_gauge("address_assign_type", device, "addr_assign_type") + file_gauge("carrier", device, "carrier") + file_counter("carrier_changes_total", device, "carrier_changes") + file_counter("carrier_up_changes_total", device, "carrier_up_count") + file_counter("carrier_down_changes_total", device, "carrier_down_count") + file_gauge("device_id", device, "dev_id") + file_gauge("dormant", device, "dormant") + file_gauge("flags", device, "flags") + file_gauge("iface_id", device, "ifindex") + file_gauge("iface_link", device, "iflink") + file_gauge("iface_link_mode", device, "link_mode") + file_gauge("mtu_bytes", device, "mtu") + file_gauge("name_assign_type", device, "name_assign_type") + file_gauge("net_dev_group", device, "netdev_group") + file_gauge("transmit_queue_length", device, "tx_queue_len") + file_gauge("protocol_type", device, "type") + local speed = load(device, "speed") + if speed ~= nil and tonumber(speed) >= 0 then + metric("node_network_speed_bytes", "gauge", {device = device}, tonumber(speed)*1000*1000/8) + end +end + +local function scrape() + for _, devicename in ipairs(get_devices()) do + get_metric(devicename) + end +end + +return { scrape = scrape } diff --git a/utils/prometheus-node-exporter-lua/files/usr/lib/lua/prometheus-collectors/openwrt.lua b/utils/prometheus-node-exporter-lua/files/usr/lib/lua/prometheus-collectors/openwrt.lua index 8d44792b9..a92b7ddc1 100644 --- a/utils/prometheus-node-exporter-lua/files/usr/lib/lua/prometheus-collectors/openwrt.lua +++ b/utils/prometheus-node-exporter-lua/files/usr/lib/lua/prometheus-collectors/openwrt.lua @@ -12,9 +12,9 @@ local labels = { target = b.release.target } -b = nil -u = nil -ubus = nil +local b = nil +local u = nil +local ubus = nil local function scrape() metric("node_openwrt_info", "gauge", labels, 1)