✨ feat(服务): 新增日志服务
parent
fbe6800cb0
commit
a5502e8aef
@ -0,0 +1,83 @@
|
|||||||
|
local skynet = require "skynet"
|
||||||
|
local coroutine = coroutine
|
||||||
|
local xpcall = xpcall
|
||||||
|
local traceback = debug.traceback
|
||||||
|
|
||||||
|
--- Parent queue, and where lock the parent
|
||||||
|
function skynet.lockable_queue(parent_queue, parent_lock)
|
||||||
|
local current_thread = nil
|
||||||
|
local ref = 0
|
||||||
|
local thread_queue = {}
|
||||||
|
local parent_queue = parent_queue
|
||||||
|
local parent_lock = parent_lock
|
||||||
|
local locked_by = nil
|
||||||
|
|
||||||
|
local function xpcall_ret(ok, ...)
|
||||||
|
ref = ref - 1
|
||||||
|
if ref == 0 then
|
||||||
|
if locked_by == current_thread then
|
||||||
|
locked_by = nil
|
||||||
|
end
|
||||||
|
current_thread = table.remove(thread_queue, 1)
|
||||||
|
if current_thread then
|
||||||
|
skynet.wakeup(current_thread)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not ok then
|
||||||
|
return nil, ...
|
||||||
|
end
|
||||||
|
-- assert(ok, (...))
|
||||||
|
return ...
|
||||||
|
end
|
||||||
|
|
||||||
|
local lockable_queue = function(f, lock, ...)
|
||||||
|
local thread = coroutine.running()
|
||||||
|
--- If queue is locked and current thread is not the running one
|
||||||
|
if locked_by and current_thread ~= thread then
|
||||||
|
return nil, "Queue is locked"
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set the locked flag even current task is not running for avoid any new task comming
|
||||||
|
if lock then
|
||||||
|
locked_by = thread
|
||||||
|
end
|
||||||
|
|
||||||
|
--- If not in recursive lock, and current is running, wait for previous one finished
|
||||||
|
if current_thread and current_thread ~= thread then
|
||||||
|
table.insert(thread_queue, thread)
|
||||||
|
skynet.wait()
|
||||||
|
assert(ref == 0) -- current_thread == thread
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set the current running thread
|
||||||
|
current_thread = thread
|
||||||
|
|
||||||
|
--- Increase the ref
|
||||||
|
ref = ref + 1
|
||||||
|
|
||||||
|
--- Execute the function
|
||||||
|
return xpcall_ret(xpcall(f, traceback, ...))
|
||||||
|
end
|
||||||
|
|
||||||
|
if parent_queue then
|
||||||
|
return function(f, lock, ...)
|
||||||
|
return parent_queue(lockable_queue, parent_lock, f, lock, ...)
|
||||||
|
--[[
|
||||||
|
return parent_queue(function(...)
|
||||||
|
return lockable_queue(f, lock, ...)
|
||||||
|
end, parent_lock, ...)
|
||||||
|
]] --
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return lockable_queue
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Lockable queue
|
||||||
|
-- @tparam function f The function to execute in this queue
|
||||||
|
-- @tparam boolean lock Lock current queue until current task exeucted completely or task cloud be queued for execution
|
||||||
|
-- @param ...
|
||||||
|
-- @return false if queue is lock, or the first value from your function f
|
||||||
|
-- @returns
|
||||||
|
return skynet.lockable_queue
|
||||||
@ -1,16 +0,0 @@
|
|||||||
local M = {}
|
|
||||||
|
|
||||||
function M.new(sep)
|
|
||||||
sep = sep or ' '
|
|
||||||
|
|
||||||
return function(...)
|
|
||||||
local argc, argv = select('#', ...), {...}
|
|
||||||
for i = 1, argc do
|
|
||||||
argv[i] = tostring(argv[i])
|
|
||||||
end
|
|
||||||
return (table.concat(argv, sep))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
local M = {}
|
|
||||||
|
|
||||||
function M.new()
|
|
||||||
return function(msg)
|
|
||||||
return msg
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
local string = require "string"
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
function M.new()
|
|
||||||
return string.format
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
---
|
|
||||||
-- compatiable with lualogging
|
|
||||||
--
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
function M.new(default)
|
|
||||||
if not default then
|
|
||||||
default = require"log.formatter.format".new()
|
|
||||||
end
|
|
||||||
|
|
||||||
return function(...)
|
|
||||||
if type((...)) == 'function' then
|
|
||||||
return (...)(select(2, ...))
|
|
||||||
end
|
|
||||||
|
|
||||||
if select('#', ...) < 2 then
|
|
||||||
return tostring((...))
|
|
||||||
end
|
|
||||||
|
|
||||||
return default(...)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,93 +0,0 @@
|
|||||||
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,
|
|
||||||
}
|
|
||||||
@ -1,377 +0,0 @@
|
|||||||
local inspect = {
|
|
||||||
_VERSION = "inspect.lua 3.1.0",
|
|
||||||
_URL = "http://github.com/kikito/inspect.lua",
|
|
||||||
_DESCRIPTION = "human-readable representations of tables",
|
|
||||||
_LICENSE = [[
|
|
||||||
MIT LICENSE
|
|
||||||
|
|
||||||
Copyright (c) 2013 Enrique García Cota
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included
|
|
||||||
in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
||||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
||||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
||||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
]],
|
|
||||||
}
|
|
||||||
|
|
||||||
local tostring = tostring
|
|
||||||
local setmetatable = setmetatable
|
|
||||||
local next = next
|
|
||||||
local type = type
|
|
||||||
local rawget = rawget
|
|
||||||
local getmetatable = getmetatable
|
|
||||||
|
|
||||||
inspect.KEY = setmetatable({}, {
|
|
||||||
__tostring = function()
|
|
||||||
return "inspect.KEY"
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
inspect.METATABLE = setmetatable({}, {
|
|
||||||
__tostring = function()
|
|
||||||
return "inspect.METATABLE"
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
|
|
||||||
local function rawpairs(t)
|
|
||||||
return next, t, nil
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Apostrophizes the string if it has quotes, but not aphostrophes
|
|
||||||
-- Otherwise, it returns a regular quoted string
|
|
||||||
local function smartQuote(str)
|
|
||||||
if str:match('"') and not str:match("'") then
|
|
||||||
return "'" .. str .. "'"
|
|
||||||
end
|
|
||||||
return '"' .. str:gsub('"', '\\"') .. '"'
|
|
||||||
end
|
|
||||||
|
|
||||||
-- \a => '\\a', \0 => '\\0', 31 => '\31'
|
|
||||||
local shortControlCharEscapes = {
|
|
||||||
["\a"] = "\\a",
|
|
||||||
["\b"] = "\\b",
|
|
||||||
["\f"] = "\\f",
|
|
||||||
["\n"] = "\\n",
|
|
||||||
["\r"] = "\\r",
|
|
||||||
["\t"] = "\\t",
|
|
||||||
["\v"] = "\\v",
|
|
||||||
}
|
|
||||||
local longControlCharEscapes = {} -- \a => nil, \0 => \000, 31 => \031
|
|
||||||
for i = 0, 31 do
|
|
||||||
local ch = string.char(i)
|
|
||||||
if not shortControlCharEscapes[ch] then
|
|
||||||
shortControlCharEscapes[ch] = "\\" .. i
|
|
||||||
longControlCharEscapes[ch] = string.format("\\%03d", i)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function escape(str)
|
|
||||||
return (str:gsub("\\", "\\\\"):gsub("(%c)%f[0-9]", longControlCharEscapes):gsub("%c", shortControlCharEscapes))
|
|
||||||
end
|
|
||||||
|
|
||||||
local function isIdentifier(str)
|
|
||||||
return type(str) == "string" and str:match("^[_%a][_%a%d]*$")
|
|
||||||
end
|
|
||||||
|
|
||||||
local function isSequenceKey(k, sequenceLength)
|
|
||||||
return type(k) == "number" and 1 <= k and k <= sequenceLength and math.floor(k) == k
|
|
||||||
end
|
|
||||||
|
|
||||||
local defaultTypeOrders = {
|
|
||||||
["number"] = 1,
|
|
||||||
["boolean"] = 2,
|
|
||||||
["string"] = 3,
|
|
||||||
["table"] = 4,
|
|
||||||
["function"] = 5,
|
|
||||||
["userdata"] = 6,
|
|
||||||
["thread"] = 7,
|
|
||||||
}
|
|
||||||
|
|
||||||
local function sortKeys(a, b)
|
|
||||||
local ta, tb = type(a), type(b)
|
|
||||||
|
|
||||||
-- strings and numbers are sorted numerically/alphabetically
|
|
||||||
if ta == tb and (ta == "string" or ta == "number") then
|
|
||||||
return a < b
|
|
||||||
end
|
|
||||||
|
|
||||||
local dta, dtb = defaultTypeOrders[ta], defaultTypeOrders[tb]
|
|
||||||
-- Two default types are compared according to the defaultTypeOrders table
|
|
||||||
if dta and dtb then
|
|
||||||
return defaultTypeOrders[ta] < defaultTypeOrders[tb]
|
|
||||||
elseif dta then
|
|
||||||
return true -- default types before custom ones
|
|
||||||
elseif dtb then
|
|
||||||
return false -- custom types after default ones
|
|
||||||
end
|
|
||||||
|
|
||||||
-- custom types are sorted out alphabetically
|
|
||||||
return ta < tb
|
|
||||||
end
|
|
||||||
|
|
||||||
-- For implementation reasons, the behavior of rawlen & # is "undefined" when
|
|
||||||
-- tables aren't pure sequences. So we implement our own # operator.
|
|
||||||
local function getSequenceLength(t)
|
|
||||||
local len = 1
|
|
||||||
local v = rawget(t, len)
|
|
||||||
while v ~= nil do
|
|
||||||
len = len + 1
|
|
||||||
v = rawget(t, len)
|
|
||||||
end
|
|
||||||
return len - 1
|
|
||||||
end
|
|
||||||
|
|
||||||
local function getNonSequentialKeys(t)
|
|
||||||
local keys, keysLength = {}, 0
|
|
||||||
local sequenceLength = getSequenceLength(t)
|
|
||||||
for k, _ in rawpairs(t) do
|
|
||||||
if not isSequenceKey(k, sequenceLength) then
|
|
||||||
keysLength = keysLength + 1
|
|
||||||
keys[keysLength] = k
|
|
||||||
end
|
|
||||||
end
|
|
||||||
table.sort(keys, sortKeys)
|
|
||||||
return keys, keysLength, sequenceLength
|
|
||||||
end
|
|
||||||
|
|
||||||
local function countTableAppearances(t, tableAppearances)
|
|
||||||
tableAppearances = tableAppearances or {}
|
|
||||||
|
|
||||||
if type(t) == "table" then
|
|
||||||
if not tableAppearances[t] then
|
|
||||||
tableAppearances[t] = 1
|
|
||||||
for k, v in rawpairs(t) do
|
|
||||||
countTableAppearances(k, tableAppearances)
|
|
||||||
countTableAppearances(v, tableAppearances)
|
|
||||||
end
|
|
||||||
countTableAppearances(getmetatable(t), tableAppearances)
|
|
||||||
else
|
|
||||||
tableAppearances[t] = tableAppearances[t] + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return tableAppearances
|
|
||||||
end
|
|
||||||
|
|
||||||
local copySequence = function(s)
|
|
||||||
local copy, len = {}, #s
|
|
||||||
for i = 1, len do
|
|
||||||
copy[i] = s[i]
|
|
||||||
end
|
|
||||||
return copy, len
|
|
||||||
end
|
|
||||||
|
|
||||||
local function makePath(path, ...)
|
|
||||||
local keys = {...}
|
|
||||||
local newPath, len = copySequence(path)
|
|
||||||
for i = 1, #keys do
|
|
||||||
newPath[len + i] = keys[i]
|
|
||||||
end
|
|
||||||
return newPath
|
|
||||||
end
|
|
||||||
|
|
||||||
local function processRecursive(process, item, path, visited)
|
|
||||||
if item == nil then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
if visited[item] then
|
|
||||||
return visited[item]
|
|
||||||
end
|
|
||||||
|
|
||||||
local processed = process(item, path)
|
|
||||||
if type(processed) == "table" then
|
|
||||||
local processedCopy = {}
|
|
||||||
visited[item] = processedCopy
|
|
||||||
local processedKey
|
|
||||||
|
|
||||||
for k, v in rawpairs(processed) do
|
|
||||||
processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY), visited)
|
|
||||||
if processedKey ~= nil then
|
|
||||||
processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey), visited)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited)
|
|
||||||
if type(mt) ~= "table" then
|
|
||||||
mt = nil
|
|
||||||
end -- ignore not nil/table __metatable field
|
|
||||||
setmetatable(processedCopy, mt)
|
|
||||||
processed = processedCopy
|
|
||||||
end
|
|
||||||
return processed
|
|
||||||
end
|
|
||||||
|
|
||||||
-------------------------------------------------------------------
|
|
||||||
|
|
||||||
local Inspector = {}
|
|
||||||
local Inspector_mt = {
|
|
||||||
__index = Inspector,
|
|
||||||
}
|
|
||||||
|
|
||||||
function Inspector:puts(...)
|
|
||||||
local args = {...}
|
|
||||||
local buffer = self.buffer
|
|
||||||
local len = #buffer
|
|
||||||
for i = 1, #args do
|
|
||||||
len = len + 1
|
|
||||||
buffer[len] = args[i]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Inspector:down(f)
|
|
||||||
self.level = self.level + 1
|
|
||||||
f()
|
|
||||||
self.level = self.level - 1
|
|
||||||
end
|
|
||||||
|
|
||||||
function Inspector:tabify()
|
|
||||||
self:puts(self.newline, string.rep(self.indent, self.level))
|
|
||||||
end
|
|
||||||
|
|
||||||
function Inspector:alreadyVisited(v)
|
|
||||||
return self.ids[v] ~= nil
|
|
||||||
end
|
|
||||||
|
|
||||||
function Inspector:getId(v)
|
|
||||||
local id = self.ids[v]
|
|
||||||
if not id then
|
|
||||||
local tv = type(v)
|
|
||||||
id = (self.maxIds[tv] or 0) + 1
|
|
||||||
self.maxIds[tv] = id
|
|
||||||
self.ids[v] = id
|
|
||||||
end
|
|
||||||
return tostring(id)
|
|
||||||
end
|
|
||||||
|
|
||||||
function Inspector:putKey(k)
|
|
||||||
if isIdentifier(k) then
|
|
||||||
return self:puts(k)
|
|
||||||
end
|
|
||||||
self:puts("[")
|
|
||||||
self:putValue(k)
|
|
||||||
self:puts("]")
|
|
||||||
end
|
|
||||||
|
|
||||||
function Inspector:putTable(t)
|
|
||||||
if t == inspect.KEY or t == inspect.METATABLE then
|
|
||||||
self:puts(tostring(t))
|
|
||||||
elseif self:alreadyVisited(t) then
|
|
||||||
self:puts("<table ", self:getId(t), ">")
|
|
||||||
elseif self.level >= self.depth then
|
|
||||||
self:puts("{...}")
|
|
||||||
else
|
|
||||||
if self.tableAppearances[t] > 1 then
|
|
||||||
self:puts("<", self:getId(t), ">")
|
|
||||||
end
|
|
||||||
|
|
||||||
local nonSequentialKeys, nonSequentialKeysLength, sequenceLength = getNonSequentialKeys(t)
|
|
||||||
local mt = getmetatable(t)
|
|
||||||
|
|
||||||
self:puts("{")
|
|
||||||
self:down(function()
|
|
||||||
local count = 0
|
|
||||||
for i = 1, sequenceLength do
|
|
||||||
if count > 0 then
|
|
||||||
self:puts(",")
|
|
||||||
end
|
|
||||||
self:puts(" ")
|
|
||||||
self:putValue(t[i])
|
|
||||||
count = count + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
for i = 1, nonSequentialKeysLength do
|
|
||||||
local k = nonSequentialKeys[i]
|
|
||||||
if count > 0 then
|
|
||||||
self:puts(",")
|
|
||||||
end
|
|
||||||
self:tabify()
|
|
||||||
self:putKey(k)
|
|
||||||
self:puts(" = ")
|
|
||||||
self:putValue(t[k])
|
|
||||||
count = count + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
if type(mt) == "table" then
|
|
||||||
if count > 0 then
|
|
||||||
self:puts(",")
|
|
||||||
end
|
|
||||||
self:tabify()
|
|
||||||
self:puts("<metatable> = ")
|
|
||||||
self:putValue(mt)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
if nonSequentialKeysLength > 0 or type(mt) == "table" then -- result is multi-lined. Justify closing }
|
|
||||||
self:tabify()
|
|
||||||
elseif sequenceLength > 0 then -- array tables have one extra space before closing }
|
|
||||||
self:puts(" ")
|
|
||||||
end
|
|
||||||
|
|
||||||
self:puts("}")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Inspector:putValue(v)
|
|
||||||
local tv = type(v)
|
|
||||||
|
|
||||||
if tv == "string" then
|
|
||||||
self:puts(smartQuote(escape(v)))
|
|
||||||
elseif tv == "number" or tv == "boolean" or tv == "nil" or tv == "cdata" or tv == "ctype" then
|
|
||||||
self:puts(tostring(v))
|
|
||||||
elseif tv == "table" then
|
|
||||||
self:putTable(v)
|
|
||||||
else
|
|
||||||
self:puts("<", tv, " ", self:getId(v), ">")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-------------------------------------------------------------------
|
|
||||||
|
|
||||||
function inspect.inspect(root, options)
|
|
||||||
options = options or {}
|
|
||||||
|
|
||||||
local depth = options.depth or math.huge
|
|
||||||
local newline = options.newline or "\n"
|
|
||||||
local indent = options.indent or " "
|
|
||||||
local process = options.process
|
|
||||||
|
|
||||||
if process then
|
|
||||||
root = processRecursive(process, root, {}, {})
|
|
||||||
end
|
|
||||||
|
|
||||||
local inspector = setmetatable({
|
|
||||||
depth = depth,
|
|
||||||
level = 0,
|
|
||||||
buffer = {},
|
|
||||||
ids = {},
|
|
||||||
maxIds = {},
|
|
||||||
newline = newline,
|
|
||||||
indent = indent,
|
|
||||||
tableAppearances = countTableAppearances(root),
|
|
||||||
}, Inspector_mt)
|
|
||||||
|
|
||||||
inspector:putValue(root)
|
|
||||||
|
|
||||||
return table.concat(inspector.buffer)
|
|
||||||
end
|
|
||||||
|
|
||||||
setmetatable(inspect, {
|
|
||||||
__call = function(_, ...)
|
|
||||||
return inspect.inspect(...)
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
|
|
||||||
return inspect
|
|
||||||
@ -1,223 +1,76 @@
|
|||||||
---
|
local skynet = require "skynet"
|
||||||
-- @module log
|
local log_define = require "zlog.log_define"
|
||||||
--
|
|
||||||
local _COPYRIGHT = "Copyright (C) 2013-2016 Alexey Melnichuk";
|
|
||||||
local _VERSION = "0.1.7-dev"
|
|
||||||
|
|
||||||
local table = require "table"
|
|
||||||
local date = require "date"
|
|
||||||
|
|
||||||
local destroy_list = {}
|
|
||||||
local loggers_list = setmetatable({}, {
|
|
||||||
__mode = 'k',
|
|
||||||
})
|
|
||||||
local emptyfn = function()
|
|
||||||
end
|
|
||||||
|
|
||||||
local LOG_LVL = {
|
local getinfo = debug.getinfo
|
||||||
EMERG = 1,
|
local LOG_LEVEL = log_define.LOG_LEVEL
|
||||||
ALERT = 2,
|
local DEFAULT_CATEGORY = log_define.DEFAULT_CATEGORY
|
||||||
FATAL = 3,
|
local log_format = log_define.format
|
||||||
ERROR = 4,
|
|
||||||
WARNING = 5,
|
|
||||||
NOTICE = 6,
|
|
||||||
INFO = 7,
|
|
||||||
DEBUG = 8,
|
|
||||||
TRACE = 9,
|
|
||||||
}
|
|
||||||
|
|
||||||
local writer_names = {}
|
|
||||||
local LOG_LVL_NAMES = {}
|
|
||||||
for k, v in pairs(LOG_LVL) do
|
|
||||||
LOG_LVL_NAMES[v] = k
|
|
||||||
writer_names[v] = k:lower()
|
|
||||||
end
|
|
||||||
|
|
||||||
local LOG_LVL_COUNT = #LOG_LVL_NAMES
|
local category_addr = {}
|
||||||
|
|
||||||
local function lvl2number(lvl)
|
local function get_service(category)
|
||||||
if type(lvl) == 'number' then
|
local addr = category_addr[category]
|
||||||
return lvl
|
if addr then
|
||||||
end
|
return addr
|
||||||
if type(lvl) == 'string' then
|
|
||||||
lvl = lvl:upper()
|
|
||||||
local n
|
|
||||||
if lvl == 'NONE' then
|
|
||||||
n = 0
|
|
||||||
else
|
|
||||||
n = LOG_LVL[lvl]
|
|
||||||
end
|
|
||||||
if not n then
|
|
||||||
return nil, "unknown log level: '" .. lvl .. "'"
|
|
||||||
end
|
|
||||||
return n
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return nil, 'unsupported log leve type: ' .. type(lvl)
|
local root_addr = skynet.localname(".logger")
|
||||||
|
if not root_addr then
|
||||||
|
-- no logger config
|
||||||
|
root_addr = skynet.uniqueservice("logger")
|
||||||
end
|
end
|
||||||
|
|
||||||
local Log = {}
|
addr = skynet.call(root_addr, "lua", "get_service", category)
|
||||||
Log._COPYRIGHT = _COPYRIGHT
|
category_addr[category] = addr
|
||||||
Log._NAME = "log"
|
return addr
|
||||||
Log._VERSION = _VERSION
|
|
||||||
Log._LICENSE = "MIT"
|
|
||||||
|
|
||||||
Log.LVL = LOG_LVL
|
|
||||||
Log.LVL_NAMES = LOG_LVL_NAMES
|
|
||||||
|
|
||||||
Log.lvl2number = lvl2number
|
|
||||||
|
|
||||||
function Log.new(max_lvl, writer, formatter, logformat)
|
|
||||||
if max_lvl and type(max_lvl) ~= 'number' and type(max_lvl) ~= 'string' then
|
|
||||||
max_lvl, writer, formatter, logformat = nil, max_lvl, writer, formatter
|
|
||||||
end
|
end
|
||||||
|
|
||||||
max_lvl = assert(lvl2number(max_lvl or LOG_LVL.INFO))
|
local function sendlog(category, level, ...)
|
||||||
|
local di = getinfo(3, "Sl")
|
||||||
if not writer then
|
local msg = log_format(skynet.self(), level, di, ...)
|
||||||
writer = require"log.writer.stdout".new()
|
skynet.call(get_service(category), "lua", "log", level, msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
if not formatter then
|
local M = {}
|
||||||
formatter = require"log.formatter.default".new()
|
|
||||||
end
|
|
||||||
|
|
||||||
if not logformat then
|
function M.d(...)
|
||||||
logformat = require"log.logformat.default".new()
|
sendlog(DEFAULT_CATEGORY, LOG_LEVEL.DEBUG, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
local write = function(lvl, ...)
|
function M.d2(category, ...)
|
||||||
local now = date()
|
sendlog(category, LOG_LEVEL.DEBUG, ...)
|
||||||
writer(logformat, formatter(...), lvl, now)
|
|
||||||
end;
|
|
||||||
|
|
||||||
local dump = function(lvl, fn, ...)
|
|
||||||
local now = date()
|
|
||||||
writer(logformat, (fn(...) or ''), lvl, now)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local logger = {}
|
function M.i(...)
|
||||||
|
sendlog(DEFAULT_CATEGORY, LOG_LEVEL.INFO, ...)
|
||||||
function logger.writer()
|
|
||||||
return writer
|
|
||||||
end
|
|
||||||
|
|
||||||
function logger.formatter()
|
|
||||||
return formatter
|
|
||||||
end
|
|
||||||
|
|
||||||
function logger.format()
|
|
||||||
return logformat
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function logger.lvl()
|
function M.i2(category, ...)
|
||||||
return max_lvl
|
sendlog(category, LOG_LEVEL.INFO, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
function logger.set_writer(value)
|
function M.w(...)
|
||||||
assert(value)
|
sendlog(DEFAULT_CATEGORY, LOG_LEVEL.WARN, ...)
|
||||||
writer, value = value, writer
|
|
||||||
return value
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function logger.set_formatter(value)
|
function M.w2(category, ...)
|
||||||
assert(value)
|
sendlog(category, LOG_LEVEL.WARN, ...)
|
||||||
formatter, value = value, formatter
|
|
||||||
return value
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function logger.set_format(value)
|
function M.e(...)
|
||||||
assert(value)
|
sendlog(DEFAULT_CATEGORY, LOG_LEVEL.ERROR, ...)
|
||||||
logformat, value = value, logformat
|
|
||||||
return value
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function logger.log(lvl, ...)
|
function M.e2(category, ...)
|
||||||
local err
|
sendlog(category, LOG_LEVEL.ERROR, ...)
|
||||||
lvl, err = lvl2number(lvl)
|
|
||||||
if not lvl then
|
|
||||||
return nil, err
|
|
||||||
end
|
|
||||||
return write(lvl, ...)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function logger.dump(lvl, ...)
|
function M.f(...)
|
||||||
local err
|
sendlog(DEFAULT_CATEGORY, LOG_LEVEL.FATAL, ...)
|
||||||
lvl, err = lvl2number(lvl)
|
|
||||||
if not lvl then
|
|
||||||
return nil, err
|
|
||||||
end
|
|
||||||
return dump(lvl, ...)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function logger.set_lvl(lvl)
|
function M.f2(category, ...)
|
||||||
local err
|
sendlog(category, LOG_LEVEL.FATAL, ...)
|
||||||
lvl, err = lvl2number(lvl)
|
|
||||||
if not lvl then
|
|
||||||
return nil, err
|
|
||||||
end
|
|
||||||
max_lvl = lvl
|
|
||||||
for i = 1, max_lvl do
|
|
||||||
logger[writer_names[i]] = function(...)
|
|
||||||
write(i, ...)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for i = 1, max_lvl do
|
|
||||||
logger[writer_names[i] .. '_dump'] = function(...)
|
|
||||||
dump(i, ...)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for i = max_lvl + 1, LOG_LVL_COUNT do
|
|
||||||
logger[writer_names[i]] = emptyfn
|
|
||||||
end
|
|
||||||
for i = max_lvl + 1, LOG_LVL_COUNT do
|
|
||||||
logger[writer_names[i] .. '_dump'] = emptyfn
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
assert(logger.set_lvl(max_lvl))
|
|
||||||
|
|
||||||
loggers_list[logger] = true;
|
|
||||||
|
|
||||||
return logger
|
|
||||||
end
|
|
||||||
|
|
||||||
function Log.add_cleanup(fn)
|
|
||||||
assert(type(fn) == 'function')
|
|
||||||
for k, v in ipairs(destroy_list) do
|
|
||||||
if v == fn then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
table.insert(destroy_list, 1, fn)
|
|
||||||
return fn
|
|
||||||
end
|
|
||||||
|
|
||||||
function Log.remove_cleanup(fn)
|
|
||||||
for k, v in ipairs(destroy_list) do
|
|
||||||
if v == fn then
|
|
||||||
table.remove(destroy_list, k)
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Log.close()
|
|
||||||
for _, fn in ipairs(destroy_list) do
|
|
||||||
pcall(fn)
|
|
||||||
end
|
|
||||||
for logger in pairs(loggers_list) do
|
|
||||||
logger.fotal = emptyfn;
|
|
||||||
logger.error = emptyfn;
|
|
||||||
logger.warning = emptyfn;
|
|
||||||
logger.info = emptyfn;
|
|
||||||
logger.notice = emptyfn;
|
|
||||||
logger.debug = emptyfn;
|
|
||||||
logger.closed = true;
|
|
||||||
loggers_list[logger] = nil
|
|
||||||
end
|
|
||||||
destroy_list = {}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return Log
|
return M
|
||||||
|
|||||||
@ -0,0 +1,77 @@
|
|||||||
|
local string_format = string.format
|
||||||
|
local tconcat = table.concat
|
||||||
|
local os_date = os.date
|
||||||
|
local string_sub = string.sub
|
||||||
|
local os_clock = os.clock
|
||||||
|
|
||||||
|
local ESC = string.char(27, 91)
|
||||||
|
local RESET = ESC .. '0m'
|
||||||
|
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
M.LOG_LEVEL = {
|
||||||
|
DEBUG = 1,
|
||||||
|
INFO = 2,
|
||||||
|
WARN = 3,
|
||||||
|
ERROR = 4,
|
||||||
|
FATAL = 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
M.LOG_LEVEL_NAME = {
|
||||||
|
[1] = "DEBUG",
|
||||||
|
[2] = "INFO ",
|
||||||
|
[3] = "WARN ",
|
||||||
|
[4] = "ERROR",
|
||||||
|
[5] = "FATAL",
|
||||||
|
}
|
||||||
|
|
||||||
|
M.LOG_COLOR = {
|
||||||
|
[1] = ESC .. '34m',
|
||||||
|
[2] = ESC .. '32m',
|
||||||
|
[3] = ESC .. '33m',
|
||||||
|
[4] = ESC .. '31m',
|
||||||
|
[5] = ESC .. '35m',
|
||||||
|
}
|
||||||
|
|
||||||
|
M.DEFAULT_CATEGORY = "root"
|
||||||
|
|
||||||
|
function M.log_dir(log_root, date)
|
||||||
|
return string_format("%s/%04d-%02d-%02d", log_root or ".", date.year, date.month, date.day)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.log_path(dir, prefix, category, date)
|
||||||
|
return string_format("%s/%s%s_%04d-%02d-%02d.log", dir or ".", prefix or "", category or M.DEFAULT_CATEGORY,
|
||||||
|
date.year, date.month, date.day)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.format(addr, level, di, ...)
|
||||||
|
local param = {...}
|
||||||
|
local date = os_date("*t")
|
||||||
|
local ms = string_sub(os_clock(), 3, 6)
|
||||||
|
|
||||||
|
local time = string_format("%02d:%02d:%02d.%02d", date.hour, date.min, date.sec, ms)
|
||||||
|
|
||||||
|
local fileline = ""
|
||||||
|
if di then
|
||||||
|
fileline = (" [%s:%d]"):format(di.short_src, di.currentline)
|
||||||
|
end
|
||||||
|
|
||||||
|
for k, v in pairs(param) do
|
||||||
|
param[k] = tostring(v)
|
||||||
|
end
|
||||||
|
|
||||||
|
local msg =
|
||||||
|
string_format("[:%08x][%s][%s] %s%s", addr, M.LOG_LEVEL_NAME[level], time, tconcat(param, " "), fileline)
|
||||||
|
|
||||||
|
return msg
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.color(level, msg)
|
||||||
|
local c = M.LOG_COLOR[level]
|
||||||
|
if not c then
|
||||||
|
return msg
|
||||||
|
end
|
||||||
|
return c .. msg .. RESET
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
||||||
@ -1,18 +0,0 @@
|
|||||||
local string = require "string"
|
|
||||||
local Log = require "log"
|
|
||||||
|
|
||||||
local sformat = string.format
|
|
||||||
local function date_fmt(now)
|
|
||||||
local Y, M, D = now:getdate()
|
|
||||||
return sformat("%.4d-%.2d-%.2d %.2d:%.2d:%.2d", Y, M, D, now:gettime())
|
|
||||||
end
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
function M.new()
|
|
||||||
return function(msg, lvl, now)
|
|
||||||
return date_fmt(now) .. ' [' .. Log.LVL_NAMES[lvl] .. '] ' .. msg
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
local packer = require "log.logformat.proxy.pack"
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
function M.new()
|
|
||||||
return function(now, lvl, msg)
|
|
||||||
return packer.pack(now, lvl, msg)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,36 +0,0 @@
|
|||||||
local Log = require "log"
|
|
||||||
local date = require "date"
|
|
||||||
local string = require "string"
|
|
||||||
local schar = string.char
|
|
||||||
local sbyte = string.byte
|
|
||||||
local sformat = string.format
|
|
||||||
local ssub = string.sub
|
|
||||||
local tn = tonumber
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
function M.pack(msg, lvl, now)
|
|
||||||
local Y, M, D = now:getdate()
|
|
||||||
local h, m, s = now:gettime()
|
|
||||||
local now_s = sformat("%.4d-%.2d-%.2d %.2d:%.2d:%.2d", Y, M, D, h, m, s)
|
|
||||||
|
|
||||||
return schar(lvl) .. now_s .. msg
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.unpack(str)
|
|
||||||
local lvl = sbyte(ssub(str, 1, 1))
|
|
||||||
if not Log.LVL_NAMES[lvl] then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local now_s = ssub(str, 2, 20)
|
|
||||||
local Y, M, D = ssub(str, 2, 5), ssub(str, 7, 8), ssub(str, 10, 11)
|
|
||||||
local h, m, s = ssub(str, 13, 14), ssub(str, 16, 17), ssub(str, 19, 20)
|
|
||||||
Y, M, D, h, m, s = tn(Y), tn(M), tn(D), tn(h), tn(m), tn(s)
|
|
||||||
if not (Y and M and D and h and m and s) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
return ssub(str, 21), lvl, date(Y, M, D, h, m, s)
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,148 +0,0 @@
|
|||||||
local string = require "string"
|
|
||||||
local math = require "math"
|
|
||||||
local Log = require "log"
|
|
||||||
|
|
||||||
local mod, floor, ceil, abs, pow = math.fmod, math.floor, math.ceil, math.abs, math.pow
|
|
||||||
local fmt = string.format
|
|
||||||
|
|
||||||
-- removes the decimal part of a number
|
|
||||||
local function fix(n)
|
|
||||||
n = tonumber(n)
|
|
||||||
return n and ((n > 0 and floor or ceil)(n))
|
|
||||||
end
|
|
||||||
|
|
||||||
local function lshift(a, b)
|
|
||||||
if math.pow then
|
|
||||||
return a * math.pow(2, b)
|
|
||||||
else
|
|
||||||
return a << b
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[ RFC5424
|
|
||||||
0 Emergency: system is unusable
|
|
||||||
1 Alert: action must be taken immediately
|
|
||||||
2 Critical: critical conditions
|
|
||||||
3 Error: error conditions
|
|
||||||
4 Warning: warning conditions
|
|
||||||
5 Notice: normal but significant condition
|
|
||||||
6 Informational: informational messages
|
|
||||||
7 Debug: debug-level messages
|
|
||||||
--]]
|
|
||||||
local SEVERITY = {
|
|
||||||
EMERG = 0,
|
|
||||||
ALERT = 1,
|
|
||||||
CRIT = 2,
|
|
||||||
ERR = 3,
|
|
||||||
WARNING = 4,
|
|
||||||
NOTICE = 5,
|
|
||||||
INFO = 6,
|
|
||||||
DEBUG = 7,
|
|
||||||
}
|
|
||||||
|
|
||||||
--[[ RFC5424
|
|
||||||
0 kernel messages
|
|
||||||
1 user-level messages
|
|
||||||
2 mail system
|
|
||||||
3 system daemons
|
|
||||||
4 security/authorization messages
|
|
||||||
5 messages generated internally by syslogd
|
|
||||||
6 line printer subsystem
|
|
||||||
7 network news subsystem
|
|
||||||
8 UUCP subsystem
|
|
||||||
9 clock daemon
|
|
||||||
10 security/authorization messages
|
|
||||||
11 FTP daemon
|
|
||||||
12 NTP subsystem
|
|
||||||
13 log audit
|
|
||||||
14 log alert
|
|
||||||
15 clock daemon (note 2)
|
|
||||||
16 local use 0 (local0)
|
|
||||||
17 local use 1 (local1)
|
|
||||||
18 local use 2 (local2)
|
|
||||||
19 local use 3 (local3)
|
|
||||||
20 local use 4 (local4)
|
|
||||||
21 local use 5 (local5)
|
|
||||||
22 local use 6 (local6)
|
|
||||||
23 local use 7 (local7)
|
|
||||||
--]]
|
|
||||||
local FACILITY = {
|
|
||||||
KERN = lshift(0, 3),
|
|
||||||
USER = lshift(1, 3),
|
|
||||||
MAIL = lshift(2, 3),
|
|
||||||
DAEMON = lshift(3, 3),
|
|
||||||
AUTH = lshift(4, 3),
|
|
||||||
SYSLOG = lshift(5, 3),
|
|
||||||
LPR = lshift(6, 3),
|
|
||||||
NEWS = lshift(7, 3),
|
|
||||||
UUCP = lshift(8, 3),
|
|
||||||
CRON = lshift(9, 3),
|
|
||||||
CLKD = lshift(9, 3),
|
|
||||||
AUTHPRIV = lshift(10, 3),
|
|
||||||
FTP = lshift(11, 3),
|
|
||||||
NTP = lshift(12, 3),
|
|
||||||
SECURITY = lshift(13, 3),
|
|
||||||
AUDIT = lshift(13, 3),
|
|
||||||
CONSOLE = lshift(14, 3),
|
|
||||||
ALERT = lshift(14, 3),
|
|
||||||
CLKD2 = lshift(15, 3),
|
|
||||||
LOCAL0 = lshift(16, 3),
|
|
||||||
LOCAL1 = lshift(17, 3),
|
|
||||||
LOCAL2 = lshift(18, 3),
|
|
||||||
LOCAL3 = lshift(19, 3),
|
|
||||||
LOCAL4 = lshift(20, 3),
|
|
||||||
LOCAL5 = lshift(21, 3),
|
|
||||||
LOCAL6 = lshift(22, 3),
|
|
||||||
LOCAL7 = lshift(23, 3),
|
|
||||||
}
|
|
||||||
|
|
||||||
local LVL2SYSLOG = {
|
|
||||||
[Log.LVL.EMERG] = SEVERITY.EMERG,
|
|
||||||
[Log.LVL.ALERT] = SEVERITY.ALERT,
|
|
||||||
[Log.LVL.FATAL] = SEVERITY.CRIT,
|
|
||||||
[Log.LVL.ERROR] = SEVERITY.ERR,
|
|
||||||
[Log.LVL.WARNING] = SEVERITY.WARNING,
|
|
||||||
[Log.LVL.NOTICE] = SEVERITY.NOTICE,
|
|
||||||
[Log.LVL.INFO] = SEVERITY.INFO,
|
|
||||||
[Log.LVL.DEBUG] = SEVERITY.DEBUG,
|
|
||||||
[Log.LVL.TRACE] = SEVERITY.DEBUG,
|
|
||||||
}
|
|
||||||
|
|
||||||
local function Date2SysLog(now)
|
|
||||||
local Y, M, D = now:getdate()
|
|
||||||
local h, m, s = now:gettime()
|
|
||||||
|
|
||||||
local b = -now:getbias();
|
|
||||||
local x = abs(b);
|
|
||||||
|
|
||||||
return fmt("%.4d-%.2d-%.2dT%.2d:%.2d:%.2d%s%.2d:%.2d", Y, M, D, h, m, s, b < 0 and "-" or "+", fix(x / 60),
|
|
||||||
floor(mod(x, 60)))
|
|
||||||
end
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
function M.new(facility, host_name, app_name, procid, msgid)
|
|
||||||
if not facility then
|
|
||||||
facility = FACILITY.USER
|
|
||||||
else
|
|
||||||
facility = FACILITY[facility:upper()]
|
|
||||||
end
|
|
||||||
host_name = host_name or '-'
|
|
||||||
app_name = app_name or '-'
|
|
||||||
procid = procid or '-'
|
|
||||||
msgid = msgid or '-'
|
|
||||||
|
|
||||||
-- HOSTNAME APP-NAME PROCID MSGID
|
|
||||||
local header = host_name .. ' ' .. app_name .. ' ' .. procid .. ' ' .. msgid
|
|
||||||
|
|
||||||
return function(msg, lvl, now)
|
|
||||||
local slvl = assert(LVL2SYSLOG[lvl])
|
|
||||||
return -- HEADER
|
|
||||||
-- PRI VERSION TIMESTAMP
|
|
||||||
'<' .. slvl + facility .. '>1 ' .. Date2SysLog(now) .. ' ' .. -- HEADER STRUCTURED-DATA MSG
|
|
||||||
header .. ' - ' .. msg
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,101 +0,0 @@
|
|||||||
local function prequire(...)
|
|
||||||
local ok, mod = pcall(require, ...)
|
|
||||||
return ok and mod, mod or nil
|
|
||||||
end
|
|
||||||
|
|
||||||
local llthreads = prequire "llthreads2"
|
|
||||||
if not llthreads then
|
|
||||||
llthreads = require "llthreads"
|
|
||||||
end
|
|
||||||
|
|
||||||
local runstring = function(code, ...)
|
|
||||||
code = [[do
|
|
||||||
local string = require "string"
|
|
||||||
local os = require "os"
|
|
||||||
local loadstring = loadstring or load
|
|
||||||
local lua_init = os.getenv("lua_init")
|
|
||||||
if lua_init and #lua_init > 0 then
|
|
||||||
if lua_init:sub(1,1) == '@' then dofile((lua_init:sub(2)))
|
|
||||||
else assert(loadstring(lua_init))() end
|
|
||||||
end
|
|
||||||
end;]] .. code
|
|
||||||
return llthreads.new(code, ...)
|
|
||||||
end
|
|
||||||
|
|
||||||
local sleep
|
|
||||||
do
|
|
||||||
repeat
|
|
||||||
local socket = prequire "socket"
|
|
||||||
if socket then
|
|
||||||
sleep = function(ms)
|
|
||||||
socket.sleep(ms / 1000)
|
|
||||||
end
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
local ztimer = prequire "lzmq.timer"
|
|
||||||
if ztimer then
|
|
||||||
sleep = ztimer.sleep
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
-- @todo find another way (use os.execute("sleep " .. ms)) on *nix
|
|
||||||
|
|
||||||
sleep = function()
|
|
||||||
end
|
|
||||||
break
|
|
||||||
until true
|
|
||||||
end
|
|
||||||
|
|
||||||
local Worker = [=[
|
|
||||||
(function(server, maker, logformat, ...)
|
|
||||||
local Log = require "log"
|
|
||||||
local logformat = require(logformat).new()
|
|
||||||
|
|
||||||
local loadstring = loadstring or load
|
|
||||||
local writer = assert(loadstring(maker))()
|
|
||||||
|
|
||||||
require(server).run(writer, Log.close, logformat, ...)
|
|
||||||
end)(...)
|
|
||||||
]=]
|
|
||||||
|
|
||||||
local function run_server(server, maker, logformat, ...)
|
|
||||||
if type(maker) == 'function' then
|
|
||||||
maker = string.dump(maker)
|
|
||||||
end
|
|
||||||
|
|
||||||
assert(type(server) == 'string')
|
|
||||||
assert(type(maker) == 'string')
|
|
||||||
assert(type(logformat) == 'string')
|
|
||||||
|
|
||||||
local child_thread = assert(runstring(Worker, server, maker, logformat, ...))
|
|
||||||
child_thread:start(true, true)
|
|
||||||
sleep(500)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local Z
|
|
||||||
local function run_zserver(server, maker, logformat, ctx, ...)
|
|
||||||
Z = Z or require "log.writer.net.zmq._private.compat"
|
|
||||||
|
|
||||||
if type(maker) == 'function' then
|
|
||||||
maker = string.dump(maker)
|
|
||||||
end
|
|
||||||
|
|
||||||
assert(type(server) == 'string')
|
|
||||||
assert(type(maker) == 'string')
|
|
||||||
assert(type(logformat) == 'string')
|
|
||||||
assert(Z.is_ctx(ctx))
|
|
||||||
|
|
||||||
local zthreads = assert(Z.threads)
|
|
||||||
local child_thread = assert((zthreads.run or zthreads.runstring)(ctx, Worker, server, maker, logformat, ...))
|
|
||||||
child_thread:start(true)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
M.run = run_server
|
|
||||||
M.zrun = run_zserver
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
local server = require "log.writer.async.server.lane"
|
|
||||||
local packer = require "log.logformat.proxy.pack"
|
|
||||||
|
|
||||||
local function create_writer(channel, maker)
|
|
||||||
if maker then
|
|
||||||
server.run(channel, maker, "log.logformat.default")
|
|
||||||
end
|
|
||||||
|
|
||||||
local queue = server.channel()
|
|
||||||
local pack = packer.pack
|
|
||||||
|
|
||||||
return function(fmt, ...)
|
|
||||||
local msg = pack(...)
|
|
||||||
queue:send(channel, msg)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
M.new = create_writer
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,71 +0,0 @@
|
|||||||
local on_lane_create = function()
|
|
||||||
local loadstring = loadstring or load
|
|
||||||
local lua_init = os.getenv("lua_init")
|
|
||||||
if lua_init and #lua_init > 0 then
|
|
||||||
if lua_init:sub(1, 1) == '@' then
|
|
||||||
dofile(lua_init:sub(2))
|
|
||||||
else
|
|
||||||
assert(loadstring(lua_init))()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local LOG = require "log"
|
|
||||||
local lanes = require"lanes".configure {
|
|
||||||
with_timers = false,
|
|
||||||
on_state_create = on_lane_create,
|
|
||||||
}
|
|
||||||
local pack = require"log.logformat.proxy.pack".pack
|
|
||||||
|
|
||||||
local queue
|
|
||||||
|
|
||||||
local function context()
|
|
||||||
queue = queue or assert(lanes.linda())
|
|
||||||
return queue
|
|
||||||
end
|
|
||||||
|
|
||||||
local function log_thread_fn(maker, logformat, channel)
|
|
||||||
local log_packer = require "log.logformat.proxy.pack"
|
|
||||||
local logformat = require(logformat).new()
|
|
||||||
local unpack = log_packer.unpack
|
|
||||||
|
|
||||||
local loadstring = loadstring or load
|
|
||||||
local writer = assert(assert(loadstring(maker))())
|
|
||||||
while (true) do
|
|
||||||
local key, val = queue:receive(1.0, channel)
|
|
||||||
-- print(maker, channel, key, val)
|
|
||||||
if not (key and val) then
|
|
||||||
key, val = nil, 'timeout'
|
|
||||||
end
|
|
||||||
if key then
|
|
||||||
local msg, lvl, now = unpack(val)
|
|
||||||
if msg and lvl and now then
|
|
||||||
writer(logformat, msg, lvl, now)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if val ~= 'timeout' then
|
|
||||||
io.stderror:write('lane_logger: ', val)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function start_log_thread(...)
|
|
||||||
local fn = assert(lanes.gen("*", log_thread_fn))
|
|
||||||
return assert(fn(...))
|
|
||||||
end
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
M.run = function(channel, maker, logformat)
|
|
||||||
logformat = logformat or "log.logformat.default"
|
|
||||||
context() -- init context
|
|
||||||
local child_thread = start_log_thread(maker, logformat, channel)
|
|
||||||
LOG.add_cleanup(function()
|
|
||||||
child_thread:cancel(60)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
M.channel = context
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
local server = require "log.writer.async._private.server"
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
M.run = function(host, port, maker, logformat)
|
|
||||||
logformat = logformat or "log.logformat.default"
|
|
||||||
server.run("log.writer.net.server.udp", maker, logformat, host, port)
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,42 +0,0 @@
|
|||||||
local Z = require "log.writer.net.zmq._private.compat"
|
|
||||||
local IMPL = require "log.writer.net.zmq._private.impl"
|
|
||||||
local server = require "log.writer.async._private.server"
|
|
||||||
|
|
||||||
local zmq, ETERM, zstrerror, zassert, zrecv = Z.zmq, Z.ETERM, Z.strerror, Z.assert, Z.recv
|
|
||||||
|
|
||||||
local function rand_str(n)
|
|
||||||
math.randomseed(os.time())
|
|
||||||
local str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
|
||||||
local res = ''
|
|
||||||
for i = 1, n do
|
|
||||||
local n = math.random(1, #str)
|
|
||||||
res = res .. str:sub(n, n)
|
|
||||||
end
|
|
||||||
return res
|
|
||||||
end
|
|
||||||
|
|
||||||
local function create_server(ctx, addr, maker, logformat)
|
|
||||||
if ctx and not Z.is_ctx(ctx) then
|
|
||||||
ctx, addr, maker, logformat = nil, ctx, addr, maker
|
|
||||||
end
|
|
||||||
logformat = logformat or "log.logformat.default"
|
|
||||||
|
|
||||||
ctx = IMPL.context(ctx)
|
|
||||||
|
|
||||||
if maker then
|
|
||||||
local addr_sync = 'inproc://' .. rand_str(15)
|
|
||||||
local skt_sync = zassert(ctx:socket(zmq.PAIR))
|
|
||||||
zassert(skt_sync:bind(addr_sync))
|
|
||||||
server.zrun("log.writer.net.server.zmq", maker, logformat, ctx, false, 'PULL', addr, addr_sync)
|
|
||||||
zassert(skt_sync:recv())
|
|
||||||
skt_sync:close()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
M.run = create_server
|
|
||||||
|
|
||||||
M.context = IMPL.context
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
local server = require "log.writer.async.server.udp"
|
|
||||||
|
|
||||||
local function create_writer(host, port, maker)
|
|
||||||
if maker then
|
|
||||||
server.run(host, port, maker, "log.logformat.default")
|
|
||||||
end
|
|
||||||
|
|
||||||
local writer = require"log.writer.format".new(require"log.logformat.proxy".new(),
|
|
||||||
require"log.writer.net.udp".new(host, port))
|
|
||||||
|
|
||||||
return writer
|
|
||||||
end
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
M.new = create_writer
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
local Z = require "log.writer.net.zmq._private.compat"
|
|
||||||
local server = require "log.writer.async.server.zmq"
|
|
||||||
|
|
||||||
local function create_writer(ctx, addr, maker)
|
|
||||||
if ctx and not Z.is_ctx(ctx) then
|
|
||||||
ctx, addr, maker = nil, ctx, addr
|
|
||||||
end
|
|
||||||
|
|
||||||
if maker then
|
|
||||||
server.run(ctx, addr, maker, "log.logformat.default")
|
|
||||||
end
|
|
||||||
|
|
||||||
return require"log.writer.format".new(require"log.logformat.proxy".new(),
|
|
||||||
require"log.writer.net.zmq.push".new(ctx, addr))
|
|
||||||
end
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
M.new = create_writer
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1 +0,0 @@
|
|||||||
return require "log.writer.stdout"
|
|
||||||
@ -1,334 +0,0 @@
|
|||||||
local io = require "io"
|
|
||||||
local os = require "os"
|
|
||||||
local Log = require "log"
|
|
||||||
|
|
||||||
local make_attr, color_writeln, COLORS
|
|
||||||
|
|
||||||
if not COLORS then -- afx cio
|
|
||||||
local ok, cio = pcall(require, "cio")
|
|
||||||
if ok then
|
|
||||||
COLORS = {
|
|
||||||
BLACK = 'n',
|
|
||||||
BLUE = 'b',
|
|
||||||
GREEN = 'g',
|
|
||||||
CYAN = 'c',
|
|
||||||
RED = 'r',
|
|
||||||
MAGENTA = 'm',
|
|
||||||
BROWN = 'y',
|
|
||||||
LIGHTGRAY = 'w',
|
|
||||||
DARKGRAY = 'n+',
|
|
||||||
LIGHTBLUE = 'b+',
|
|
||||||
LIGHTGREEN = 'g+',
|
|
||||||
LIGHTCYAN = 'c+',
|
|
||||||
LIGHTRED = 'r+',
|
|
||||||
LIGHTMAGENTA = 'm+',
|
|
||||||
YELLOW = 'y+',
|
|
||||||
WHITE = 'w+',
|
|
||||||
}
|
|
||||||
make_attr = function(F, B)
|
|
||||||
return F .. '/' .. B
|
|
||||||
end
|
|
||||||
color_writeln = function(attr, text)
|
|
||||||
cio.textattr(attr)
|
|
||||||
cio.writeln(text or "")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if not COLORS then -- conio
|
|
||||||
local ok, conio = pcall(require, "conio")
|
|
||||||
if ok then
|
|
||||||
COLORS = {
|
|
||||||
BLACK = conio.COLOR_BLACK,
|
|
||||||
BLUE = conio.COLOR_BLUE,
|
|
||||||
GREEN = conio.COLOR_GREEN,
|
|
||||||
CYAN = conio.COLOR_CYAN,
|
|
||||||
RED = conio.COLOR_RED,
|
|
||||||
MAGENTA = conio.COLOR_MAGENTA,
|
|
||||||
BROWN = conio.COLOR_BROWN,
|
|
||||||
LIGHTGRAY = conio.COLOR_LIGHTGRAY,
|
|
||||||
DARKGRAY = conio.COLOR_DARKGRAY,
|
|
||||||
LIGHTBLUE = conio.COLOR_LIGHTBLUE,
|
|
||||||
LIGHTGREEN = conio.COLOR_LIGHTGREEN,
|
|
||||||
LIGHTCYAN = conio.COLOR_LIGHTCYAN,
|
|
||||||
LIGHTRED = conio.COLOR_LIGHTRED,
|
|
||||||
LIGHTMAGENTA = conio.COLOR_LIGHTMAGENTA,
|
|
||||||
YELLOW = conio.COLOR_YELLOW,
|
|
||||||
WHITE = conio.COLOR_WHITE,
|
|
||||||
}
|
|
||||||
make_attr = function(F, B)
|
|
||||||
return {F, B}
|
|
||||||
end
|
|
||||||
color_writeln = function(attr, text)
|
|
||||||
conio.textcolor(attr[1])
|
|
||||||
conio.textbackground(attr[2])
|
|
||||||
conio.cputs((text or "") .. '\n')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if not COLORS then -- ansicolors
|
|
||||||
local IS_WINDOWS = (package.config:sub(1, 1) == '\\')
|
|
||||||
if IS_WINDOWS and os.getenv("ANSICON") then
|
|
||||||
IS_WINDOWS = nil
|
|
||||||
end
|
|
||||||
local ok, c
|
|
||||||
if not IS_WINDOWS then
|
|
||||||
ok, c = pcall(require, "ansicolors")
|
|
||||||
end
|
|
||||||
if ok and (type(c) == 'table') then
|
|
||||||
if c.black then -- version above 1.0.2
|
|
||||||
COLORS = {
|
|
||||||
BLACK = 1,
|
|
||||||
BLUE = 2,
|
|
||||||
GREEN = 3,
|
|
||||||
CYAN = 4,
|
|
||||||
RED = 5,
|
|
||||||
MAGENTA = 6,
|
|
||||||
BROWN = 7,
|
|
||||||
LIGHTGRAY = 8,
|
|
||||||
DARKGRAY = 9,
|
|
||||||
LIGHTBLUE = 10,
|
|
||||||
LIGHTGREEN = 11,
|
|
||||||
LIGHTCYAN = 12,
|
|
||||||
LIGHTRED = 13,
|
|
||||||
LIGHTMAGENTA = 14,
|
|
||||||
YELLOW = 15,
|
|
||||||
WHITE = 16,
|
|
||||||
}
|
|
||||||
local reset = tostring(c.reset)
|
|
||||||
local fore = {
|
|
||||||
[COLORS.BLACK] = c.black,
|
|
||||||
[COLORS.BLUE] = c.blue,
|
|
||||||
[COLORS.GREEN] = c.green,
|
|
||||||
[COLORS.CYAN] = c.cyan,
|
|
||||||
[COLORS.RED] = c.red,
|
|
||||||
[COLORS.MAGENTA] = c.magenta,
|
|
||||||
[COLORS.BROWN] = c.yellow,
|
|
||||||
[COLORS.LIGHTGRAY] = c.white,
|
|
||||||
[COLORS.DARKGRAY] = c.black .. c.bright,
|
|
||||||
[COLORS.LIGHTBLUE] = c.blue .. c.bright,
|
|
||||||
[COLORS.LIGHTGREEN] = c.green .. c.bright,
|
|
||||||
[COLORS.LIGHTCYAN] = c.cyan .. c.bright,
|
|
||||||
[COLORS.LIGHTRED] = c.red .. c.bright,
|
|
||||||
[COLORS.LIGHTMAGENTA] = c.magenta .. c.bright,
|
|
||||||
[COLORS.YELLOW] = c.yellow .. c.bright,
|
|
||||||
[COLORS.WHITE] = c.white .. c.bright,
|
|
||||||
}
|
|
||||||
|
|
||||||
local back = {
|
|
||||||
[COLORS.BLACK] = c.onblack,
|
|
||||||
[COLORS.BLUE] = c.onblue,
|
|
||||||
[COLORS.GREEN] = c.ongreen,
|
|
||||||
[COLORS.CYAN] = c.oncyan,
|
|
||||||
[COLORS.RED] = c.onred,
|
|
||||||
[COLORS.MAGENTA] = c.onmagenta,
|
|
||||||
[COLORS.BROWN] = c.onyellow,
|
|
||||||
[COLORS.LIGHTGRAY] = c.onwhite,
|
|
||||||
[COLORS.DARKGRAY] = c.onblack .. c.bright,
|
|
||||||
[COLORS.LIGHTBLUE] = c.onblue .. c.bright,
|
|
||||||
[COLORS.LIGHTGREEN] = c.ongreen .. c.bright,
|
|
||||||
[COLORS.LIGHTCYAN] = c.oncyan .. c.bright,
|
|
||||||
[COLORS.LIGHTRED] = c.onred .. c.bright,
|
|
||||||
[COLORS.LIGHTMAGENTA] = c.onmagenta .. c.bright,
|
|
||||||
[COLORS.YELLOW] = c.onyellow .. c.bright,
|
|
||||||
[COLORS.WHITE] = c.onwhite .. c.bright,
|
|
||||||
}
|
|
||||||
|
|
||||||
make_attr = function(F, B)
|
|
||||||
return fore[F] .. back[B]
|
|
||||||
end
|
|
||||||
color_writeln = function(attr, text)
|
|
||||||
io.write(attr, text, reset, '\n')
|
|
||||||
end
|
|
||||||
elseif c.noReset then -- 1.0.2
|
|
||||||
COLORS = {
|
|
||||||
BLACK = 'black',
|
|
||||||
BLUE = 'blue',
|
|
||||||
GREEN = 'green',
|
|
||||||
CYAN = 'cyan',
|
|
||||||
RED = 'red',
|
|
||||||
MAGENTA = 'magenta',
|
|
||||||
BROWN = 'yellow',
|
|
||||||
LIGHTGRAY = 'white',
|
|
||||||
DARKGRAY = 'bright black',
|
|
||||||
LIGHTBLUE = 'bright blue',
|
|
||||||
LIGHTGREEN = 'bright green',
|
|
||||||
LIGHTCYAN = 'bright cyan',
|
|
||||||
LIGHTRED = 'bright red',
|
|
||||||
LIGHTMAGENTA = 'bright magenta',
|
|
||||||
YELLOW = 'bright yellow',
|
|
||||||
WHITE = 'bright white',
|
|
||||||
}
|
|
||||||
|
|
||||||
make_attr = function(F, B)
|
|
||||||
return c.noReset("%{" .. F .. " " .. B .. "bg}")
|
|
||||||
end
|
|
||||||
local RESET = c.noReset("%{reset}")
|
|
||||||
color_writeln = function(attr, text)
|
|
||||||
io.write(attr, (text), RESET, '\n')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if ok and (type(c) == 'function') then
|
|
||||||
COLORS = {
|
|
||||||
BLACK = 1,
|
|
||||||
BLUE = 2,
|
|
||||||
GREEN = 3,
|
|
||||||
CYAN = 4,
|
|
||||||
RED = 5,
|
|
||||||
MAGENTA = 6,
|
|
||||||
BROWN = 7,
|
|
||||||
LIGHTGRAY = 8,
|
|
||||||
DARKGRAY = 9,
|
|
||||||
LIGHTBLUE = 10,
|
|
||||||
LIGHTGREEN = 11,
|
|
||||||
LIGHTCYAN = 12,
|
|
||||||
LIGHTRED = 13,
|
|
||||||
LIGHTMAGENTA = 14,
|
|
||||||
YELLOW = 15,
|
|
||||||
WHITE = 16,
|
|
||||||
}
|
|
||||||
local fore = {
|
|
||||||
[COLORS.BLACK] = "%{black}",
|
|
||||||
[COLORS.BLUE] = "%{blue}",
|
|
||||||
[COLORS.GREEN] = "%{green}",
|
|
||||||
[COLORS.CYAN] = "%{cyan}",
|
|
||||||
[COLORS.RED] = "%{red}",
|
|
||||||
[COLORS.MAGENTA] = "%{magenta}",
|
|
||||||
[COLORS.BROWN] = "%{yellow}",
|
|
||||||
[COLORS.LIGHTGRAY] = "%{white}",
|
|
||||||
[COLORS.DARKGRAY] = "%{black}" .. "%{bright}",
|
|
||||||
[COLORS.LIGHTBLUE] = "%{blue}" .. "%{bright}",
|
|
||||||
[COLORS.LIGHTGREEN] = "%{green}" .. "%{bright}",
|
|
||||||
[COLORS.LIGHTCYAN] = "%{cyan}" .. "%{bright}",
|
|
||||||
[COLORS.LIGHTRED] = "%{red}" .. "%{bright}",
|
|
||||||
[COLORS.LIGHTMAGENTA] = "%{magenta}" .. "%{bright}",
|
|
||||||
[COLORS.YELLOW] = "%{yellow}" .. "%{bright}",
|
|
||||||
[COLORS.WHITE] = "%{white}" .. "%{bright}",
|
|
||||||
}
|
|
||||||
local back = {
|
|
||||||
[COLORS.BLACK] = "%{blackbg}",
|
|
||||||
[COLORS.BLUE] = "%{bluebg}",
|
|
||||||
[COLORS.GREEN] = "%{greenbg}",
|
|
||||||
[COLORS.CYAN] = "%{cyanbg}",
|
|
||||||
[COLORS.RED] = "%{redbg}",
|
|
||||||
[COLORS.MAGENTA] = "%{magentabg}",
|
|
||||||
[COLORS.BROWN] = "%{yellowbg}",
|
|
||||||
[COLORS.LIGHTGRAY] = "%{whitebg}",
|
|
||||||
[COLORS.DARKGRAY] = "%{blackbg}" .. "%{bright}",
|
|
||||||
[COLORS.LIGHTBLUE] = "%{bluebg}" .. "%{bright}",
|
|
||||||
[COLORS.LIGHTGREEN] = "%{greenbg}" .. "%{bright}",
|
|
||||||
[COLORS.LIGHTCYAN] = "%{cyanbg}" .. "%{bright}",
|
|
||||||
[COLORS.LIGHTRED] = "%{redbg}" .. "%{bright}",
|
|
||||||
[COLORS.LIGHTMAGENTA] = "%{magentabg}" .. "%{bright}",
|
|
||||||
[COLORS.YELLOW] = "%{yellowbg}" .. "%{bright}",
|
|
||||||
[COLORS.WHITE] = "%{whitebg}" .. "%{bright}",
|
|
||||||
}
|
|
||||||
make_attr = function(F, B)
|
|
||||||
return fore[F] .. back[B]
|
|
||||||
end
|
|
||||||
color_writeln = function(attr, text)
|
|
||||||
io.write(c(attr .. text), '\n')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if not COLORS then
|
|
||||||
local ok, term = pcall(require, "term")
|
|
||||||
if ok then
|
|
||||||
COLORS = {
|
|
||||||
BLACK = 1,
|
|
||||||
BLUE = 2,
|
|
||||||
GREEN = 3,
|
|
||||||
CYAN = 4,
|
|
||||||
RED = 5,
|
|
||||||
MAGENTA = 6,
|
|
||||||
BROWN = 7,
|
|
||||||
LIGHTGRAY = 8,
|
|
||||||
DARKGRAY = 9,
|
|
||||||
LIGHTBLUE = 10,
|
|
||||||
LIGHTGREEN = 11,
|
|
||||||
LIGHTCYAN = 12,
|
|
||||||
LIGHTRED = 13,
|
|
||||||
LIGHTMAGENTA = 14,
|
|
||||||
YELLOW = 15,
|
|
||||||
WHITE = 16,
|
|
||||||
}
|
|
||||||
|
|
||||||
local c = term.colors
|
|
||||||
local reset = c.reset
|
|
||||||
local fore = {
|
|
||||||
[COLORS.BLACK] = c.black,
|
|
||||||
[COLORS.BLUE] = c.blue,
|
|
||||||
[COLORS.GREEN] = c.green,
|
|
||||||
[COLORS.CYAN] = c.cyan,
|
|
||||||
[COLORS.RED] = c.red,
|
|
||||||
[COLORS.MAGENTA] = c.magenta,
|
|
||||||
[COLORS.BROWN] = c.yellow,
|
|
||||||
[COLORS.LIGHTGRAY] = c.white,
|
|
||||||
[COLORS.DARKGRAY] = c.black .. c.bright,
|
|
||||||
[COLORS.LIGHTBLUE] = c.blue .. c.bright,
|
|
||||||
[COLORS.LIGHTGREEN] = c.green .. c.bright,
|
|
||||||
[COLORS.LIGHTCYAN] = c.cyan .. c.bright,
|
|
||||||
[COLORS.LIGHTRED] = c.red .. c.bright,
|
|
||||||
[COLORS.LIGHTMAGENTA] = c.magenta .. c.bright,
|
|
||||||
[COLORS.YELLOW] = c.yellow .. c.bright,
|
|
||||||
[COLORS.WHITE] = c.white .. c.bright,
|
|
||||||
}
|
|
||||||
|
|
||||||
local back = {
|
|
||||||
[COLORS.BLACK] = c.onblack,
|
|
||||||
[COLORS.BLUE] = c.onblue,
|
|
||||||
[COLORS.GREEN] = c.ongreen,
|
|
||||||
[COLORS.CYAN] = c.oncyan,
|
|
||||||
[COLORS.RED] = c.onred,
|
|
||||||
[COLORS.MAGENTA] = c.onmagenta,
|
|
||||||
[COLORS.BROWN] = c.onyellow,
|
|
||||||
[COLORS.LIGHTGRAY] = c.onwhite,
|
|
||||||
[COLORS.DARKGRAY] = c.onblack .. c.bright,
|
|
||||||
[COLORS.LIGHTBLUE] = c.onblue .. c.bright,
|
|
||||||
[COLORS.LIGHTGREEN] = c.ongreen .. c.bright,
|
|
||||||
[COLORS.LIGHTCYAN] = c.oncyan .. c.bright,
|
|
||||||
[COLORS.LIGHTRED] = c.onred .. c.bright,
|
|
||||||
[COLORS.LIGHTMAGENTA] = c.onmagenta .. c.bright,
|
|
||||||
[COLORS.YELLOW] = c.onyellow .. c.bright,
|
|
||||||
[COLORS.WHITE] = c.onwhite .. c.bright,
|
|
||||||
}
|
|
||||||
|
|
||||||
make_attr = function(F, B)
|
|
||||||
return fore[F] .. back[B]
|
|
||||||
end
|
|
||||||
color_writeln = function(attr, text)
|
|
||||||
io.write(attr .. text .. reset, '\n')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if not COLORS then -- fallback to console
|
|
||||||
return require "log.writer.console"
|
|
||||||
end
|
|
||||||
|
|
||||||
local colors = {
|
|
||||||
[Log.LVL.EMERG] = make_attr(COLORS.WHITE, COLORS.LIGHTRED),
|
|
||||||
[Log.LVL.ALERT] = make_attr(COLORS.BLUE, COLORS.LIGHTRED),
|
|
||||||
[Log.LVL.FATAL] = make_attr(COLORS.BLACK, COLORS.LIGHTRED),
|
|
||||||
[Log.LVL.ERROR] = make_attr(COLORS.LIGHTRED, COLORS.BLACK),
|
|
||||||
[Log.LVL.WARNING] = make_attr(COLORS.LIGHTMAGENTA, COLORS.BLACK),
|
|
||||||
[Log.LVL.NOTICE] = make_attr(COLORS.LIGHTCYAN, COLORS.BLACK),
|
|
||||||
[Log.LVL.INFO] = make_attr(COLORS.WHITE, COLORS.BLACK),
|
|
||||||
[Log.LVL.DEBUG] = make_attr(COLORS.YELLOW, COLORS.BLACK),
|
|
||||||
[Log.LVL.TRACE] = make_attr(COLORS.LIGHTGREEN, COLORS.BLACK),
|
|
||||||
}
|
|
||||||
|
|
||||||
local function console_writer(fmt, msg, lvl, now)
|
|
||||||
color_writeln(colors[lvl], fmt(msg, lvl, now))
|
|
||||||
end
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
function M.new()
|
|
||||||
return console_writer
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
local LOG = require "log"
|
|
||||||
local file_logger = require "log.writer.file.private.impl"
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
function M.new(opt)
|
|
||||||
local logger = file_logger:new(opt)
|
|
||||||
LOG.add_cleanup(function()
|
|
||||||
logger:close()
|
|
||||||
end)
|
|
||||||
|
|
||||||
return function(fmt, msg, lvl, now)
|
|
||||||
logger:write((fmt(msg, lvl, now)))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
local file = require "log.writer.file"
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
function M.new(log_dir, log_name, max_rows)
|
|
||||||
return file.new {
|
|
||||||
log_dir = log_dir,
|
|
||||||
log_name = log_name,
|
|
||||||
max_rows = max_rows,
|
|
||||||
by_day = true,
|
|
||||||
close_file = false,
|
|
||||||
flush_interval = 1,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
|
|
||||||
@ -1,484 +0,0 @@
|
|||||||
local Log = require "log"
|
|
||||||
local io = require "io"
|
|
||||||
local os = require "os"
|
|
||||||
local string = require "string"
|
|
||||||
local date = require "date"
|
|
||||||
local lfs = require "lfs"
|
|
||||||
|
|
||||||
local DIR_SEP = package.config:sub(1, 1)
|
|
||||||
local IS_WINDOWS = DIR_SEP == '\\'
|
|
||||||
|
|
||||||
local function remove_dir_end(str)
|
|
||||||
return (string.gsub(str, '[\\/]+$', ''))
|
|
||||||
end
|
|
||||||
|
|
||||||
local function ensure_dir_end(str)
|
|
||||||
return remove_dir_end(str) .. DIR_SEP
|
|
||||||
end
|
|
||||||
|
|
||||||
local function path_normolize_sep(P)
|
|
||||||
return (string.gsub(P, '\\', DIR_SEP):gsub('/', DIR_SEP))
|
|
||||||
end
|
|
||||||
|
|
||||||
local function path_fullpath(P)
|
|
||||||
P = path_normolize_sep(P)
|
|
||||||
local ch1, ch2 = P:sub(1, 1), P:sub(2, 2)
|
|
||||||
if IS_WINDOWS then
|
|
||||||
if ch1 == DIR_SEP then -- \temp => c:\temp
|
|
||||||
local cwd = lfs.currentdir()
|
|
||||||
local disk = cwd:sub(1, 2)
|
|
||||||
P = disk .. P
|
|
||||||
elseif ch1 == '~' then -- ~\temp
|
|
||||||
local base = os.getenv('USERPROFILE') or (os.getenv('HOMEDRIVE') .. os.getenv('HOMEPATH'))
|
|
||||||
P = ((ch2 == DIR_SEP) and remove_dir_end(base) or ensure_dir_end(base)) .. string.sub(P, 2)
|
|
||||||
elseif ch2 ~= ':' then
|
|
||||||
P = ensure_dir_end(lfs.currentdir()) .. P
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if ch1 == '~' then -- ~/temp
|
|
||||||
local base = os.getenv('HOME')
|
|
||||||
P = ((ch2 == DIR_SEP) and remove_dir_end(base) or ensure_dir_end(base)) .. string.sub(P, 2)
|
|
||||||
else
|
|
||||||
if P:sub(1, 1) ~= '/' then
|
|
||||||
P = ensure_dir_end(lfs.currentdir()) .. P
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
P = string.gsub(P, DIR_SEP .. '%.' .. DIR_SEP, DIR_SEP):gsub(DIR_SEP .. DIR_SEP, DIR_SEP)
|
|
||||||
while true do
|
|
||||||
local first, last = string.find(P, DIR_SEP .. "[^" .. DIR_SEP .. "]+" .. DIR_SEP .. '%.%.' .. DIR_SEP)
|
|
||||||
if not first then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
P = string.sub(P, 1, first) .. string.sub(P, last + 1)
|
|
||||||
end
|
|
||||||
|
|
||||||
return P
|
|
||||||
end
|
|
||||||
|
|
||||||
local function attrib(P, ...)
|
|
||||||
if IS_WINDOWS then
|
|
||||||
if #P < 4 and P:sub(2, 2) == ':' then
|
|
||||||
P = ensure_dir_end(P) -- c: => c:\
|
|
||||||
else
|
|
||||||
P = remove_dir_end(P) -- c:\temp\ => c:\temp
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return lfs.attributes(P, ...)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function path_exists(P)
|
|
||||||
return attrib(P, 'mode') ~= nil and P
|
|
||||||
end
|
|
||||||
|
|
||||||
local function path_isdir(P)
|
|
||||||
return attrib(P, 'mode') == 'directory' and P
|
|
||||||
end
|
|
||||||
|
|
||||||
local function path_mkdir(P)
|
|
||||||
local P = path_fullpath(P)
|
|
||||||
local p = ''
|
|
||||||
|
|
||||||
for str in string.gmatch(ensure_dir_end(P), '.-' .. DIR_SEP) do
|
|
||||||
p = p .. str
|
|
||||||
if path_exists(p) then
|
|
||||||
if not path_isdir(p) then
|
|
||||||
return nil, 'can not create ' .. p
|
|
||||||
end
|
|
||||||
else
|
|
||||||
local ok, err = lfs.mkdir(remove_dir_end(p))
|
|
||||||
if not ok then
|
|
||||||
return nil, err .. ' ' .. p
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
local function path_getctime(P)
|
|
||||||
return attrib(P, 'change')
|
|
||||||
end
|
|
||||||
|
|
||||||
local function path_getmtime(P)
|
|
||||||
return attrib(P, 'modification')
|
|
||||||
end
|
|
||||||
|
|
||||||
local function path_getatime(P)
|
|
||||||
return attrib(P, 'access')
|
|
||||||
end
|
|
||||||
|
|
||||||
local function path_getsize(P)
|
|
||||||
return attrib(P, 'size')
|
|
||||||
end
|
|
||||||
|
|
||||||
local function path_getrows(P)
|
|
||||||
local f, err = io.open(P, "r")
|
|
||||||
if not f then
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
local count = 0
|
|
||||||
for _ in f:lines() do
|
|
||||||
count = count + 1
|
|
||||||
end
|
|
||||||
f:close()
|
|
||||||
return count
|
|
||||||
end
|
|
||||||
|
|
||||||
local function path_remove(P)
|
|
||||||
return os.remove(P)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function path_rename(from, to)
|
|
||||||
path_remove(to)
|
|
||||||
return os.rename(from, to)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function reset_out(FileName, rewrite)
|
|
||||||
local END_OF_LINE = '\n'
|
|
||||||
local FILE_APPEND = 'a'
|
|
||||||
|
|
||||||
if rewrite then
|
|
||||||
local FILE_REWRITE = 'w+'
|
|
||||||
local f, err = io.open(FileName, FILE_REWRITE);
|
|
||||||
if not f then
|
|
||||||
return nil, err
|
|
||||||
end
|
|
||||||
f:close();
|
|
||||||
end
|
|
||||||
|
|
||||||
return function(msg)
|
|
||||||
local f, err = io.open(FileName, FILE_APPEND)
|
|
||||||
if not f then
|
|
||||||
return nil, err
|
|
||||||
end
|
|
||||||
f:write(msg, END_OF_LINE)
|
|
||||||
f:close()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function make_no_close_reset(flush_interval)
|
|
||||||
return function(FileName, rewrite)
|
|
||||||
local END_OF_LINE = '\n'
|
|
||||||
local FILE_APPEND = 'a'
|
|
||||||
|
|
||||||
if rewrite then
|
|
||||||
local FILE_REWRITE = 'w+'
|
|
||||||
local f, err = io.open(FileName, FILE_REWRITE);
|
|
||||||
if not f then
|
|
||||||
return nil, err
|
|
||||||
end
|
|
||||||
f:close()
|
|
||||||
end
|
|
||||||
|
|
||||||
local f, err = io.open(FileName, FILE_APPEND);
|
|
||||||
if not f then
|
|
||||||
return nil, err
|
|
||||||
end
|
|
||||||
|
|
||||||
local writer
|
|
||||||
if flush_interval then
|
|
||||||
local flush_interval, counter = flush_interval, 0
|
|
||||||
writer = function(msg)
|
|
||||||
f:write(msg, END_OF_LINE)
|
|
||||||
counter = counter + 1
|
|
||||||
if counter >= flush_interval then
|
|
||||||
f:flush()
|
|
||||||
counter = 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
writer = function(msg)
|
|
||||||
f:write(msg, END_OF_LINE)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return writer, function()
|
|
||||||
f:close()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function split_ext(fname)
|
|
||||||
local s1, s2 = string.match(fname, '([^\\/]*)([.][^.\\/]*)$')
|
|
||||||
if s1 then
|
|
||||||
return s1, s2
|
|
||||||
end
|
|
||||||
s1 = string.match(fname, '([^\\/]+)$')
|
|
||||||
if s1 then
|
|
||||||
return s1, ''
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function assert_2(f1, f2, v1, v2)
|
|
||||||
assert(f1 == v1, string.format("Expected '%s' got '%s'", tostring(f1), tostring(v1)))
|
|
||||||
assert(f2 == v2, string.format("Expected '%s' got '%s'", tostring(f2), tostring(v2)))
|
|
||||||
end
|
|
||||||
|
|
||||||
assert_2("events", ".log", split_ext("events.log"))
|
|
||||||
assert_2("events", '', split_ext("events"))
|
|
||||||
assert_2(nil, nil, split_ext("events\\"))
|
|
||||||
assert_2('', '.log', split_ext("events\\.log"))
|
|
||||||
assert_2('log', '', split_ext("events\\log"))
|
|
||||||
|
|
||||||
local file_logger = {}
|
|
||||||
|
|
||||||
local FILE_LOG_DATE_FMT = "%Y%m%d"
|
|
||||||
local EOL_SIZE = IS_WINDOWS and 2 or 1
|
|
||||||
|
|
||||||
local function get_file_date(fname)
|
|
||||||
local mdate = path_getmtime(fname)
|
|
||||||
if mdate then
|
|
||||||
mdate = date(mdate):tolocal()
|
|
||||||
else
|
|
||||||
mdate = date()
|
|
||||||
end
|
|
||||||
return mdate:fmt(FILE_LOG_DATE_FMT)
|
|
||||||
end
|
|
||||||
|
|
||||||
function file_logger:close()
|
|
||||||
if self.private_.logger and self.private_.logger_close then
|
|
||||||
self.private_.logger_close()
|
|
||||||
end
|
|
||||||
self.private_.logger = nil
|
|
||||||
self.private_.logger_close = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
function file_logger:open()
|
|
||||||
local full_name = self:current_name()
|
|
||||||
|
|
||||||
local logger, err = self.private_.reset_out(full_name)
|
|
||||||
if not logger then
|
|
||||||
return nil, string.format("can not create logger for file '%s':", full_name, err)
|
|
||||||
end
|
|
||||||
|
|
||||||
self.private_.logger = logger
|
|
||||||
self.private_.logger_close = err
|
|
||||||
self.private_.log_date = os.date(FILE_LOG_DATE_FMT)
|
|
||||||
self.private_.log_rows = 0
|
|
||||||
self.private_.log_size = 0
|
|
||||||
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
function file_logger:current_name()
|
|
||||||
return self.private_.log_dir .. self.private_.log_name
|
|
||||||
end
|
|
||||||
|
|
||||||
function file_logger:archive_roll_name(i)
|
|
||||||
return self.private_.log_dir .. string.format("%s.%.5d.log", self.private_.arc_pfx, i)
|
|
||||||
end
|
|
||||||
|
|
||||||
function file_logger:archive_date_name(d, i)
|
|
||||||
return self.private_.log_dir .. string.format("%s.%s.%.5d.log", self.private_.arc_pfx, d, i)
|
|
||||||
end
|
|
||||||
|
|
||||||
function file_logger:reset_log_by_roll()
|
|
||||||
self:close()
|
|
||||||
|
|
||||||
local full_name = self:current_name()
|
|
||||||
local first_name = self:archive_roll_name(1)
|
|
||||||
|
|
||||||
-- we must "free" space for current file
|
|
||||||
if path_exists(first_name) then
|
|
||||||
for i = self.private_.roll_count - 1, 1, -1 do
|
|
||||||
local fname1 = self:archive_roll_name(i)
|
|
||||||
local fname2 = self:archive_roll_name(i + 1)
|
|
||||||
path_rename(fname1, fname2)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if path_exists(full_name) then
|
|
||||||
local ok, err = path_rename(full_name, first_name)
|
|
||||||
if not ok then
|
|
||||||
return nil, string.format("can not rename '%s' to '%s' : %s", full_name, first_name, err or '')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return self:open()
|
|
||||||
end
|
|
||||||
|
|
||||||
function file_logger:next_date_name(log_date)
|
|
||||||
local id = self.private_.id
|
|
||||||
|
|
||||||
local fname = self:archive_date_name(log_date, id)
|
|
||||||
while path_exists(fname) do
|
|
||||||
id = id + 1
|
|
||||||
fname = self:archive_date_name(log_date, id)
|
|
||||||
end
|
|
||||||
|
|
||||||
self.private_.id = id
|
|
||||||
return fname
|
|
||||||
end
|
|
||||||
|
|
||||||
function file_logger:reset_log_by_date(log_date)
|
|
||||||
self:close()
|
|
||||||
|
|
||||||
local full_name = self:current_name()
|
|
||||||
if path_exists(full_name) then -- previews file
|
|
||||||
log_date = log_date or get_file_date(full_name)
|
|
||||||
local next_fname = self:next_date_name(log_date)
|
|
||||||
local ok, err = path_rename(full_name, next_fname)
|
|
||||||
if not ok then
|
|
||||||
return nil, string.format("can not rename '%s' to '%s' : ", full_name, next_fname, err or '')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return self:open()
|
|
||||||
end
|
|
||||||
|
|
||||||
function file_logger:reset_log(...)
|
|
||||||
if self.private_.roll_count then
|
|
||||||
return self:reset_log_by_roll(...)
|
|
||||||
end
|
|
||||||
return self:reset_log_by_date(...)
|
|
||||||
end
|
|
||||||
|
|
||||||
function file_logger:check()
|
|
||||||
if self.private_.by_day then
|
|
||||||
local now = os.date(FILE_LOG_DATE_FMT)
|
|
||||||
if self.private_.log_date ~= now then
|
|
||||||
local ok, err = self:reset_log_by_date(self.private_.log_date)
|
|
||||||
self.private_.id = 1
|
|
||||||
return ok, err
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.private_.max_rows and (self.private_.log_rows >= self.private_.max_rows) then
|
|
||||||
return self:reset_log()
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.private_.max_size and (self.private_.log_size >= self.private_.max_size) then
|
|
||||||
return self:reset_log()
|
|
||||||
end
|
|
||||||
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
function file_logger:write(msg)
|
|
||||||
local ok, err = self:check()
|
|
||||||
if not ok then
|
|
||||||
io.stderr:write("logger error: ", err, '\n')
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
self.private_.logger(msg)
|
|
||||||
self.private_.log_rows = self.private_.log_rows + 1
|
|
||||||
self.private_.log_size = self.private_.log_size + #msg + EOL_SIZE
|
|
||||||
end
|
|
||||||
|
|
||||||
function file_logger:init(opt)
|
|
||||||
|
|
||||||
if (opt.by_day or opt.roll_count) then
|
|
||||||
assert(not (opt.by_day and opt.roll_count), "Can not set 'by_day' and 'roll_count' fields at the same time!")
|
|
||||||
end
|
|
||||||
assert(opt.log_name, 'field log_name is required')
|
|
||||||
|
|
||||||
local log_dir = path_fullpath(opt.log_dir or '.')
|
|
||||||
|
|
||||||
if path_exists(log_dir) then
|
|
||||||
assert(path_isdir(log_dir))
|
|
||||||
else
|
|
||||||
assert(path_mkdir(log_dir))
|
|
||||||
end
|
|
||||||
|
|
||||||
local log_name, log_ext = string.match(opt.log_name, '([^\\/]+)([.][^.\\/]+)$')
|
|
||||||
assert(log_name and log_ext)
|
|
||||||
|
|
||||||
log_dir = ensure_dir_end(log_dir)
|
|
||||||
local full_name = log_dir .. log_name .. log_ext
|
|
||||||
local current_size = path_getsize(full_name)
|
|
||||||
if 0 == current_size then
|
|
||||||
-- prevent rename zero size logfile
|
|
||||||
path_remove(full_name)
|
|
||||||
end
|
|
||||||
|
|
||||||
local flush_interval = opt.flush_interval and
|
|
||||||
assert(tonumber(opt.flush_interval), 'flush_interval must be a number') or 1
|
|
||||||
self.private_ = {
|
|
||||||
-- options
|
|
||||||
log_dir = log_dir,
|
|
||||||
log_name = log_name .. log_ext,
|
|
||||||
max_rows = opt.max_rows or math.huge,
|
|
||||||
max_size = opt.max_size or math.huge,
|
|
||||||
reset_out = opt.close_file and reset_out or make_no_close_reset(flush_interval),
|
|
||||||
arc_pfx = opt.archive_prefix or log_name,
|
|
||||||
roll_count = opt.roll_count and assert(tonumber(opt.roll_count), 'roll_count must be a number'),
|
|
||||||
by_day = not not opt.by_day,
|
|
||||||
|
|
||||||
-- state
|
|
||||||
-- log_date = ; -- date when current log file was create
|
|
||||||
-- log_rows = 0; -- how many lines in current log file
|
|
||||||
-- log_size = 0;
|
|
||||||
id = 1, -- numbers of file in current log_date
|
|
||||||
}
|
|
||||||
if self.private_.roll_count then
|
|
||||||
assert(self.private_.roll_count > 0)
|
|
||||||
end
|
|
||||||
|
|
||||||
local reuse_log = opt.reuse
|
|
||||||
|
|
||||||
if reuse_log and current_size and (current_size > 0) then
|
|
||||||
self.private_.log_date = get_file_date(full_name)
|
|
||||||
|
|
||||||
if opt.max_rows then
|
|
||||||
self.private_.log_rows = path_getrows(full_name) or 0
|
|
||||||
else
|
|
||||||
self.private_.log_rows = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
if opt.max_size then
|
|
||||||
self.private_.log_size = path_getsize(full_name) or 0
|
|
||||||
else
|
|
||||||
self.private_.log_size = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
local logger, err = self.private_.reset_out(full_name)
|
|
||||||
if not logger then
|
|
||||||
error(string.format("can not create logger for file '%s':", full_name, err))
|
|
||||||
end
|
|
||||||
|
|
||||||
self.private_.logger = logger
|
|
||||||
self.private_.logger_close = err
|
|
||||||
|
|
||||||
else
|
|
||||||
assert(self:reset_log())
|
|
||||||
end
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
function file_logger:new(...)
|
|
||||||
local o = setmetatable({}, {
|
|
||||||
__index = self,
|
|
||||||
}):init(...)
|
|
||||||
Log.add_cleanup(function()
|
|
||||||
o:close()
|
|
||||||
end)
|
|
||||||
return o
|
|
||||||
end
|
|
||||||
|
|
||||||
local function do_profile()
|
|
||||||
require"profiler".start()
|
|
||||||
|
|
||||||
local logger = file_logger:new{
|
|
||||||
log_dir = './logs',
|
|
||||||
log_name = "events.log",
|
|
||||||
max_rows = 1000,
|
|
||||||
max_size = 70,
|
|
||||||
roll_count = 11,
|
|
||||||
-- by_day = true;
|
|
||||||
close_file = false,
|
|
||||||
flush_interval = 1,
|
|
||||||
reuse = true,
|
|
||||||
}
|
|
||||||
|
|
||||||
for i = 1, 10000 do
|
|
||||||
local msg = string.format("%5d", i)
|
|
||||||
logger:write(msg)
|
|
||||||
end
|
|
||||||
|
|
||||||
logger:close()
|
|
||||||
end
|
|
||||||
|
|
||||||
return file_logger
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
local file = require "log.writer.file"
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
function M.new(log_dir, log_name, roll_count, max_size)
|
|
||||||
return file.new {
|
|
||||||
log_dir = log_dir,
|
|
||||||
log_name = log_name,
|
|
||||||
max_size = max_size or 10 * 1024 * 1024,
|
|
||||||
roll_count = assert(roll_count),
|
|
||||||
close_file = false,
|
|
||||||
flush_interval = 1,
|
|
||||||
reuse = true,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
|
|
||||||
@ -1 +0,0 @@
|
|||||||
return require "log.writer.filter.lvl.le"
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
local Log = require "log"
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
function M.new(max_lvl, writer)
|
|
||||||
max_lvl = assert(Log.lvl2number(max_lvl))
|
|
||||||
return function(fmt, msg, lvl, now)
|
|
||||||
if lvl == max_lvl then
|
|
||||||
writer(fmt, msg, lvl, now)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
local Log = require "log"
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
function M.new(max_lvl, writer)
|
|
||||||
max_lvl = assert(Log.lvl2number(max_lvl))
|
|
||||||
return function(fmt, msg, lvl, now)
|
|
||||||
if lvl <= max_lvl then
|
|
||||||
writer(fmt, msg, lvl, now)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
local M = {}
|
|
||||||
|
|
||||||
function M.new(newfmt, writer)
|
|
||||||
return function(oldfmt, msg, lvl, now)
|
|
||||||
writer(newfmt, msg, lvl, now)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,42 +0,0 @@
|
|||||||
local log = require "log"
|
|
||||||
|
|
||||||
local freeswitch = assert(freeswitch)
|
|
||||||
|
|
||||||
local FS_LVL = {
|
|
||||||
console = 0,
|
|
||||||
alert = 1,
|
|
||||||
crit = 2,
|
|
||||||
err = 3,
|
|
||||||
warning = 4,
|
|
||||||
notice = 5,
|
|
||||||
info = 6,
|
|
||||||
debug = 7,
|
|
||||||
}
|
|
||||||
|
|
||||||
local LOG2FS = {
|
|
||||||
[log.LVL.EMERG] = FS_LVL.alert,
|
|
||||||
[log.LVL.ALERT] = FS_LVL.alert,
|
|
||||||
[log.LVL.FATAL] = FS_LVL.crit,
|
|
||||||
[log.LVL.ERROR] = FS_LVL.err,
|
|
||||||
[log.LVL.WARNING] = FS_LVL.warning,
|
|
||||||
[log.LVL.NOTICE] = FS_LVL.notice,
|
|
||||||
[log.LVL.INFO] = FS_LVL.info,
|
|
||||||
[log.LVL.DEBUG] = FS_LVL.debug,
|
|
||||||
[log.LVL.TRACE] = FS_LVL.debug,
|
|
||||||
}
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
function M.new(session)
|
|
||||||
if session then
|
|
||||||
return function(fmt, msg, lvl, now)
|
|
||||||
session:consoleLog(LOG2FS[lvl], msg .. '\n')
|
|
||||||
end
|
|
||||||
else
|
|
||||||
return function(fmt, msg, lvl, now)
|
|
||||||
freeswitch.consoleLog(LOG2FS[lvl], msg .. '\n')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
local M = {}
|
|
||||||
|
|
||||||
function M.new(...)
|
|
||||||
local writers = {...}
|
|
||||||
return function(...)
|
|
||||||
for i = 1, #writers do
|
|
||||||
writers[i](...)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
local socket = require "socket"
|
|
||||||
local log_packer = require "log.logformat.proxy.pack"
|
|
||||||
|
|
||||||
local _M = {}
|
|
||||||
|
|
||||||
function _M.run(writer, final, logformat, host, port)
|
|
||||||
local uskt = assert(socket.udp())
|
|
||||||
assert(uskt:setsockname(host, port))
|
|
||||||
local unpack = log_packer.unpack
|
|
||||||
|
|
||||||
while true do
|
|
||||||
local msg, err = uskt:receivefrom()
|
|
||||||
if msg then
|
|
||||||
local msg, lvl, now = unpack(msg)
|
|
||||||
if msg and lvl and now then
|
|
||||||
writer(logformat, msg, lvl, now)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if err ~= 'timeout' then
|
|
||||||
io.stderr:write('log.writer.net.udp.server: ', err, '\n')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- @todo
|
|
||||||
-- if final then final() end
|
|
||||||
end
|
|
||||||
|
|
||||||
return _M
|
|
||||||
@ -1,55 +0,0 @@
|
|||||||
local Z = require "log.writer.net.zmq._private.compat"
|
|
||||||
local IMPL = require "log.writer.net.zmq._private.impl"
|
|
||||||
|
|
||||||
local zmq, ETERM, zstrerror, zassert, zrecv = Z.zmq, Z.ETERM, Z.strerror, Z.assert, Z.recv
|
|
||||||
local zerrcode = Z.errcode
|
|
||||||
|
|
||||||
local log_packer = require "log.logformat.proxy.pack"
|
|
||||||
|
|
||||||
local _M = {}
|
|
||||||
|
|
||||||
function _M.run(writer, final, logformat, ctx, stype, address, addr_sync)
|
|
||||||
-- print(writer, logformat, ctx, stype, address, addr_sync)
|
|
||||||
local stypes = {
|
|
||||||
SUB = zmq.SUB,
|
|
||||||
PULL = zmq.PULL,
|
|
||||||
}
|
|
||||||
stype = assert(stypes[stype], 'Unsupported socket type')
|
|
||||||
|
|
||||||
ctx = IMPL.context(ctx)
|
|
||||||
|
|
||||||
local skt = zassert(ctx:socket(stype))
|
|
||||||
zassert(skt:bind(address))
|
|
||||||
|
|
||||||
if addr_sync then
|
|
||||||
local skt_sync = zassert(ctx:socket(zmq.PAIR))
|
|
||||||
zassert(skt_sync:connect(addr_sync))
|
|
||||||
skt_sync:send("")
|
|
||||||
skt_sync:close()
|
|
||||||
end
|
|
||||||
|
|
||||||
local unpack = log_packer.unpack
|
|
||||||
|
|
||||||
while (true) do
|
|
||||||
local msg, err = zrecv(skt)
|
|
||||||
if msg then
|
|
||||||
local msg, lvl, now = unpack(msg)
|
|
||||||
if msg and lvl and now then
|
|
||||||
writer(logformat, msg, lvl, now)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if zerrcode(err) == ETERM then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
io.stderr:write('log.writer.net.zmq.server: ', tostring(err), zstrerror(err), '\n')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if final then
|
|
||||||
final()
|
|
||||||
end
|
|
||||||
|
|
||||||
skt:close()
|
|
||||||
end
|
|
||||||
|
|
||||||
return _M
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
local Log = require "log"
|
|
||||||
local sendmail = require "sendmail"
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
function M.new(from, to, server, subject)
|
|
||||||
assert(to, "'to' parameter is required")
|
|
||||||
assert(from, "'from' parameter is required")
|
|
||||||
assert(server, "'server' parameter is required")
|
|
||||||
|
|
||||||
subject = subject or ''
|
|
||||||
|
|
||||||
return function(fmt, msg, lvl, now)
|
|
||||||
msg = fmt(msg, lvl, now)
|
|
||||||
sendmail(from, to, server, {
|
|
||||||
subject = now:fmt("%F %T") .. ' [' .. Log.LVL_NAMES[lvl] .. '] ' .. subject,
|
|
||||||
file = {
|
|
||||||
name = 'message.txt',
|
|
||||||
data = msg,
|
|
||||||
},
|
|
||||||
text = msg,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
local socket = require("socket")
|
|
||||||
|
|
||||||
local function create_socket(host, port, timeout)
|
|
||||||
local skt = assert(socket.udp())
|
|
||||||
assert(skt:settimeout(timeout or 0.1))
|
|
||||||
assert(skt:setpeername(host, port))
|
|
||||||
return skt
|
|
||||||
end
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
function M.new(host, port, timeout)
|
|
||||||
local skt = create_socket(host, port, timeout)
|
|
||||||
return function(fmt, ...)
|
|
||||||
skt:send((fmt(...)))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1 +0,0 @@
|
|||||||
return require "log.writer.net.zmq.pub"
|
|
||||||
@ -1,150 +0,0 @@
|
|||||||
local function prequire(...)
|
|
||||||
local ok, mod = pcall(require, ...)
|
|
||||||
return ok and mod, mod or nil
|
|
||||||
end
|
|
||||||
|
|
||||||
local zmq, zthreads, zpoller
|
|
||||||
local zstrerror, zassert, ETERM
|
|
||||||
local zconnect, zbind
|
|
||||||
local zrecv_all, zrecv
|
|
||||||
local zerrcode
|
|
||||||
|
|
||||||
local function has_member(t, key)
|
|
||||||
local ok, has
|
|
||||||
if type(key) == "table" then
|
|
||||||
ok, has = pcall(function()
|
|
||||||
for _, k in ipairs(key) do
|
|
||||||
if nil == t[k] then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end)
|
|
||||||
else
|
|
||||||
ok, has = pcall(function()
|
|
||||||
return nil ~= t[key]
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
return ok and has
|
|
||||||
end
|
|
||||||
|
|
||||||
local function is_ctx(ctx)
|
|
||||||
local tname = type(ctx)
|
|
||||||
if (tname ~= 'table') and (tname ~= 'userdata') then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
return has_member(ctx, {'socket', 'term'})
|
|
||||||
end
|
|
||||||
|
|
||||||
zmq = prequire "lzmq"
|
|
||||||
if zmq then
|
|
||||||
zpoller = prequire "lzmq.poller"
|
|
||||||
zthreads = prequire "lzmq.threads"
|
|
||||||
ETERM = zmq.errors.ETERM
|
|
||||||
zstrerror = function(err)
|
|
||||||
if type(err) == "number" then
|
|
||||||
return zmq.strerror(err)
|
|
||||||
end
|
|
||||||
if type(err) == "string" then
|
|
||||||
return err
|
|
||||||
end
|
|
||||||
return err:msg()
|
|
||||||
end
|
|
||||||
zerrcode = function(err)
|
|
||||||
if type(err) == "number" then
|
|
||||||
return err
|
|
||||||
end
|
|
||||||
if type(err) == "string" then
|
|
||||||
return err
|
|
||||||
end -- @todo extract no from string
|
|
||||||
return err:no()
|
|
||||||
end
|
|
||||||
zassert = zmq.assert
|
|
||||||
zrecv_all = function(skt)
|
|
||||||
return skt:recv_all()
|
|
||||||
end
|
|
||||||
zconnect = function(skt, addr)
|
|
||||||
return skt:connect(addr)
|
|
||||||
end
|
|
||||||
zbind = function(skt, addr)
|
|
||||||
return skt:bind(addr)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
zmq = require "zmq"
|
|
||||||
zpoller = require "zmq.poller"
|
|
||||||
zthreads = prequire "zmq.threads"
|
|
||||||
ETERM = 'closed'
|
|
||||||
zstrerror = function(err)
|
|
||||||
return err
|
|
||||||
end
|
|
||||||
zerrcode = function(err)
|
|
||||||
return err
|
|
||||||
end
|
|
||||||
zassert = assert
|
|
||||||
zrecv_all = function(skt)
|
|
||||||
local t = {}
|
|
||||||
local r, err = skt:recv()
|
|
||||||
if not r then
|
|
||||||
return nil, err
|
|
||||||
end
|
|
||||||
table.insert(t, r)
|
|
||||||
while skt:rcvmore() == 1 do
|
|
||||||
r, err = skt:recv()
|
|
||||||
if not r then
|
|
||||||
return nil, err, t
|
|
||||||
end
|
|
||||||
table.insert(t, r)
|
|
||||||
end
|
|
||||||
return t
|
|
||||||
end
|
|
||||||
zconnect = function(skt, addr)
|
|
||||||
if type(addr) == 'table' then
|
|
||||||
for i, a in ipairs(addr) do
|
|
||||||
local ok, err = skt:connect(a)
|
|
||||||
if not ok then
|
|
||||||
return nil, err, i
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
return skt:connect(addr)
|
|
||||||
end
|
|
||||||
zbind = function(skt, addr)
|
|
||||||
if type(addr) == 'table' then
|
|
||||||
for i, a in ipairs(addr) do
|
|
||||||
local ok, err = skt:bind(a)
|
|
||||||
if not ok then
|
|
||||||
return nil, err, i
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
return skt:bind(addr)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
zrecv = function(skt)
|
|
||||||
local ok, err, t = zrecv_all(skt)
|
|
||||||
if not ok then
|
|
||||||
if t and t[1] then
|
|
||||||
return t[1]
|
|
||||||
end
|
|
||||||
return nil, err
|
|
||||||
end
|
|
||||||
return ok[1]
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
|
||||||
zmq = zmq,
|
|
||||||
threads = zthreads,
|
|
||||||
poller = zpoller,
|
|
||||||
connect = zconnect,
|
|
||||||
bind = zbind,
|
|
||||||
recv_all = zrecv_all,
|
|
||||||
recv = zrecv,
|
|
||||||
strerror = zstrerror,
|
|
||||||
errcode = zerrcode,
|
|
||||||
assert = zassert,
|
|
||||||
ETERM = ETERM,
|
|
||||||
is_ctx = is_ctx,
|
|
||||||
}
|
|
||||||
@ -1,74 +0,0 @@
|
|||||||
local Log = require "log"
|
|
||||||
local Z = require "log.writer.net.zmq._private.compat"
|
|
||||||
|
|
||||||
local zmq, zthreads = Z.zmq, Z.threads
|
|
||||||
local zstrerror, zassert = Z.strerror, Z.assert
|
|
||||||
local ETERM = Z.ETERM
|
|
||||||
local zconnect, zbind = Z.connect, Z.bind
|
|
||||||
|
|
||||||
local log_ctx
|
|
||||||
|
|
||||||
local function context(ctx)
|
|
||||||
-- we have to use same context for all writers
|
|
||||||
if ctx and log_ctx then
|
|
||||||
assert(ctx == log_ctx)
|
|
||||||
end
|
|
||||||
|
|
||||||
if log_ctx then
|
|
||||||
return log_ctx
|
|
||||||
end
|
|
||||||
|
|
||||||
log_ctx = ctx or (zthreads and zthreads.get_parent_ctx()) or zassert(zmq.init(1))
|
|
||||||
|
|
||||||
return log_ctx
|
|
||||||
end
|
|
||||||
|
|
||||||
local function socket(ctx, stype, is_srv, addr, timeout)
|
|
||||||
local stypes = {
|
|
||||||
PUSH = zmq.PUSH,
|
|
||||||
PUB = zmq.PUB,
|
|
||||||
}
|
|
||||||
stype = assert(stypes[stype], 'Unsupported socket type')
|
|
||||||
timeout = timeout or 100
|
|
||||||
ctx = context(ctx)
|
|
||||||
|
|
||||||
local skt = ctx:socket(stype)
|
|
||||||
if ctx.autoclose then
|
|
||||||
ctx:autoclose(skt)
|
|
||||||
end
|
|
||||||
skt:set_sndtimeo(timeout)
|
|
||||||
skt:set_linger(timeout)
|
|
||||||
if is_srv then
|
|
||||||
zassert(zbind(skt, addr))
|
|
||||||
else
|
|
||||||
zassert(zconnect(skt, addr))
|
|
||||||
end
|
|
||||||
if not ctx.autoclose then
|
|
||||||
Log.add_cleanup(function()
|
|
||||||
skt:close()
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
return skt
|
|
||||||
end
|
|
||||||
|
|
||||||
local function init(stype, is_srv)
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
function M.new(ctx, addr, timeout)
|
|
||||||
if ctx and not Z.is_ctx(ctx) then
|
|
||||||
ctx, addr, timeout = nil, ctx, addr
|
|
||||||
end
|
|
||||||
|
|
||||||
local skt = socket(ctx, stype, is_srv, addr, timeout)
|
|
||||||
return function(fmt, ...)
|
|
||||||
skt:send((fmt(...)))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
|
||||||
init = init,
|
|
||||||
context = context,
|
|
||||||
}
|
|
||||||
@ -1 +0,0 @@
|
|||||||
return require"log.writer.net.zmq._private.impl".init('PUB', false)
|
|
||||||
@ -1 +0,0 @@
|
|||||||
return require"log.writer.net.zmq._private.impl".init('PUSH', false)
|
|
||||||
@ -1 +0,0 @@
|
|||||||
return require"log.writer.net.zmq._private.impl".init('PUB', true)
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
local M = {}
|
|
||||||
|
|
||||||
function M.new(prefix, writer)
|
|
||||||
return function(fmt, msg, lvl, now)
|
|
||||||
writer(fmt, prefix .. msg, lvl, now)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
local io = require "io"
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
function M.new()
|
|
||||||
return function(fmt, ...)
|
|
||||||
io.stderr:write(fmt(...), '\n')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
local io = require "io"
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
function M.new()
|
|
||||||
return function(fmt, ...)
|
|
||||||
io.stdout:write(fmt(...), '\n')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@ -0,0 +1,177 @@
|
|||||||
|
local skynet = require "skynet"
|
||||||
|
local log_define = require "zlog.log_define"
|
||||||
|
local queue = require "skynet.queue"
|
||||||
|
require "skynet.manager"
|
||||||
|
|
||||||
|
local LOG_LEVEL = log_define.LOG_LEVEL
|
||||||
|
local DEFAULT_CATEGORY = log_define.DEFAULT_CATEGORY
|
||||||
|
local log_format = log_define.format
|
||||||
|
local color = log_define.color
|
||||||
|
local string_match = string.match
|
||||||
|
|
||||||
|
local skynet_env = require("skynet.env")
|
||||||
|
local nodeid = skynet_env.get("nodeid")
|
||||||
|
|
||||||
|
local zenv = require("zenv.init")
|
||||||
|
local define = zenv.Logger
|
||||||
|
|
||||||
|
local log_root = define.log_root
|
||||||
|
local log_level = define.log_level or LOG_LEVEL.INFO
|
||||||
|
local log_console = define.log_console
|
||||||
|
|
||||||
|
local name = zenv.get_node_conf(nodeid).name
|
||||||
|
local log_prefix = name .. "_"
|
||||||
|
|
||||||
|
local last_day = -1
|
||||||
|
local category = ...
|
||||||
|
local is_master = not category
|
||||||
|
local category_addr = {}
|
||||||
|
local lock = queue()
|
||||||
|
local file
|
||||||
|
|
||||||
|
local function close_file()
|
||||||
|
if not file then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
file:close()
|
||||||
|
file = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local function open_file(date)
|
||||||
|
date = date or os.date("*t")
|
||||||
|
|
||||||
|
local dir = log_define.log_dir(log_root, date)
|
||||||
|
if not os.rename(dir, dir) then
|
||||||
|
os.execute("mkdir -p " .. dir)
|
||||||
|
end
|
||||||
|
|
||||||
|
if file then
|
||||||
|
close_file()
|
||||||
|
end
|
||||||
|
|
||||||
|
local path = log_define.log_path(dir, log_prefix, category, date)
|
||||||
|
local f, e = io.open(path, "a")
|
||||||
|
if not f then
|
||||||
|
print("logger error:", tostring(e))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
file = f
|
||||||
|
last_day = date.day
|
||||||
|
end
|
||||||
|
|
||||||
|
local CMD = {}
|
||||||
|
|
||||||
|
function CMD.console(level, msg)
|
||||||
|
print(color(level, msg))
|
||||||
|
end
|
||||||
|
|
||||||
|
function CMD.log(level, msg)
|
||||||
|
if level < log_level then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
msg = msg or ""
|
||||||
|
local date = os.date("*t")
|
||||||
|
if not file or date.day ~= last_day then
|
||||||
|
open_file(date)
|
||||||
|
end
|
||||||
|
|
||||||
|
file:write(msg .. '\n')
|
||||||
|
file:flush()
|
||||||
|
|
||||||
|
if log_console then
|
||||||
|
if is_master then
|
||||||
|
CMD.console(level, msg)
|
||||||
|
else
|
||||||
|
skynet.call(".logger", "lua", "console", level, msg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function CMD.set_console(is_open)
|
||||||
|
log_console = is_open
|
||||||
|
if is_master then
|
||||||
|
for _, addr in pairs(category_addr) do
|
||||||
|
skynet.call(addr, "lua", "set_console", is_open)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function CMD.set_level(level)
|
||||||
|
log_level = level
|
||||||
|
if is_master then
|
||||||
|
for _, addr in pairs(category_addr) do
|
||||||
|
skynet.call(addr, "lua", "set_level", level)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function CMD.get_service(cate)
|
||||||
|
if not is_master then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local addr
|
||||||
|
lock(function()
|
||||||
|
addr = category_addr[cate]
|
||||||
|
if not addr then
|
||||||
|
addr = skynet.newservice("logger", cate)
|
||||||
|
category_addr[cate] = addr
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
return addr
|
||||||
|
end
|
||||||
|
|
||||||
|
if is_master then
|
||||||
|
|
||||||
|
skynet.info_func(function()
|
||||||
|
return {
|
||||||
|
log_console = log_console,
|
||||||
|
log_level = log_level,
|
||||||
|
}
|
||||||
|
end)
|
||||||
|
|
||||||
|
skynet.register_protocol {
|
||||||
|
name = "text",
|
||||||
|
id = skynet.PTYPE_TEXT,
|
||||||
|
unpack = skynet.tostring,
|
||||||
|
dispatch = function(_, addr, msg)
|
||||||
|
local level = LOG_LEVEL.INFO
|
||||||
|
if string_match(msg, "maybe in an endless loop") then
|
||||||
|
level = LOG_LEVEL.WARN
|
||||||
|
end
|
||||||
|
if string_match(msg, "stack traceback:") then
|
||||||
|
level = LOG_LEVEL.ERROR
|
||||||
|
end
|
||||||
|
msg = log_format(addr, level, nil, msg)
|
||||||
|
CMD.log(level, msg)
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
skynet.register_protocol {
|
||||||
|
name = "SYSTEM",
|
||||||
|
id = skynet.PTYPE_SYSTEM,
|
||||||
|
unpack = function(...)
|
||||||
|
return ...
|
||||||
|
end,
|
||||||
|
dispatch = function(_, addr)
|
||||||
|
local level = LOG_LEVEL.FATAL
|
||||||
|
local msg = log_format(addr, level, nil, "SIGHUP")
|
||||||
|
CMD.log(level, msg)
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
category_addr[DEFAULT_CATEGORY] = skynet.self()
|
||||||
|
skynet.register(".logger")
|
||||||
|
end
|
||||||
|
|
||||||
|
open_file()
|
||||||
|
|
||||||
|
skynet.start(function()
|
||||||
|
skynet.dispatch("lua", function(_, _, cmd, ...)
|
||||||
|
local f = CMD[cmd]
|
||||||
|
assert(f, cmd)
|
||||||
|
return skynet.retpack(f(...))
|
||||||
|
end)
|
||||||
|
end)
|
||||||
Loading…
Reference in New Issue