Mercurial > 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 |
parents | |
children | 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); |