# HG changeset patch # User Matthew Wild # Date 1637921402 0 # Node ID b86282953663b102208c3124a14ebc55f2ca12e7 # Parent bb66e87a36042c460b1fe00ecd345ee630d16ea9 mod_s2s_status: Module to track status of s2s connections by domain diff -r bb66e87a3604 -r b86282953663 mod_s2s_status/README.markdown --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_s2s_status/README.markdown Fri Nov 26 10:10:02 2021 +0000 @@ -0,0 +1,42 @@ +--- +labels: +- 'Stage-Alpha' +summary: 'Track the status and health of s2s connections' +... + +Introduction +============ + +Prosody already gives some insight into current s2s connections, e.g. via +the `s2s:show()` command in the console. This will tell you about all current +s2s connections. + +However sometimes this is not enough. For example if an s2s connection fails +to establish, it won't show up - you have to go digging through the log file +looking for the errors instead. + +This module maintains a record of recent connection attempts to a remote +domain. You can use this module to answer questions such as: + +- Why did the last connection attempt to `example.com` fail? +- When did I last have a successful connection with `example.com`? +- Are my s2s connections generally stable? + +**Note:** At the time of writing, this module is not yet finished, and should +be considered a proof-of-concept. + +# Configuration + +Just load the module as normal: + +``` {.lua} +modules_enabled = { + ... + "s2s_status"; + ... +} +``` + +# Compatibility + +trunk (0.12) and later, e.g. due to [60676b607b6d](https://hg.prosody.im/trunk/rev/60676b607b6d). diff -r bb66e87a3604 -r b86282953663 mod_s2s_status/mod_s2s_status.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_s2s_status/mod_s2s_status.lua Fri Nov 26 10:10:02 2021 +0000 @@ -0,0 +1,90 @@ +local status_out = module:shared("out"); + +local errors = require "util.error"; + +local function get_session_info(session) + local direction, peer_host = session.direction; + if direction == "outgoing" then + peer_host = session.to_host; + elseif direction == "incoming" then + peer_host = session.from_host; + end + return peer_host, direction, session.id; +end + +local function get_domain_log_out(peer_domain) + local domain_log = status_out[peer_domain]; + if not domain_log then + domain_log = {}; + status_out[peer_domain] = domain_log; + end +end + +local function get_connection_record(domain_log, id) + for _, record in ipairs(domain_log) do + if record.id == id then + return record; + end + end + -- No record for this connection yet, create it + local record = { id = id }; + table.insert(domain_log, 1, record); + return record; +end + +local function log_new_connection_out(peer_domain, id) + local domain_log = get_domain_log_out(peer_domain); + local record = get_connection_record(domain_log, id); + record.status, record.time_started = "connecting", os.time(); +end + +local function log_successful_connection_out(peer_domain, id) + local domain_log = get_domain_log_out(peer_domain); + local record = get_connection_record(domain_log, id); + record.status, record.time_connected = "connected", os.time(); +end + +local function log_ended_connection_out(peer_domain, id, reason) + local domain_log = get_domain_log_out(peer_domain); + local record = get_connection_record(domain_log, id); + + if record.status == "connecting" then + record.status = "failed"; + elseif record.status == "connected" then + record.status = "disconnected"; + end + if reason then + local e_reason = errors.new(reason); + record.error = { + type = e_reason.type; + condition = e_reason.condition; + text = e_reason.text; + }; + if not record.error.text and type(reason) == "string" then + record.error.text = reason; + end + end + local now = os.time(); + record.time_ended = now; +end + +local function s2sout_established(event) + local peer_domain, _, id = get_session_info(event.session); + log_successful_connection_out(peer_domain, id); +end + +local function s2sout_destroyed(event) + local peer_domain, _, id = get_session_info(event.session); + log_ended_connection_out(peer_domain, id); +end + +local function s2s_created(event) + local peer_domain, direction, id = get_session_info(event.session); + if direction == "outgoing" then + log_new_connection_out(peer_domain, id); + end +end + +module:hook("s2s-created", s2s_created); +module:hook("s2sout-established", s2sout_established); +module:hook("s2sout-destroyed", s2sout_destroyed);