# HG changeset patch # User Matthew Wild # Date 1602854590 -3600 # Node ID 5841d54cb6c643839200d94ec5b45b0a098a4300 # Parent 93a980ac181607b30d57564f6d8d7d16d3c307ab mod_debug_traceback: Descendent of mod_traceback with some additional features diff -r 93a980ac1816 -r 5841d54cb6c6 mod_debug_traceback/README.markdown --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_debug_traceback/README.markdown Fri Oct 16 14:23:10 2020 +0100 @@ -0,0 +1,25 @@ +--- +labels: +- 'Stage-Alpha' +summary: Generate tracebacks on-demand +--- + +# Introduction + +This module writes out a traceback to a file when a chosen signal (by default +`SIGUSR1`) is received. It can be useful to diagnose cases where Prosody is +unresponsive. + +# Configuration + +`debug_traceback_filename` +: The name of the file to write the traceback to. Some variables + are supported, see [mod_log_ringbuffer] docs for more info. Defaults + to `{paths.data}/traceback-{pid}-{count}.log`. + +`debug_traceback_signal` +: The name of the signal to listen for. Defaults to `SIGUSR1`. + +# Compatibility + +Prosody 0.11 or later. diff -r 93a980ac1816 -r 5841d54cb6c6 mod_debug_traceback/mod_debug_traceback.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_debug_traceback/mod_debug_traceback.lua Fri Oct 16 14:23:10 2020 +0100 @@ -0,0 +1,54 @@ +module:set_global(); + +local traceback = require "util.debug".traceback; +local pposix = require "util.pposix"; +local os_date = os.date; +local render_filename = require "util.interpolation".new("%b{}", function (s) return s; end, { + yyyymmdd = function (t) + return os_date("%Y%m%d", t); + end; + hhmmss = function (t) + return os_date("%H%M%S", t); + end; +}); + +local count = 0; + +local function get_filename(filename_template) + filename_template = filename_template; + return render_filename(filename_template, { + paths = prosody.paths; + pid = pposix.getpid(); + count = count; + time = os.time(); + }); +end + +local default_filename_template = "{paths.data}/traceback-{pid}-{count}.log"; +local filename_template = module:get_option_string("debug_traceback_filename", default_filename_template); +local signal_name = module:get_option_string("debug_traceback_signal", "SIGUSR1"); + +function dump_traceback() + module:log("info", "Received %s, writing traceback", signal_name); + + local tb = traceback(); + module:fire_event("debug_traceback/triggered", { traceback = tb }); + + local f, err = io.open(get_filename(filename_template), "a+"); + if not f then + module:log("error", "Unable to write traceback: %s", err); + return; + end + f:write("-- Traceback generated at ", os.date("%b %d %H:%M:%S"), " --\n"); + f:write(traceback(), "\n"); + f:write("-- End of traceback --\n"); + f:close(); + count = count + 1; +end + +local mod_posix = module:depends("posix"); +if mod_posix.features and mod_posix.features.signal_events then + module:hook("signal/"..signal_name, dump_traceback); +else + require"util.signal".signal(signal_name, dump_traceback); +end