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