initial commit

This commit is contained in:
Cadey Ratio 2019-12-25 13:32:59 +00:00
commit 11f7f53653
7 changed files with 258 additions and 0 deletions

12
LICENSE Normal file
View File

@ -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.

57
README.md Normal file
View File

@ -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
```

17
lua-ln-scm-1.rockspec Normal file
View File

@ -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 = {}
}

62
spec/ln_spec.lua Normal file
View File

@ -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)

8
src/example.lua Normal file
View File

@ -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" }

99
src/ln.lua Normal file
View File

@ -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,
}

3
test.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
busted --defer-print