Software / code / prosody-modules
Comparison
mod_log_ringbuffer/mod_log_ringbuffer.lua @ 4205:481c4d75e77d
mod_log_ringbuffer: New module to send logs to an in-memory ringbuffer
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Thu, 15 Oct 2020 16:47:21 +0100 |
| child | 4215:86f8ece24029 |
comparison
equal
deleted
inserted
replaced
| 4204:a5930a185806 | 4205:481c4d75e77d |
|---|---|
| 1 module:set_global(); | |
| 2 | |
| 3 local loggingmanager = require "core.loggingmanager"; | |
| 4 local format = require "util.format".format; | |
| 5 local pposix = require "util.pposix"; | |
| 6 local rb = require "util.ringbuffer"; | |
| 7 | |
| 8 local default_timestamp = "%b %d %H:%M:%S "; | |
| 9 local max_chunk_size = module:get_option_number("log_ringbuffer_chunk_size", 16384); | |
| 10 | |
| 11 local os_date = os.date; | |
| 12 | |
| 13 local default_filename_template = "ringbuffer-logs-{pid}-{count}.log"; | |
| 14 local render_filename = require "util.interpolation".new("%b{}", function (s) return s; end, { | |
| 15 yyyymmdd = function (t) | |
| 16 return os_date("%Y%m%d", t); | |
| 17 end; | |
| 18 hhmmss = function (t) | |
| 19 return os_date("%H%M%S", t); | |
| 20 end; | |
| 21 }); | |
| 22 | |
| 23 local dump_count = 0; | |
| 24 | |
| 25 local function dump_buffer(buffer, filename) | |
| 26 dump_count = dump_count + 1; | |
| 27 local f, err = io.open(filename, "a+"); | |
| 28 if not f then | |
| 29 module:log("error", "Unable to open output file: %s", err); | |
| 30 return; | |
| 31 end | |
| 32 local bytes_remaining = buffer:length(); | |
| 33 f:write(("-- Dumping %d bytes at %s --\n"):format(bytes_remaining, os_date(default_timestamp))); | |
| 34 while bytes_remaining > 0 do | |
| 35 local chunk_size = math.min(bytes_remaining, max_chunk_size); | |
| 36 local chunk = buffer:read(chunk_size); | |
| 37 if not chunk then | |
| 38 f:write("-- Dump aborted due to error --\n\n"); | |
| 39 f:close(); | |
| 40 return; | |
| 41 end | |
| 42 f:write(chunk); | |
| 43 bytes_remaining = bytes_remaining - chunk_size; | |
| 44 end | |
| 45 f:write("-- End of dump --\n\n"); | |
| 46 f:close(); | |
| 47 end | |
| 48 | |
| 49 local function get_filename(filename_template) | |
| 50 filename_template = filename_template or default_filename_template; | |
| 51 return render_filename(filename_template, { | |
| 52 paths = prosody.paths; | |
| 53 pid = pposix.getpid(); | |
| 54 count = dump_count; | |
| 55 time = os.time(); | |
| 56 }); | |
| 57 end | |
| 58 | |
| 59 local function ringbuffer_log_sink_maker(sink_config) | |
| 60 local buffer = rb.new(sink_config.size or 100*1024); | |
| 61 | |
| 62 local timestamps = sink_config.timestamps; | |
| 63 | |
| 64 if timestamps == true or timestamps == nil then | |
| 65 timestamps = default_timestamp; -- Default format | |
| 66 elseif timestamps then | |
| 67 timestamps = timestamps .. " "; | |
| 68 end | |
| 69 | |
| 70 local function dump() | |
| 71 dump_buffer(buffer, get_filename(sink_config.filename)); | |
| 72 end | |
| 73 | |
| 74 if sink_config.signal then | |
| 75 require "util.signal".signal(sink_config.signal, dump); | |
| 76 elseif sink_config.event then | |
| 77 module:hook_global(sink_config.global_event, dump); | |
| 78 end | |
| 79 | |
| 80 return function (name, level, message, ...) | |
| 81 buffer:write(format("%s%s\t%s\t%s\n", timestamps and os_date(timestamps) or "", name, level, format(message, ...))); | |
| 82 end; | |
| 83 end | |
| 84 | |
| 85 loggingmanager.register_sink_type("ringbuffer", ringbuffer_log_sink_maker); |