initial commit
This commit is contained in:
commit
11f7f53653
|
@ -0,0 +1,12 @@
|
|||
Copyright (c) 2019 Christine Dodrill <me@christine.website>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
|
@ -0,0 +1,57 @@
|
|||
# ln: The Natural Logger for Lua
|
||||
|
||||
This is a clone of [ln](https://github.com/Xe/ln) for Lua. ln works by using
|
||||
key->value pairs to create structured logging output. By default, this outputs
|
||||
logs formatted similar to [logfmt][logfmt].
|
||||
|
||||
[logfmt]: https://www.brandur.org/logfmt
|
||||
|
||||
Example:
|
||||
|
||||
```lua
|
||||
local ln = require "ln"
|
||||
|
||||
ln.log {foo = "bar"}
|
||||
-- time="2019-12-25T13:24:00" foo=bar
|
||||
```
|
||||
|
||||
It also supports multiple tables:
|
||||
|
||||
```lua
|
||||
local ln = require "ln"
|
||||
|
||||
ln.log({foo = "bar"}, {needs_space = "a string value with spaces"})
|
||||
-- time="2019-12-25T13:24:00" foo=bar needs_space="a string value with spaces"
|
||||
```
|
||||
|
||||
And logging errors:
|
||||
|
||||
```lua
|
||||
local ln = require "ln"
|
||||
|
||||
local result, err = thing_that_could_fail()
|
||||
if err ~= nil then
|
||||
ln.err(err, {tried = "thing_that_could_fail()"})
|
||||
end
|
||||
-- time="2019-12-25T13:27:32" err="vibe check failed" tried=thing_that_could_fail()
|
||||
```
|
||||
|
||||
And outputting logs as JSON:
|
||||
|
||||
```
|
||||
local ln = require "ln"
|
||||
|
||||
ln.default_logger.formatter = ln.JSONFormatter:new()
|
||||
ln.log {foo = "bar"}
|
||||
-- {"foo":"bar","time":"2019-12-25T13:27:32"}
|
||||
```
|
||||
|
||||
Or creating your own logger instance:
|
||||
|
||||
```lua
|
||||
local ln = require "ln"
|
||||
|
||||
local lgr = ln.Logger:new()
|
||||
lgr:log {foo = "bar"}
|
||||
-- time="2019-12-25T13:27:32" foo=bar
|
||||
```
|
|
@ -0,0 +1,17 @@
|
|||
package = "ln"
|
||||
version = "scm-1"
|
||||
source = {
|
||||
url = "git+ssh://ssh.tulpa.dev/cadey/lua-ln"
|
||||
}
|
||||
description = {
|
||||
homepage = "https://tulpa.dev/cadey/lua-ln",
|
||||
license = "0bsd"
|
||||
}
|
||||
dependencies = {
|
||||
"lua ~> 5.3",
|
||||
"dkjson"
|
||||
}
|
||||
build = {
|
||||
type = "builtin",
|
||||
modules = {}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
local ln = require "ln"
|
||||
|
||||
describe("ln", function()
|
||||
describe("exports", function()
|
||||
it("has Logger", function()
|
||||
assert.truthy(ln.Logger)
|
||||
end)
|
||||
|
||||
it("has default_logger", function()
|
||||
assert.truthy(ln.default_logger)
|
||||
end)
|
||||
|
||||
it("has LogfmtFormatter", function()
|
||||
assert.truthy(ln.LogfmtFormatter)
|
||||
end)
|
||||
|
||||
it("has JSONFormatter", function()
|
||||
assert.truthy(ln.JSONFormatter)
|
||||
end)
|
||||
|
||||
it("has log", function()
|
||||
assert.truthy(ln.log)
|
||||
end)
|
||||
|
||||
it("has err", function()
|
||||
assert.truthy(ln.err)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("default logger operations", function()
|
||||
local lgr = ln.default_logger
|
||||
it("can log", function()
|
||||
lgr:log {foo = "bar"}
|
||||
end)
|
||||
|
||||
it("can error", function()
|
||||
lgr:err("vibe check failed", {foo = "bar"})
|
||||
end)
|
||||
|
||||
it("takes multiple tables", function()
|
||||
lgr:log({foo = "bar"}, {baz = "boz"})
|
||||
end)
|
||||
|
||||
it("lets you override the formatter", function()
|
||||
lgr.formatter = ln.JSONFormatter:new()
|
||||
lgr:log {foo = "bar"}
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("logfmt", function()
|
||||
local fmtr = ln.LogfmtFormatter:new()
|
||||
|
||||
it("should return a non-nil message", function()
|
||||
assert.truthy(fmtr:format({foo = "bar"}))
|
||||
end)
|
||||
|
||||
it("should have spaces when the input does", function()
|
||||
local msg = fmtr:format {foo = "bar with spaces"}
|
||||
assert.truthy(string.find(msg, 'foo="bar with spaces"'))
|
||||
end)
|
||||
end)
|
||||
end)
|
|
@ -0,0 +1,8 @@
|
|||
local ln = require "ln"
|
||||
local lgr = ln.default_logger
|
||||
|
||||
lgr:log { foo = "bar", needs_space = "a string value with spaces" }
|
||||
lgr:err("foo bar", {foo = "bar"})
|
||||
|
||||
local jlgr = ln.Logger:new(ln.JSONFormatter:new())
|
||||
jlgr:log { foo = "bar", big = "scary space value" }
|
|
@ -0,0 +1,99 @@
|
|||
local json = require "dkjson"
|
||||
|
||||
local function time()
|
||||
return os.date "%Y-%m-%dT%H:%M:%S"
|
||||
end
|
||||
|
||||
local function quote(value)
|
||||
if string.find(value, " ") then
|
||||
return string.format("%q", value)
|
||||
end
|
||||
|
||||
return value
|
||||
end
|
||||
|
||||
local LogfmtFormatter = {}
|
||||
|
||||
function LogfmtFormatter:format(tbl)
|
||||
local message = "time=\"" .. time() .. "\" "
|
||||
for k, v in pairs(tbl) do
|
||||
message = message .. k .. "=" .. quote(v) .. " "
|
||||
end
|
||||
|
||||
return message
|
||||
end
|
||||
|
||||
function LogfmtFormatter:new()
|
||||
local o = {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end
|
||||
|
||||
local JSONFormatter = {}
|
||||
|
||||
function JSONFormatter:format(tbl)
|
||||
tbl["time"] = time()
|
||||
|
||||
return json.encode(tbl)
|
||||
end
|
||||
|
||||
function JSONFormatter:new()
|
||||
local o = {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end
|
||||
|
||||
local Logger = {}
|
||||
|
||||
function Logger:err(err, ...)
|
||||
self:log({err = err}, ...)
|
||||
end
|
||||
|
||||
function Logger:log(...)
|
||||
local result = {}
|
||||
local args = table.pack(...)
|
||||
|
||||
for i=1, args.n do
|
||||
if type(args[i]) == "table" then
|
||||
for k, v in pairs(args[i]) do
|
||||
result[tostring(k)] = tostring(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
message = self.formatter:format(result)
|
||||
|
||||
print(message)
|
||||
end
|
||||
|
||||
function Logger:new(formatter)
|
||||
if formatter == nil then
|
||||
formatter = LogfmtFormatter:new()
|
||||
end
|
||||
local o = {
|
||||
formatter = formatter,
|
||||
}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end
|
||||
|
||||
local default_logger = Logger:new()
|
||||
local function log(...)
|
||||
default_logger:log(...)
|
||||
end
|
||||
|
||||
local function err(why, ...)
|
||||
default_logger:err(why, ...)
|
||||
end
|
||||
|
||||
return {
|
||||
default_logger = default_logger,
|
||||
Logger = Logger,
|
||||
LogfmtFormatter = LogfmtFormatter,
|
||||
JSONFormatter = JSONFormatter,
|
||||
log = log,
|
||||
err = err,
|
||||
}
|
Loading…
Reference in New Issue