# HG changeset patch # User Matthew Wild # Date 1603205647 -3600 # Node ID df2ccb42a241862ec80334a90e2779efc7fc800a # Parent d6fb9f7afaa53db9be2334e80f29bc5083cb0d17 mod_log_ringbuffer: Add 'lines' option (actually an alternative ringbuffer implementation) diff -r d6fb9f7afaa5 -r df2ccb42a241 mod_log_ringbuffer/README.markdown --- a/mod_log_ringbuffer/README.markdown Tue Oct 20 15:34:29 2020 +0100 +++ b/mod_log_ringbuffer/README.markdown Tue Oct 20 15:54:07 2020 +0100 @@ -50,6 +50,10 @@ : The size, in bytes, of the buffer. When the buffer fills, old data will be overwritten by new data. +`lines` +: If specified, preserves the latest N complete lines in the + buffer. The `size` option is ignored when this option is set. + `filename` : The name of the file to dump logs to when triggered. diff -r d6fb9f7afaa5 -r df2ccb42a241 mod_log_ringbuffer/mod_log_ringbuffer.lua --- a/mod_log_ringbuffer/mod_log_ringbuffer.lua Tue Oct 20 15:34:29 2020 +0100 +++ b/mod_log_ringbuffer/mod_log_ringbuffer.lua Tue Oct 20 15:54:07 2020 +0100 @@ -4,6 +4,7 @@ local format = require "util.format".format; local pposix = require "util.pposix"; local rb = require "util.ringbuffer"; +local queue = require "util.queue"; local default_timestamp = "%b %d %H:%M:%S "; local max_chunk_size = module:get_option_number("log_ringbuffer_chunk_size", 16384); @@ -22,26 +23,15 @@ local dump_count = 0; -local function dump_buffer(buffer, filename) +local function dump_buffer(dump, filename) dump_count = dump_count + 1; local f, err = io.open(filename, "a+"); if not f then module:log("error", "Unable to open output file: %s", err); return; end - local bytes_remaining = buffer:length(); - f:write(("-- Dumping %d bytes at %s --\n"):format(bytes_remaining, os_date(default_timestamp))); - while bytes_remaining > 0 do - local chunk_size = math.min(bytes_remaining, max_chunk_size); - local chunk = buffer:read(chunk_size); - if not chunk then - f:write("-- Dump aborted due to error --\n\n"); - f:close(); - return; - end - f:write(chunk); - bytes_remaining = bytes_remaining - chunk_size; - end + f:write(("-- Dumping log buffer at %s --\n"):format(os_date(default_timestamp))); + dump(f); f:write("-- End of dump --\n\n"); f:close(); end @@ -56,9 +46,52 @@ }); end +local function new_buffer(config) + local write, dump; + + if config.lines then + local buffer = queue.new(config.lines, true); + function write(line) + buffer:push(line); + end + function dump(f) + -- COMPAT w/0.11 - update to use :consume() + for line in buffer.pop, buffer do + f:write(line); + end + end + else + local buffer_size = config.size or 100*1024; + local buffer = rb.new(buffer_size); + function write(line) + if not buffer:write(line) then + if #line > buffer_size then + buffer:discard(buffer_size); + buffer:write(line:sub(-buffer_size)); + else + buffer:discard(#line); + buffer:write(line); + end + end + end + function dump(f) + local bytes_remaining = buffer:length(); + while bytes_remaining > 0 do + local chunk_size = math.min(bytes_remaining, max_chunk_size); + local chunk = buffer:read(chunk_size); + if not chunk then + return; + end + f:write(chunk); + bytes_remaining = bytes_remaining - chunk_size; + end + end + end + return write, dump; +end + local function ringbuffer_log_sink_maker(sink_config) - local buffer_size = sink_config.size or 100*1024; - local buffer = rb.new(buffer_size); + local write, dump = new_buffer(sink_config); local timestamps = sink_config.timestamps; @@ -68,27 +101,19 @@ timestamps = timestamps .. " "; end - local function dump() - dump_buffer(buffer, sink_config.filename or get_filename(sink_config.filename_template)); + local function handler() + dump_buffer(dump, sink_config.filename or get_filename(sink_config.filename_template)); end if sink_config.signal then - require "util.signal".signal(sink_config.signal, dump); + require "util.signal".signal(sink_config.signal, handler); elseif sink_config.event then - module:hook_global(sink_config.event, dump); + module:hook_global(sink_config.event, handler); end return function (name, level, message, ...) local line = format("%s%s\t%s\t%s\n", timestamps and os_date(timestamps) or "", name, level, format(message, ...)); - if not buffer:write(line) then - if #line > buffer_size then - buffer:discard(buffer_size); - buffer:write(line:sub(-buffer_size)); - else - buffer:discard(#line); - buffer:write(line); - end - end + write(line); end; end