Merge pull request #5128 from champtar/prometheus
prometheus-node-exporter-lua: make it modular and faster
This commit is contained in:
commit
367a1c7b89
14 changed files with 345 additions and 288 deletions
|
@ -4,7 +4,7 @@
|
||||||
include $(TOPDIR)/rules.mk
|
include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=prometheus-node-exporter-lua
|
PKG_NAME:=prometheus-node-exporter-lua
|
||||||
PKG_VERSION:=2017.05.07
|
PKG_VERSION:=2017.12.08
|
||||||
PKG_RELEASE:=1
|
PKG_RELEASE:=1
|
||||||
|
|
||||||
PKG_MAINTAINER:=Christian Simon <simon@swine.de>
|
PKG_MAINTAINER:=Christian Simon <simon@swine.de>
|
||||||
|
@ -12,15 +12,18 @@ PKG_LICENSE:=Apache-2.0
|
||||||
|
|
||||||
include $(INCLUDE_DIR)/package.mk
|
include $(INCLUDE_DIR)/package.mk
|
||||||
|
|
||||||
define Package/prometheus-node-exporter-lua
|
define Package/prometheus-node-exporter-lua/Default
|
||||||
SECTION:=utils
|
SECTION:=utils
|
||||||
CATEGORY:=Utilities
|
CATEGORY:=Utilities
|
||||||
TITLE:=Provides system statistics as Prometheus scraping endpoint
|
TITLE:=Prometheus node exporter
|
||||||
DEPENDS:=+luasocket
|
|
||||||
URL:=https://github.com/rbo/openwrt_exporter
|
|
||||||
PKGARCH:=all
|
PKGARCH:=all
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
define Package/prometheus-node-exporter-lua
|
||||||
|
$(call Package/prometheus-node-exporter-lua/Default)
|
||||||
|
DEPENDS:=+luasocket +lua
|
||||||
|
endef
|
||||||
|
|
||||||
define Package/prometheus-node-exporter-lua/conffiles
|
define Package/prometheus-node-exporter-lua/conffiles
|
||||||
/etc/config/prometheus-node-exporter-lua
|
/etc/config/prometheus-node-exporter-lua
|
||||||
endef
|
endef
|
||||||
|
@ -31,6 +34,30 @@ define Package/prometheus-node-exporter-lua/description
|
||||||
This service is a lightweight rewrite in LUA of the offical Prometheus node_exporter.
|
This service is a lightweight rewrite in LUA of the offical Prometheus node_exporter.
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
define Package/prometheus-node-exporter-lua-nat_traffic
|
||||||
|
$(call Package/prometheus-node-exporter-lua/Default)
|
||||||
|
TITLE+= (nat_traffic collector)
|
||||||
|
DEPENDS:=prometheus-node-exporter-lua
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/prometheus-node-exporter-lua-netstat
|
||||||
|
$(call Package/prometheus-node-exporter-lua/Default)
|
||||||
|
TITLE+= (netstat collector)
|
||||||
|
DEPENDS:=prometheus-node-exporter-lua
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/prometheus-node-exporter-lua-wifi
|
||||||
|
$(call Package/prometheus-node-exporter-lua/Default)
|
||||||
|
TITLE+= (wifi collector)
|
||||||
|
DEPENDS:=prometheus-node-exporter-lua +libiwinfo-lua +libubus-lua
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/prometheus-node-exporter-lua-wifi_stations
|
||||||
|
$(call Package/prometheus-node-exporter-lua/Default)
|
||||||
|
TITLE+= (wifi_stations collector)
|
||||||
|
DEPENDS:=prometheus-node-exporter-lua +libiwinfo-lua +libubus-lua
|
||||||
|
endef
|
||||||
|
|
||||||
Build/Compile=
|
Build/Compile=
|
||||||
|
|
||||||
define Package/prometheus-node-exporter-lua/install
|
define Package/prometheus-node-exporter-lua/install
|
||||||
|
@ -40,6 +67,38 @@ define Package/prometheus-node-exporter-lua/install
|
||||||
$(INSTALL_BIN) ./files/etc/init.d/prometheus-node-exporter-lua $(1)/etc/init.d/prometheus-node-exporter-lua
|
$(INSTALL_BIN) ./files/etc/init.d/prometheus-node-exporter-lua $(1)/etc/init.d/prometheus-node-exporter-lua
|
||||||
$(INSTALL_DIR) $(1)/usr/bin
|
$(INSTALL_DIR) $(1)/usr/bin
|
||||||
$(INSTALL_BIN) ./files/usr/bin/prometheus-node-exporter-lua $(1)/usr/bin/prometheus-node-exporter-lua
|
$(INSTALL_BIN) ./files/usr/bin/prometheus-node-exporter-lua $(1)/usr/bin/prometheus-node-exporter-lua
|
||||||
|
$(INSTALL_DIR) $(1)/usr/lib/lua/prometheus-collectors
|
||||||
|
$(INSTALL_BIN) ./files/usr/lib/lua/prometheus-collectors/cpu.lua $(1)/usr/lib/lua/prometheus-collectors/
|
||||||
|
$(INSTALL_BIN) ./files/usr/lib/lua/prometheus-collectors/filefd.lua $(1)/usr/lib/lua/prometheus-collectors/
|
||||||
|
$(INSTALL_BIN) ./files/usr/lib/lua/prometheus-collectors/loadavg.lua $(1)/usr/lib/lua/prometheus-collectors/
|
||||||
|
$(INSTALL_BIN) ./files/usr/lib/lua/prometheus-collectors/meminfo.lua $(1)/usr/lib/lua/prometheus-collectors/
|
||||||
|
$(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/
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/prometheus-node-exporter-lua-nat_traffic/install
|
||||||
|
$(INSTALL_DIR) $(1)/usr/lib/lua/prometheus-collectors
|
||||||
|
$(INSTALL_BIN) ./files/usr/lib/lua/prometheus-collectors/nat_traffic.lua $(1)/usr/lib/lua/prometheus-collectors/
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/prometheus-node-exporter-lua-netstat/install
|
||||||
|
$(INSTALL_DIR) $(1)/usr/lib/lua/prometheus-collectors
|
||||||
|
$(INSTALL_BIN) ./files/usr/lib/lua/prometheus-collectors/netstat.lua $(1)/usr/lib/lua/prometheus-collectors/
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/prometheus-node-exporter-lua-wifi/install
|
||||||
|
$(INSTALL_DIR) $(1)/usr/lib/lua/prometheus-collectors
|
||||||
|
$(INSTALL_BIN) ./files/usr/lib/lua/prometheus-collectors/wifi.lua $(1)/usr/lib/lua/prometheus-collectors/
|
||||||
|
endef
|
||||||
|
|
||||||
|
define Package/prometheus-node-exporter-lua-wifi_stations/install
|
||||||
|
$(INSTALL_DIR) $(1)/usr/lib/lua/prometheus-collectors
|
||||||
|
$(INSTALL_BIN) ./files/usr/lib/lua/prometheus-collectors/wifi_stations.lua $(1)/usr/lib/lua/prometheus-collectors/
|
||||||
endef
|
endef
|
||||||
|
|
||||||
$(eval $(call BuildPackage,prometheus-node-exporter-lua))
|
$(eval $(call BuildPackage,prometheus-node-exporter-lua))
|
||||||
|
$(eval $(call BuildPackage,prometheus-node-exporter-lua-nat_traffic))
|
||||||
|
$(eval $(call BuildPackage,prometheus-node-exporter-lua-netstat))
|
||||||
|
$(eval $(call BuildPackage,prometheus-node-exporter-lua-wifi))
|
||||||
|
$(eval $(call BuildPackage,prometheus-node-exporter-lua-wifi_stations))
|
||||||
|
|
|
@ -15,5 +15,8 @@ start_service() {
|
||||||
procd_append_param command --port ${port}
|
procd_append_param command --port ${port}
|
||||||
procd_append_param command --bind ${bind}
|
procd_append_param command --bind ${bind}
|
||||||
|
|
||||||
|
procd_set_param stdout 1
|
||||||
|
procd_set_param stderr 1
|
||||||
|
|
||||||
procd_close_instance
|
procd_close_instance
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,32 +8,16 @@
|
||||||
|
|
||||||
socket = require("socket")
|
socket = require("socket")
|
||||||
|
|
||||||
-- Allow us to call unpack under both lua5.1 and lua5.2+
|
|
||||||
local unpack = unpack or table.unpack
|
|
||||||
|
|
||||||
-- This table defines the scrapers to run.
|
|
||||||
-- Each corresponds directly to a scraper_<name> function.
|
|
||||||
scrapers = { "cpu", "load_averages", "memory", "file_handles", "network",
|
|
||||||
"network_devices", "time", "uname", "nat", "wifi"}
|
|
||||||
|
|
||||||
-- Parsing
|
-- Parsing
|
||||||
|
|
||||||
function space_split(s)
|
function space_split(s)
|
||||||
elements = {}
|
local elements = {}
|
||||||
for element in s:gmatch("%S+") do
|
for element in s:gmatch("%S+") do
|
||||||
table.insert(elements, element)
|
table.insert(elements, element)
|
||||||
end
|
end
|
||||||
return elements
|
return elements
|
||||||
end
|
end
|
||||||
|
|
||||||
function line_split(s)
|
|
||||||
elements = {}
|
|
||||||
for element in s:gmatch("[^\n]+") do
|
|
||||||
table.insert(elements, element)
|
|
||||||
end
|
|
||||||
return elements
|
|
||||||
end
|
|
||||||
|
|
||||||
function get_contents(filename)
|
function get_contents(filename)
|
||||||
local f = io.open(filename, "rb")
|
local f = io.open(filename, "rb")
|
||||||
local contents = ""
|
local contents = ""
|
||||||
|
@ -69,284 +53,54 @@ function metric(name, mtype, labels, value)
|
||||||
return outputter
|
return outputter
|
||||||
end
|
end
|
||||||
|
|
||||||
function scraper_wifi()
|
function timed_scrape(collector)
|
||||||
local rv = { }
|
|
||||||
local ntm = require "luci.model.network".init()
|
|
||||||
|
|
||||||
local metric_wifi_network_up = metric("wifi_network_up","gauge")
|
|
||||||
local metric_wifi_network_quality = metric("wifi_network_quality","gauge")
|
|
||||||
local metric_wifi_network_bitrate = metric("wifi_network_bitrate","gauge")
|
|
||||||
local metric_wifi_network_noise = metric("wifi_network_noise","gauge")
|
|
||||||
local metric_wifi_network_signal = metric("wifi_network_signal","gauge")
|
|
||||||
|
|
||||||
local metric_wifi_station_signal = metric("wifi_station_signal","gauge")
|
|
||||||
local metric_wifi_station_tx_packets = metric("wifi_station_tx_packets","gauge")
|
|
||||||
local metric_wifi_station_rx_packets = metric("wifi_station_rx_packets","gauge")
|
|
||||||
|
|
||||||
local dev
|
|
||||||
for _, dev in ipairs(ntm:get_wifidevs()) do
|
|
||||||
local rd = {
|
|
||||||
up = dev:is_up(),
|
|
||||||
device = dev:name(),
|
|
||||||
name = dev:get_i18n(),
|
|
||||||
networks = { }
|
|
||||||
}
|
|
||||||
|
|
||||||
local net
|
|
||||||
for _, net in ipairs(dev:get_wifinets()) do
|
|
||||||
local labels = {
|
|
||||||
channel = net:channel(),
|
|
||||||
ssid = net:active_ssid(),
|
|
||||||
bssid = net:active_bssid(),
|
|
||||||
mode = net:active_mode(),
|
|
||||||
ifname = net:ifname(),
|
|
||||||
country = net:country(),
|
|
||||||
frequency = net:frequency(),
|
|
||||||
}
|
|
||||||
if net:is_up() then
|
|
||||||
metric_wifi_network_up(labels, 1)
|
|
||||||
local signal = net:signal_percent()
|
|
||||||
if signal ~= 0 then
|
|
||||||
metric_wifi_network_quality(labels, net:signal_percent())
|
|
||||||
end
|
|
||||||
metric_wifi_network_noise(labels, net:noise())
|
|
||||||
local bitrate = net:bitrate()
|
|
||||||
if bitrate then
|
|
||||||
metric_wifi_network_bitrate(labels, bitrate)
|
|
||||||
end
|
|
||||||
|
|
||||||
local assoclist = net:assoclist()
|
|
||||||
for mac, station in pairs(assoclist) do
|
|
||||||
local labels = {
|
|
||||||
ifname = net:ifname(),
|
|
||||||
mac = mac,
|
|
||||||
}
|
|
||||||
metric_wifi_station_signal(labels, station.signal)
|
|
||||||
metric_wifi_station_tx_packets(labels, station.tx_packets)
|
|
||||||
metric_wifi_station_rx_packets(labels, station.rx_packets)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
metric_wifi_network_up(labels, 0)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
rv[#rv+1] = rd
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function scraper_cpu()
|
|
||||||
local stat = get_contents("/proc/stat")
|
|
||||||
|
|
||||||
-- system boot time, seconds since epoch
|
|
||||||
metric("node_boot_time", "gauge", nil, string.match(stat, "btime ([0-9]+)"))
|
|
||||||
|
|
||||||
-- context switches since boot (all CPUs)
|
|
||||||
metric("node_context_switches", "counter", nil, string.match(stat, "ctxt ([0-9]+)"))
|
|
||||||
|
|
||||||
-- cpu times, per CPU, per mode
|
|
||||||
local cpu_mode = {"user", "nice", "system", "idle", "iowait", "irq",
|
|
||||||
"softirq", "steal", "guest", "guest_nice"}
|
|
||||||
local i = 0
|
|
||||||
local cpu_metric = metric("node_cpu", "counter")
|
|
||||||
while string.match(stat, string.format("cpu%d ", i)) do
|
|
||||||
local cpu = space_split(string.match(stat, string.format("cpu%d ([0-9 ]+)", i)))
|
|
||||||
local labels = {cpu = "cpu" .. i}
|
|
||||||
for ii, mode in ipairs(cpu_mode) do
|
|
||||||
labels['mode'] = mode
|
|
||||||
cpu_metric(labels, cpu[ii] / 100)
|
|
||||||
end
|
|
||||||
i = i + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
-- interrupts served
|
|
||||||
metric("node_intr", "counter", nil, string.match(stat, "intr ([0-9]+)"))
|
|
||||||
|
|
||||||
-- processes forked
|
|
||||||
metric("node_forks", "counter", nil, string.match(stat, "processes ([0-9]+)"))
|
|
||||||
|
|
||||||
-- processes running
|
|
||||||
metric("node_procs_running", "gauge", nil, string.match(stat, "procs_running ([0-9]+)"))
|
|
||||||
|
|
||||||
-- processes blocked for I/O
|
|
||||||
metric("node_procs_blocked", "gauge", nil, string.match(stat, "procs_blocked ([0-9]+)"))
|
|
||||||
end
|
|
||||||
|
|
||||||
function scraper_load_averages()
|
|
||||||
local loadavg = space_split(get_contents("/proc/loadavg"))
|
|
||||||
|
|
||||||
metric("node_load1", "gauge", nil, loadavg[1])
|
|
||||||
metric("node_load5", "gauge", nil, loadavg[2])
|
|
||||||
metric("node_load15", "gauge", nil, loadavg[3])
|
|
||||||
end
|
|
||||||
|
|
||||||
function scraper_memory()
|
|
||||||
local meminfo = line_split(get_contents("/proc/meminfo"):gsub("[):]", ""):gsub("[(]", "_"))
|
|
||||||
|
|
||||||
for i, mi in ipairs(meminfo) do
|
|
||||||
local name, size, unit = unpack(space_split(mi))
|
|
||||||
if unit == 'kB' then
|
|
||||||
size = size * 1024
|
|
||||||
end
|
|
||||||
metric("node_memory_" .. name, "gauge", nil, size)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function scraper_file_handles()
|
|
||||||
local file_nr = space_split(get_contents("/proc/sys/fs/file-nr"))
|
|
||||||
|
|
||||||
metric("node_filefd_allocated", "gauge", nil, file_nr[1])
|
|
||||||
metric("node_filefd_maximum", "gauge", nil, file_nr[3])
|
|
||||||
end
|
|
||||||
|
|
||||||
function scraper_network()
|
|
||||||
-- NOTE: Both of these are missing in OpenWRT kernels.
|
|
||||||
-- See: https://dev.openwrt.org/ticket/15781
|
|
||||||
local netstat = get_contents("/proc/net/netstat") .. get_contents("/proc/net/snmp")
|
|
||||||
|
|
||||||
-- all devices
|
|
||||||
local netsubstat = {"IcmpMsg", "Icmp", "IpExt", "Ip", "TcpExt", "Tcp", "UdpLite", "Udp"}
|
|
||||||
for i, nss in ipairs(netsubstat) do
|
|
||||||
local substat_s = string.match(netstat, nss .. ": ([A-Z][A-Za-z0-9 ]+)")
|
|
||||||
if substat_s then
|
|
||||||
local substat = space_split(substat_s)
|
|
||||||
local substatv = space_split(string.match(netstat, nss .. ": ([0-9 -]+)"))
|
|
||||||
for ii, ss in ipairs(substat) do
|
|
||||||
metric("node_netstat_" .. nss .. "_" .. ss, "gauge", nil, substatv[ii])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function scraper_network_devices()
|
|
||||||
local netdevstat = line_split(get_contents("/proc/net/dev"))
|
|
||||||
local netdevsubstat = {"receive_bytes", "receive_packets", "receive_errs",
|
|
||||||
"receive_drop", "receive_fifo", "receive_frame", "receive_compressed",
|
|
||||||
"receive_multicast", "transmit_bytes", "transmit_packets",
|
|
||||||
"transmit_errs", "transmit_drop", "transmit_fifo", "transmit_colls",
|
|
||||||
"transmit_carrier", "transmit_compressed"}
|
|
||||||
for i, line in ipairs(netdevstat) do
|
|
||||||
netdevstat[i] = string.match(netdevstat[i], "%S.*")
|
|
||||||
end
|
|
||||||
local nds_table = {}
|
|
||||||
local devs = {}
|
|
||||||
for i, nds in ipairs(netdevstat) do
|
|
||||||
local dev, stat_s = string.match(netdevstat[i], "([^:]+): (.*)")
|
|
||||||
if dev then
|
|
||||||
nds_table[dev] = space_split(stat_s)
|
|
||||||
table.insert(devs, dev)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for i, ndss in ipairs(netdevsubstat) do
|
|
||||||
netdev_metric = metric("node_network_" .. ndss, "gauge")
|
|
||||||
for ii, d in ipairs(devs) do
|
|
||||||
netdev_metric({device=d}, nds_table[d][i])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function scraper_time()
|
|
||||||
-- current time
|
|
||||||
metric("node_time", "counter", nil, os.time())
|
|
||||||
end
|
|
||||||
|
|
||||||
function scraper_uname()
|
|
||||||
-- version can have spaces, so grab it directly
|
|
||||||
local version = string.sub(io.popen("uname -v"):read("*a"), 1, -2)
|
|
||||||
-- avoid individual popen calls for the rest of the values
|
|
||||||
local uname_string = io.popen("uname -a"):read("*a")
|
|
||||||
local sysname, nodename, release = unpack(space_split(uname_string))
|
|
||||||
local labels = {domainname = "(none)", nodename = nodename, release = release,
|
|
||||||
sysname = sysname, version = version}
|
|
||||||
|
|
||||||
-- The machine hardware name is immediately after the version string, so add
|
|
||||||
-- up the values we know and add in the 4 spaces to find the offset...
|
|
||||||
machine_offset = string.len(sysname .. nodename .. release .. version) + 4
|
|
||||||
labels['machine'] = string.match(string.sub(uname_string, machine_offset), "(%S+)" )
|
|
||||||
metric("node_uname_info", "gauge", labels, 1)
|
|
||||||
end
|
|
||||||
|
|
||||||
function scraper_nat()
|
|
||||||
-- documetation about nf_conntrack:
|
|
||||||
-- https://www.frozentux.net/iptables-tutorial/chunkyhtml/x1309.html
|
|
||||||
-- local natstat = line_split(get_contents("/proc/net/nf_conntrack"))
|
|
||||||
local natstat = line_split(get_contents("nf_conntrack"))
|
|
||||||
|
|
||||||
nat_metric = metric("node_nat_traffic", "gauge" )
|
|
||||||
for i, e in ipairs(natstat) do
|
|
||||||
-- output(string.format("%s\n",e ))
|
|
||||||
local fields = space_split(e)
|
|
||||||
local src, dest, bytes;
|
|
||||||
bytes = 0;
|
|
||||||
for ii, field in ipairs(fields) do
|
|
||||||
if src == nil and string.match(field, '^src') then
|
|
||||||
src = string.match(field,"src=([^ ]+)");
|
|
||||||
elseif dest == nil and string.match(field, '^dst') then
|
|
||||||
dest = string.match(field,"dst=([^ ]+)");
|
|
||||||
elseif string.match(field, '^bytes') then
|
|
||||||
local b = string.match(field, "bytes=([^ ]+)");
|
|
||||||
bytes = bytes + b;
|
|
||||||
-- output(string.format("\t%d %s",ii,field ));
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
-- local src, dest, bytes = string.match(natstat[i], "src=([^ ]+) dst=([^ ]+) .- bytes=([^ ]+)");
|
|
||||||
-- local src, dest, bytes = string.match(natstat[i], "src=([^ ]+) dst=([^ ]+) sport=[^ ]+ dport=[^ ]+ packets=[^ ]+ bytes=([^ ]+)")
|
|
||||||
|
|
||||||
local labels = { src = src, dest = dest }
|
|
||||||
-- output(string.format("src=|%s| dest=|%s| bytes=|%s|", src, dest, bytes ))
|
|
||||||
nat_metric(labels, bytes )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function timed_scrape(scraper)
|
|
||||||
local start_time = socket.gettime()
|
local start_time = socket.gettime()
|
||||||
-- build the function name and call it from global variable table
|
local success = 1
|
||||||
_G["scraper_"..scraper]()
|
local status, err = pcall(collector.scrape)
|
||||||
local duration = socket.gettime() - start_time
|
if not status then
|
||||||
return duration
|
success = 0
|
||||||
|
print(err)
|
||||||
|
end
|
||||||
|
return (socket.gettime() - start_time), success
|
||||||
end
|
end
|
||||||
|
|
||||||
function run_all_scrapers()
|
function run_all_collectors(collectors)
|
||||||
times = {}
|
local metric_duration = metric("node_scrape_collector_duration_seconds", "gauge")
|
||||||
for i,scraper in ipairs(scrapers) do
|
local metric_success = metric("node_scrape_collector_success", "gauge")
|
||||||
runtime = timed_scrape(scraper)
|
for _,cname in pairs(collectors) do
|
||||||
times[scraper] = runtime
|
if col_mods[cname] ~= nil then
|
||||||
scrape_time_sums[scraper] = scrape_time_sums[scraper] + runtime
|
local duration, success = timed_scrape(col_mods[cname])
|
||||||
scrape_counts[scraper] = scrape_counts[scraper] + 1
|
local labels = {collector=cname}
|
||||||
end
|
metric_duration(labels, duration)
|
||||||
|
metric_success(labels, success)
|
||||||
local name = "node_exporter_scrape_duration_seconds"
|
end
|
||||||
local duration_metric = metric(name, "summary")
|
|
||||||
for i,scraper in ipairs(scrapers) do
|
|
||||||
local labels = {collector=scraper, result="success"}
|
|
||||||
duration_metric(labels, times[scraper])
|
|
||||||
print_metric(name.."_sum", labels, scrape_time_sums[scraper])
|
|
||||||
print_metric(name.."_count", labels, scrape_counts[scraper])
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Web server-specific functions
|
-- Web server-specific functions
|
||||||
|
|
||||||
function http_ok_header()
|
function http_ok_header()
|
||||||
output("HTTP/1.1 200 OK\r")
|
output("HTTP/1.0 200 OK\r\nServer: lua-metrics\r\nContent-Type: text/plain; version=0.0.4\r\n\r")
|
||||||
output("Server: lua-metrics\r")
|
|
||||||
output("Content-Type: text/plain; version=0.0.4\r")
|
|
||||||
output("\r")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function http_not_found()
|
function http_not_found()
|
||||||
output("HTTP/1.1 404 Not Found\r")
|
output("HTTP/1.0 404 Not Found\r\nServer: lua-metrics\r\nContent-Type: text/plain\r\n\r\nERROR: File Not Found.")
|
||||||
output("Server: lua-metrics\r")
|
|
||||||
output("Content-Type: text/plain\r")
|
|
||||||
output("\r")
|
|
||||||
output("ERROR: File Not Found.")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function serve(request)
|
function serve(request)
|
||||||
if not string.match(request, "GET /metrics.*") then
|
local q = request:match("^GET /metrics%??([^ ]*) HTTP/1%.[01]$")
|
||||||
|
if q == nil then
|
||||||
http_not_found()
|
http_not_found()
|
||||||
else
|
else
|
||||||
http_ok_header()
|
http_ok_header()
|
||||||
run_all_scrapers()
|
local cols = {}
|
||||||
|
for c in q:gmatch("collect[^=]*=([^&]+)") do
|
||||||
|
cols[#cols+1] = c
|
||||||
|
end
|
||||||
|
if #cols == 0 then
|
||||||
|
cols = col_names
|
||||||
|
end
|
||||||
|
run_all_collectors(cols)
|
||||||
end
|
end
|
||||||
client:close()
|
client:close()
|
||||||
return true
|
return true
|
||||||
|
@ -363,11 +117,12 @@ for k,v in ipairs(arg) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
scrape_counts = {}
|
col_mods = {}
|
||||||
scrape_time_sums = {}
|
col_names = {}
|
||||||
for i,scraper in ipairs(scrapers) do
|
for c in io.popen("ls -1 /usr/lib/lua/prometheus-collectors/*.lua"):lines() do
|
||||||
scrape_counts[scraper] = 0
|
c = c:match("([^/]+)%.lua$")
|
||||||
scrape_time_sums[scraper] = 0
|
col_mods[c] = require('prometheus-collectors.'..c)
|
||||||
|
col_names[#col_names+1] = c
|
||||||
end
|
end
|
||||||
|
|
||||||
if port then
|
if port then
|
||||||
|
@ -387,5 +142,5 @@ if port then
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
output = print
|
output = print
|
||||||
run_all_scrapers()
|
run_all_collectors(col_names)
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
-- stat/cpu collector
|
||||||
|
local function scrape()
|
||||||
|
local stat = get_contents("/proc/stat")
|
||||||
|
|
||||||
|
-- system boot time, seconds since epoch
|
||||||
|
metric("node_boot_time", "gauge", nil, string.match(stat, "btime ([0-9]+)"))
|
||||||
|
|
||||||
|
-- context switches since boot (all CPUs)
|
||||||
|
metric("node_context_switches", "counter", nil, string.match(stat, "ctxt ([0-9]+)"))
|
||||||
|
|
||||||
|
-- cpu times, per CPU, per mode
|
||||||
|
local cpu_mode = {"user", "nice", "system", "idle", "iowait", "irq",
|
||||||
|
"softirq", "steal", "guest", "guest_nice"}
|
||||||
|
local i = 0
|
||||||
|
local cpu_metric = metric("node_cpu", "counter")
|
||||||
|
while true do
|
||||||
|
local cpu = {string.match(stat, "cpu"..i.." (%d+) (%d+) (%d+) (%d+) (%d+) (%d+) (%d+) (%d+) (%d+) (%d+)")}
|
||||||
|
if #cpu ~= 10 then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
for ii, mode in ipairs(cpu_mode) do
|
||||||
|
cpu_metric({cpu="cpu"..i, mode=mode}, cpu[ii] / 100)
|
||||||
|
end
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
-- interrupts served
|
||||||
|
metric("node_intr", "counter", nil, string.match(stat, "intr ([0-9]+)"))
|
||||||
|
|
||||||
|
-- processes forked
|
||||||
|
metric("node_forks", "counter", nil, string.match(stat, "processes ([0-9]+)"))
|
||||||
|
|
||||||
|
-- processes running
|
||||||
|
metric("node_procs_running", "gauge", nil, string.match(stat, "procs_running ([0-9]+)"))
|
||||||
|
|
||||||
|
-- processes blocked for I/O
|
||||||
|
metric("node_procs_blocked", "gauge", nil, string.match(stat, "procs_blocked ([0-9]+)"))
|
||||||
|
end
|
||||||
|
|
||||||
|
return { scrape = scrape }
|
|
@ -0,0 +1,8 @@
|
||||||
|
local function scrape()
|
||||||
|
local file_nr = space_split(get_contents("/proc/sys/fs/file-nr"))
|
||||||
|
|
||||||
|
metric("node_filefd_allocated", "gauge", nil, file_nr[1])
|
||||||
|
metric("node_filefd_maximum", "gauge", nil, file_nr[3])
|
||||||
|
end
|
||||||
|
|
||||||
|
return { scrape = scrape }
|
|
@ -0,0 +1,9 @@
|
||||||
|
local function scrape()
|
||||||
|
local loadavg = space_split(get_contents("/proc/loadavg"))
|
||||||
|
|
||||||
|
metric("node_load1", "gauge", nil, loadavg[1])
|
||||||
|
metric("node_load5", "gauge", nil, loadavg[2])
|
||||||
|
metric("node_load15", "gauge", nil, loadavg[3])
|
||||||
|
end
|
||||||
|
|
||||||
|
return { scrape = scrape }
|
|
@ -0,0 +1,11 @@
|
||||||
|
local function scrape()
|
||||||
|
for line in io.lines("/proc/meminfo") do
|
||||||
|
local name, size, unit = string.match(line, "([^:]+):%s+(%d+)%s?(k?B?)")
|
||||||
|
if unit == 'kB' then
|
||||||
|
size = size * 1024
|
||||||
|
end
|
||||||
|
metric("node_memory_" .. name:gsub("[):]", ""):gsub("[(]", "_"), "gauge", nil, size)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return { scrape = scrape }
|
|
@ -0,0 +1,31 @@
|
||||||
|
local function scrape()
|
||||||
|
-- documetation about nf_conntrack:
|
||||||
|
-- https://www.frozentux.net/iptables-tutorial/chunkyhtml/x1309.html
|
||||||
|
nat_metric = metric("node_nat_traffic", "gauge" )
|
||||||
|
for e in io.lines("/proc/net/nf_conntrack") do
|
||||||
|
-- output(string.format("%s\n",e ))
|
||||||
|
local fields = space_split(e)
|
||||||
|
local src, dest, bytes;
|
||||||
|
bytes = 0;
|
||||||
|
for _, field in ipairs(fields) do
|
||||||
|
if src == nil and string.match(field, '^src') then
|
||||||
|
src = string.match(field,"src=([^ ]+)");
|
||||||
|
elseif dest == nil and string.match(field, '^dst') then
|
||||||
|
dest = string.match(field,"dst=([^ ]+)");
|
||||||
|
elseif string.match(field, '^bytes') then
|
||||||
|
local b = string.match(field, "bytes=([^ ]+)");
|
||||||
|
bytes = bytes + b;
|
||||||
|
-- output(string.format("\t%d %s",ii,field ));
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
-- local src, dest, bytes = string.match(natstat[i], "src=([^ ]+) dst=([^ ]+) .- bytes=([^ ]+)");
|
||||||
|
-- local src, dest, bytes = string.match(natstat[i], "src=([^ ]+) dst=([^ ]+) sport=[^ ]+ dport=[^ ]+ packets=[^ ]+ bytes=([^ ]+)")
|
||||||
|
|
||||||
|
local labels = { src = src, dest = dest }
|
||||||
|
-- output(string.format("src=|%s| dest=|%s| bytes=|%s|", src, dest, bytes ))
|
||||||
|
nat_metric(labels, bytes )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return { scrape = scrape }
|
|
@ -0,0 +1,25 @@
|
||||||
|
|
||||||
|
local netdevsubstat = {"receive_bytes", "receive_packets", "receive_errs",
|
||||||
|
"receive_drop", "receive_fifo", "receive_frame", "receive_compressed",
|
||||||
|
"receive_multicast", "transmit_bytes", "transmit_packets",
|
||||||
|
"transmit_errs", "transmit_drop", "transmit_fifo", "transmit_colls",
|
||||||
|
"transmit_carrier", "transmit_compressed"}
|
||||||
|
local pattern = "([^%s:]+):%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)"
|
||||||
|
|
||||||
|
local function scrape()
|
||||||
|
local nds_table = {}
|
||||||
|
for line in io.lines("/proc/net/dev") do
|
||||||
|
local t = {string.match(line, pattern)}
|
||||||
|
if #t == 17 then
|
||||||
|
nds_table[t[1]] = t
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for i, ndss in ipairs(netdevsubstat) do
|
||||||
|
netdev_metric = metric("node_network_" .. ndss, "gauge")
|
||||||
|
for dev, nds_dev in pairs(nds_table) do
|
||||||
|
netdev_metric({device=dev}, nds_dev[i+1])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return { scrape = scrape }
|
|
@ -0,0 +1,20 @@
|
||||||
|
local function scrape()
|
||||||
|
-- NOTE: Both of these are missing in OpenWRT kernels.
|
||||||
|
-- See: https://dev.openwrt.org/ticket/15781
|
||||||
|
local netstat = get_contents("/proc/net/netstat") .. get_contents("/proc/net/snmp")
|
||||||
|
|
||||||
|
-- all devices
|
||||||
|
local netsubstat = {"IcmpMsg", "Icmp", "IpExt", "Ip", "TcpExt", "Tcp", "UdpLite", "Udp"}
|
||||||
|
for i, nss in ipairs(netsubstat) do
|
||||||
|
local substat_s = string.match(netstat, nss .. ": ([A-Z][A-Za-z0-9 ]+)")
|
||||||
|
if substat_s then
|
||||||
|
local substat = space_split(substat_s)
|
||||||
|
local substatv = space_split(string.match(netstat, nss .. ": ([0-9 -]+)"))
|
||||||
|
for ii, ss in ipairs(substat) do
|
||||||
|
metric("node_netstat_" .. nss .. "_" .. ss, "gauge", nil, substatv[ii])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return { scrape = scrape }
|
|
@ -0,0 +1,6 @@
|
||||||
|
local function scrape()
|
||||||
|
-- current time
|
||||||
|
metric("node_time", "counter", nil, os.time())
|
||||||
|
end
|
||||||
|
|
||||||
|
return { scrape = scrape }
|
|
@ -0,0 +1,16 @@
|
||||||
|
local labels = {
|
||||||
|
domainname = "",
|
||||||
|
nodename = "",
|
||||||
|
release = string.sub(get_contents("/proc/sys/kernel/osrelease"), 1, -2),
|
||||||
|
sysname = string.sub(get_contents("/proc/sys/kernel/ostype"), 1, -2),
|
||||||
|
version = string.sub(get_contents("/proc/sys/kernel/version"), 1, -2),
|
||||||
|
machine = string.sub(io.popen("uname -m"):read("*a"), 1, -2)
|
||||||
|
}
|
||||||
|
|
||||||
|
local function scrape()
|
||||||
|
labels["domainname"] = string.sub(get_contents("/proc/sys/kernel/domainname"), 1, -2)
|
||||||
|
labels["nodename"] = string.sub(get_contents("/proc/sys/kernel/hostname"), 1, -2)
|
||||||
|
metric("node_uname_info", "gauge", labels, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
return { scrape = scrape }
|
|
@ -0,0 +1,43 @@
|
||||||
|
local ubus = require "ubus"
|
||||||
|
local iwinfo = require "iwinfo"
|
||||||
|
|
||||||
|
local function scrape()
|
||||||
|
local metric_wifi_network_quality = metric("wifi_network_quality","gauge")
|
||||||
|
local metric_wifi_network_bitrate = metric("wifi_network_bitrate","gauge")
|
||||||
|
local metric_wifi_network_noise = metric("wifi_network_noise","gauge")
|
||||||
|
local metric_wifi_network_signal = metric("wifi_network_signal","gauge")
|
||||||
|
|
||||||
|
local u = ubus.connect()
|
||||||
|
local status = u:call("network.wireless", "status", {})
|
||||||
|
|
||||||
|
for dev, dev_table in pairs(status) do
|
||||||
|
for _, intf in ipairs(dev_table['interfaces']) do
|
||||||
|
local ifname = intf['ifname']
|
||||||
|
local iw = iwinfo[iwinfo.type(ifname)]
|
||||||
|
local labels = {
|
||||||
|
channel = iw.channel(ifname),
|
||||||
|
ssid = iw.ssid(ifname),
|
||||||
|
bssid = iw.bssid(ifname),
|
||||||
|
mode = iw.mode(ifname),
|
||||||
|
ifname = ifname,
|
||||||
|
country = iw.country(ifname),
|
||||||
|
frequency = iw.frequency(ifname),
|
||||||
|
device = dev,
|
||||||
|
}
|
||||||
|
|
||||||
|
local qc = iw.quality(ifname) or 0
|
||||||
|
local qm = iw.quality_max(ifname) or 0
|
||||||
|
local quality = 0
|
||||||
|
if qc > 0 and qm > 0 then
|
||||||
|
quality = math.floor((100 / qm) * qc)
|
||||||
|
end
|
||||||
|
|
||||||
|
metric_wifi_network_quality(labels, quality)
|
||||||
|
metric_wifi_network_noise(labels, iw.noise(ifname) or 0)
|
||||||
|
metric_wifi_network_bitrate(labels, iw.bitrate(ifname) or 0)
|
||||||
|
metric_wifi_network_signal(labels, iw.signal(ifname) or -255)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return { scrape = scrape }
|
|
@ -0,0 +1,31 @@
|
||||||
|
local ubus = require "ubus"
|
||||||
|
local iwinfo = require "iwinfo"
|
||||||
|
|
||||||
|
local function scrape()
|
||||||
|
local metric_wifi_station_signal = metric("wifi_station_signal","gauge")
|
||||||
|
local metric_wifi_station_tx_packets = metric("wifi_station_tx_packets","gauge")
|
||||||
|
local metric_wifi_station_rx_packets = metric("wifi_station_rx_packets","gauge")
|
||||||
|
|
||||||
|
local u = ubus.connect()
|
||||||
|
local status = u:call("network.wireless", "status", {})
|
||||||
|
|
||||||
|
for dev, dev_table in pairs(status) do
|
||||||
|
for _, intf in ipairs(dev_table['interfaces']) do
|
||||||
|
local ifname = intf['ifname']
|
||||||
|
local iw = iwinfo[iwinfo.type(ifname)]
|
||||||
|
|
||||||
|
local assoclist = iw.assoclist(ifname)
|
||||||
|
for mac, station in pairs(assoclist) do
|
||||||
|
local labels = {
|
||||||
|
ifname = ifname,
|
||||||
|
mac = mac,
|
||||||
|
}
|
||||||
|
metric_wifi_station_signal(labels, station.signal)
|
||||||
|
metric_wifi_station_tx_packets(labels, station.tx_packets)
|
||||||
|
metric_wifi_station_rx_packets(labels, station.rx_packets)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return { scrape = scrape }
|
Loading…
Reference in a new issue