File

mod_munin/mod_munin.lua @ 6302:06fbbd45ba75

mod_cloud_notify: Readme: fix links and labels that were removed in the last commit diff --git a/mod_cloud_notify/README.md b/mod_cloud_notify/README.md --- a/mod_cloud_notify/README.md +++ b/mod_cloud_notify/README.md @@ -1,3 +1,9 @@ +---- +-labels: +-- 'Stage-Beta' +-summary: 'XEP-0357: Cloud push notifications' +---- + # Introduction This module enables support for sending "push notifications" to clients @@ -32,15 +38,15 @@ notification to your device. When your d it will display it or wake up the app so it can connect to XMPP and receive any pending messages. -This protocol is described for developers in \[XEP-0357: Push -Notifications\]. +This protocol is described for developers in [XEP-0357: Push +Notifications]. -For this module to work reliably, you must have \[mod_smacks\], -\[mod_mam\] and \[mod_carbons\] also enabled on your server. +For this module to work reliably, you must have [mod_smacks], +[mod_mam] and [mod_carbons] also enabled on your server. Some clients, notably Siskin and Snikket iOS need some additional extensions that are not currently defined in a standard XEP. To support -these clients, see \[mod_cloud_notify_extensions\]. +these clients, see [mod_cloud_notify_extensions]. # Configuration @@ -58,18 +64,18 @@ these clients, see \[mod_cloud_notify_ex # Internal design notes App servers are notified about offline messages, messages stored by -\[mod_mam\] or messages waiting in the smacks queue. The business rules +[mod_mam] or messages waiting in the smacks queue. The business rules outlined [here](//mail.jabber.org/pipermail/standards/2016-February/030925.html) are all honored[^2]. -To cooperate with \[mod_smacks\] this module consumes some events: +To cooperate with [mod_smacks] this module consumes some events: `smacks-ack-delayed`, `smacks-hibernation-start` and `smacks-hibernation-end`. These events allow this module to send out notifications for messages received while the session is hibernated by -\[mod_smacks\] or even when smacks acknowledgements for messages are +[mod_smacks] or even when smacks acknowledgements for messages are delayed by a certain amount of seconds configurable with the -\[mod_smacks\] setting `smacks_max_ack_delay`. +[mod_smacks] setting `smacks_max_ack_delay`. The `smacks_max_ack_delay` setting allows to send out notifications to clients which aren't already in smacks hibernation state (because the
author Menel <menel@snikket.de>
date Fri, 13 Jun 2025 10:44:37 +0200
parent 4553:7e5c8186f121
line wrap: on
line source

module:set_global();

local s_format = string.format;
local t_insert = table.insert;
local t_concat = table.concat;
local array = require"util.array";
local it = require"util.iterators";
local mt = require"util.multitable";

local meta = mt.new(); meta.data = module:shared"meta";
local data = mt.new(); data.data = module:shared"data";

local munin_listener = {};
local munin_commands = {};

local node_name = module:get_option_string("munin_node_name", "localhost");
local ignore_stats = module:get_option_set("munin_ignored_stats", { });

local function clean_fieldname(name)
	return (name:gsub("[^A-Za-z0-9_]", "_"):gsub("^[^A-Za-z_]", "_%1"));
end

function munin_listener.onconnect(conn)
	-- require"core.statsmanager".collect();
	conn:write("# munin node at "..node_name.."\n");
end

function munin_listener.onincoming(conn, line)
	line = line and line:match("^[^\r\n]+");
	if type(line) ~= "string" then return end
	-- module:log("debug", "incoming: %q", line);
	local command = line:match"^%w+";
	command = munin_commands[command];
	if not command then
		conn:write("# Unknown command.\n");
		return;
	end
	local ok, err = pcall(command, conn, line);
	if not ok then
		module:log("error", "Error running %q: %s", line, err);
		conn:close();
	end
end

function munin_listener.ondisconnect() end

function munin_commands.cap(conn)
	conn:write("cap\n");
end

function munin_commands.list(conn)
	conn:write(array(it.keys(data.data)):concat(" ") .. "\n");
end

function munin_commands.config(conn, line)
	-- TODO what exactly?
	local stat = line:match("%s(%S+)");
	if not stat then conn:write("# Unknown service\n.\n"); return end
	for _, _, k, value in meta:iter(stat, "", nil) do
		conn:write(s_format("%s %s\n", k, value));
	end
	for _, name, k, value in meta:iter(stat, nil, nil) do
		if name ~= "" and not ignore_stats:contains(name) then
			conn:write(s_format("%s.%s %s\n", name, k, value));
		end
	end
	conn:write(".\n");
end

function munin_commands.fetch(conn, line)
	local stat = line:match("%s(%S+)");
	if not stat then conn:write("# Unknown service\n.\n"); return end
	for _, name, value in data:iter(stat, nil) do
		if not ignore_stats:contains(name) then
			conn:write(s_format("%s.value %.12f\n", name, value));
		end
	end
	conn:write(".\n");
end

function munin_commands.quit(conn)
	conn:close();
end

module:hook("stats-updated", function (event)
	local all_stats, this = event.stats_extra;
	local host, sect, name, typ, key;
	for stat, value in pairs(event.changed_stats) do
		if not ignore_stats:contains(stat) then
			this = all_stats[stat];
			-- module:log("debug", "changed_stats[%q] = %s", stat, tostring(value));
			host, sect, name, typ = stat:match("^/([^/]+)/([^/]+)/(.+):(%a+)$");
			if host == nil then
				sect, name, typ = stat:match("^([^.]+)%.(.+):(%a+)$");
			elseif host == "*" then
				host = nil;
			end
			if sect:find("^mod_measure_.") then
				sect = sect:sub(13);
			elseif sect:find("^mod_statistics_.") then
				sect = sect:sub(16);
			end
			key = clean_fieldname(s_format("%s_%s_%s", host or "global", sect, typ));

			if not meta:get(key) then
				if host then
					meta:set(key, "", "graph_title", s_format("%s %s on %s", sect, typ, host));
				else
					meta:set(key, "", "graph_title", s_format("Global %s %s", sect, typ));
				end
				meta:set(key, "", "graph_vlabel", this and this.units or typ);
				meta:set(key, "", "graph_category", sect);

				meta:set(key, name, "label", name);
			elseif not meta:get(key, name, "label") then
				meta:set(key, name, "label", name);
			end

			data:set(key, name, value);
		end
	end
end);

local function openmetrics_handler(event)
	local registry = event.metric_registry
	local host, sect, name, typ, key;
	for family_name, metric_family in pairs(registry:get_metric_families()) do
		if not ignore_stats:contains(family_name) then
			-- module:log("debug", "changed_stats[%q] = %s", stat, tostring(value));
			local host_key
			if metric_family.label_keys[1] == "host" then
				host_key = 1
			end
			if family_name:sub(1, 12) == "prosody_mod_" then
				sect, name = family_name:match("^prosody_mod_([^/]+)/(.+)$")
			else
				sect, name = family_name:match("^([^_]+)_(.+)$")
			end
			name = clean_fieldname(name)

			local metric_type = metric_family.type_
			if metric_type == "gauge" or metric_type == "unknown" then
				typ = "GAUGE"
			else
				typ = "DCOUNTER"
			end

			for labelset, metric in metric_family:iter_metrics() do
				host = host_key and labelset[host_key] or "global"
				local name_parts = {}
				for i, label in ipairs(labelset) do
					if i ~= host_key then
						t_insert(name_parts, label)
					end
				end
				local full_name = t_concat(name_parts, "_")
				local display_name = #name_parts > 0 and full_name or name
				key = clean_fieldname(s_format("%s_%s_%s", host or "global", sect, name));

				local unit
				local factor = 1
				unit = metric_family.unit
				if unit == "seconds" and typ == "DCOUNTER" then
					factor = 100
					unit = "%time"
				elseif typ == "DCOUNTER" then
					unit = unit .. "/s"
				end

				if not meta:get(key, "") then
					meta:set(key, "", "graph_title", s_format(metric_family.description));
					if unit ~= "" then
						meta:set(key, "", "graph_vlabel", unit);
					end
					meta:set(key, "", "graph_category", sect);
				end
				if not meta:get(key, display_name) then
					meta:set(key, display_name, "label", display_name);
					meta:set(key, display_name, "type", typ)
				end

				for suffix, extra_labels, value in metric:iter_samples() do
					if metric_type == "histogram" or metric_type == "summary" then
						if suffix == "_sum" then
							data:set(key, display_name, value * factor)
						end
					elseif suffix == "_total" or suffix == "" then
						data:set(key, display_name, value * factor)
					end
				end
			end
		end
	end
end

module:hook("openmetrics-updated", openmetrics_handler);

module:provides("net", {
	listener = munin_listener;
	default_mode = "*l";
	default_port = 4949;
});