comparison mod_log_ringbuffer/mod_log_ringbuffer.lua @ 4226:df2ccb42a241

mod_log_ringbuffer: Add 'lines' option (actually an alternative ringbuffer implementation)
author Matthew Wild <mwild1@gmail.com>
date Tue, 20 Oct 2020 15:54:07 +0100
parents d6fb9f7afaa5
children 133b23758cf6
comparison
equal deleted inserted replaced
4225:d6fb9f7afaa5 4226:df2ccb42a241
2 2
3 local loggingmanager = require "core.loggingmanager"; 3 local loggingmanager = require "core.loggingmanager";
4 local format = require "util.format".format; 4 local format = require "util.format".format;
5 local pposix = require "util.pposix"; 5 local pposix = require "util.pposix";
6 local rb = require "util.ringbuffer"; 6 local rb = require "util.ringbuffer";
7 local queue = require "util.queue";
7 8
8 local default_timestamp = "%b %d %H:%M:%S "; 9 local default_timestamp = "%b %d %H:%M:%S ";
9 local max_chunk_size = module:get_option_number("log_ringbuffer_chunk_size", 16384); 10 local max_chunk_size = module:get_option_number("log_ringbuffer_chunk_size", 16384);
10 11
11 local os_date = os.date; 12 local os_date = os.date;
20 end; 21 end;
21 }); 22 });
22 23
23 local dump_count = 0; 24 local dump_count = 0;
24 25
25 local function dump_buffer(buffer, filename) 26 local function dump_buffer(dump, filename)
26 dump_count = dump_count + 1; 27 dump_count = dump_count + 1;
27 local f, err = io.open(filename, "a+"); 28 local f, err = io.open(filename, "a+");
28 if not f then 29 if not f then
29 module:log("error", "Unable to open output file: %s", err); 30 module:log("error", "Unable to open output file: %s", err);
30 return; 31 return;
31 end 32 end
32 local bytes_remaining = buffer:length(); 33 f:write(("-- Dumping log buffer at %s --\n"):format(os_date(default_timestamp)));
33 f:write(("-- Dumping %d bytes at %s --\n"):format(bytes_remaining, os_date(default_timestamp))); 34 dump(f);
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"); 35 f:write("-- End of dump --\n\n");
46 f:close(); 36 f:close();
47 end 37 end
48 38
49 local function get_filename(filename_template) 39 local function get_filename(filename_template)
54 count = dump_count; 44 count = dump_count;
55 time = os.time(); 45 time = os.time();
56 }); 46 });
57 end 47 end
58 48
49 local function new_buffer(config)
50 local write, dump;
51
52 if config.lines then
53 local buffer = queue.new(config.lines, true);
54 function write(line)
55 buffer:push(line);
56 end
57 function dump(f)
58 -- COMPAT w/0.11 - update to use :consume()
59 for line in buffer.pop, buffer do
60 f:write(line);
61 end
62 end
63 else
64 local buffer_size = config.size or 100*1024;
65 local buffer = rb.new(buffer_size);
66 function write(line)
67 if not buffer:write(line) then
68 if #line > buffer_size then
69 buffer:discard(buffer_size);
70 buffer:write(line:sub(-buffer_size));
71 else
72 buffer:discard(#line);
73 buffer:write(line);
74 end
75 end
76 end
77 function dump(f)
78 local bytes_remaining = buffer:length();
79 while bytes_remaining > 0 do
80 local chunk_size = math.min(bytes_remaining, max_chunk_size);
81 local chunk = buffer:read(chunk_size);
82 if not chunk then
83 return;
84 end
85 f:write(chunk);
86 bytes_remaining = bytes_remaining - chunk_size;
87 end
88 end
89 end
90 return write, dump;
91 end
92
59 local function ringbuffer_log_sink_maker(sink_config) 93 local function ringbuffer_log_sink_maker(sink_config)
60 local buffer_size = sink_config.size or 100*1024; 94 local write, dump = new_buffer(sink_config);
61 local buffer = rb.new(buffer_size);
62 95
63 local timestamps = sink_config.timestamps; 96 local timestamps = sink_config.timestamps;
64 97
65 if timestamps == true or timestamps == nil then 98 if timestamps == true or timestamps == nil then
66 timestamps = default_timestamp; -- Default format 99 timestamps = default_timestamp; -- Default format
67 elseif timestamps then 100 elseif timestamps then
68 timestamps = timestamps .. " "; 101 timestamps = timestamps .. " ";
69 end 102 end
70 103
71 local function dump() 104 local function handler()
72 dump_buffer(buffer, sink_config.filename or get_filename(sink_config.filename_template)); 105 dump_buffer(dump, sink_config.filename or get_filename(sink_config.filename_template));
73 end 106 end
74 107
75 if sink_config.signal then 108 if sink_config.signal then
76 require "util.signal".signal(sink_config.signal, dump); 109 require "util.signal".signal(sink_config.signal, handler);
77 elseif sink_config.event then 110 elseif sink_config.event then
78 module:hook_global(sink_config.event, dump); 111 module:hook_global(sink_config.event, handler);
79 end 112 end
80 113
81 return function (name, level, message, ...) 114 return function (name, level, message, ...)
82 local line = format("%s%s\t%s\t%s\n", timestamps and os_date(timestamps) or "", name, level, format(message, ...)); 115 local line = format("%s%s\t%s\t%s\n", timestamps and os_date(timestamps) or "", name, level, format(message, ...));
83 if not buffer:write(line) then 116 write(line);
84 if #line > buffer_size then
85 buffer:discard(buffer_size);
86 buffer:write(line:sub(-buffer_size));
87 else
88 buffer:discard(#line);
89 buffer:write(line);
90 end
91 end
92 end; 117 end;
93 end 118 end
94 119
95 loggingmanager.register_sink_type("ringbuffer", ringbuffer_log_sink_maker); 120 loggingmanager.register_sink_type("ringbuffer", ringbuffer_log_sink_maker);