Skip to content

Commit

Permalink
Add. Protected formatter.
Browse files Browse the repository at this point in the history
  • Loading branch information
moteus committed Sep 5, 2016
1 parent ac68990 commit 17963c9
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 0 deletions.
91 changes: 91 additions & 0 deletions lua/log/formatter/pformat.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
local lpeg = require "lpeg"
local table = require "table"
local string = require "string"

local unpack = unpack or table.unpack

local HAS_A_FORMAT = pcall(string.format, '%a' , 10)

local P, C, Cs, Ct, Cp, S, R = lpeg.P, lpeg.C, lpeg.Cs, lpeg.Ct, lpeg.Cp, lpeg.S, lpeg.R

local any = P(1)
local empty = P(0)

local esc = P'%%'
local flags = S'-+ #0'
local digit = R'09'

local fsym = S('cdiouxXeEfgGqs' .. (HAS_A_FORMAT and 'aA' or ''))
local width = digit * digit + digit
local precision = P'.' * (digit * digit + digit)
local format = (flags + empty) * (width + empty) * (precision + empty) * (P'.' + empty)
local valid_format = P'%' * format * fsym
local valid_format_capture = Cs(valid_format)

local any_fsym = any - (flags + digit + P'.')
local any_format = P'%' * (flags + digit + P'.')^0 * any_fsym

local types = {
c = 'number';
d = 'number';
i = 'number';
o = 'number';
u = 'number';
x = 'number';
X = 'number';
a = 'number';
A = 'number';
e = 'number';
E = 'number';
f = 'number';
g = 'number';
G = 'number';
q = 'string';
s = 'string';
}

local function safe_format(protect_only_args, fmt, ...)
local n, args = 0, {...}

local function fix_fmt(f)
local fmt = valid_format_capture:match(f)

if not fmt then
if protect_only_args then return end
return '%' .. f
end

local typ = string.sub(fmt, -1)

n = n + 1

if types[typ] ~= type( args[n] ) then
args[n], fmt = tostring(args[n]), '%s'
end

return fmt
end

local pattern = Cs((esc + any_format / fix_fmt + any) ^ 0)
fmt = pattern:match(fmt)

return string.format(fmt, unpack(args, 1, n))
end

local function buld_formatter(protect_only_args, no_warning)
return function(...)
local ok, msg = pcall(string.format, ...)
if not ok then
local err = msg
msg = safe_format(protect_only_args, ...)
if not no_warning then
msg = msg .. ' - ' .. 'WARNING: Error formatting log message: ' .. err
end
end
return msg
end
end

return {
new = buld_formatter
}
2 changes: 2 additions & 0 deletions rockspecs/lua-log-scm-0.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ description = {
dependencies = {
"lua >= 5.1",
"date >= 2.0",
-- "lpeg >= 0.10.0",
-- "llthread >= 1.2",
-- "luasocket >= 2.0.1",
-- "lzmq >= 0.4.2",
Expand All @@ -35,6 +36,7 @@ build = {
["log.formatter.concat" ] = "lua/log/formatter/concat.lua",
["log.formatter.default" ] = "lua/log/formatter/default.lua",
["log.formatter.format" ] = "lua/log/formatter/format.lua",
["log.formatter.pformat" ] = "lua/log/formatter/pformat.lua",
["log.formatter.mix" ] = "lua/log/formatter/mix.lua",
["log.logformat.default" ] = "lua/log/logformat/default.lua",
["log.logformat.proxy" ] = "lua/log/logformat/proxy.lua",
Expand Down
71 changes: 71 additions & 0 deletions test/test_basic.lua
Original file line number Diff line number Diff line change
Expand Up @@ -268,4 +268,75 @@ end

end

local _ENV = TEST_CASE'protected formatter' do

function test_do_not_raise_error_nil_argument()
local formatter = require "log.formatter.pformat".new()

local msg
assert_pass(function() msg = formatter("%s", nil) end)
assert_string(msg)

local expected = tostring(nil)
assert_equal(expected, string.sub(msg,1, #expected))

assert_match('Error formatting log message', msg)
end

function test_do_not_raise_error_unknown_format()
local formatter = require "log.formatter.pformat".new()

local msg
assert_pass(function() msg = formatter("%t", 10) end)
assert_string(msg)

local expected = "%t"
assert_equal(expected, string.sub(msg,1, #expected))

assert_match('Error formatting log message', msg)
end

function test_do_not_raise_error_and_no_warning_nil_argument()
local formatter = require "log.formatter.pformat".new(nil, true)

local msg
assert_pass(function() msg = formatter("%t", nil) end)
assert_string(msg)

local expected = '%t'
assert_equal(expected, msg)
end

function test_do_not_raise_error_and_no_warning_unknown_format()
local formatter = require "log.formatter.pformat".new(nil, true)

local msg
assert_pass(function() msg = formatter("%t", 10) end)
assert_string(msg)

local expected = '%t'
assert_equal(expected, msg)
end

function test_do_not_raise_error_nil_argument_2()
local formatter = require "log.formatter.pformat".new(true)

local msg
assert_pass(function() msg = formatter("%s", nil) end)
assert_string(msg)

local expected = tostring(nil)
assert_equal(expected, string.sub(msg,1, #expected))

assert_match('Error formatting log message', msg)
end

function test_raise_error_unknown_format()
local formatter = require "log.formatter.pformat".new(true)

local msg = assert_error(function() msg = formatter("%t", 10) end)
end

end

if not HAS_RUNNER then lunit.run() end

0 comments on commit 17963c9

Please sign in to comment.