lua实现详细日志记录,lua日志记录


find .|xargs grep -ri "IBM"

--[[
logger
--]]


local _M = {}
local mt = { __index = _M }


local random = require("resty.random")
local str = require("resty.string")
local time = require("time")
local cjson = require("cjson")
 
local startTime = os.date("%H:%M:%S")


local function trim(s)
return string.gsub(s, "^%s*(.-)%s*$", "%1")
end


--[[
用分隔符切分字符串


@param pString 要切分的字符串
@param pPattern 分隔符

@return 返回一个table 里面存有切分后的字符串
--]]


local function split(str, delimiter)


    local fields = {}
    str:gsub(string.format("([^%s]*)%s?", delimiter, delimiter), function(c) table.insert(fields, c) end)


if fields[#fields] == "" then
fields[#fields] = nil
end


    return fields
end


--[[
将一个lua变量转换为字符串
可以让你更加清楚的看到这个变量里面到底存了什么内容


@param value 要转换成字符串的变量


@return 变量内容的字符串形式
--]]


local function to_str(value)
local str = ''


if type(value) ~= 'table' then
if type(value) == 'string' then
str = string.format("%q", value)
else
str = tostring(value)
end
else
local auxTable = {}


for key in pairs(value) do
if tonumber(key) ~= key then
table.insert(auxTable, key)
else
table.insert(auxTable, to_str(key))
end
end


table.sort(auxTable)


str = str .. '{'


local separator = ""
local entry = ""


for _, fieldName in ipairs(auxTable) do
if tonumber(fieldName) and tonumber(fieldName) > 0 then
entry = to_str(value[tonumber(fieldName)])
else
entry = fieldName .. " = " .. to_str(value[fieldName])
end
str = str .. separator .. entry


separator = ", "
end


str = str .. '}'


end


return str
end


--- log ID 
-- </br> 当前交易的log标识号,查询log的时候可以用来定位一笔交易。
-- @class table
-- @name id
-- @field id 用于定义当前交易log的8位随机16进制字符。


_M.id = str.to_hex(random.bytes(4, true))


_M.DAY  = 1
_M.HOUR = 2
_M.rotateType = _M.DAY




--- 设置记录日志文件的类型。
-- @param rotateType 要设定的类型。 
-- @return 没有返回。
-- @usage logger.setRotateType(logger.HOUR)


function _M.setRotateType(rotateType)


_M.rotateType = rotateType


end


--- 设置记录日志的目录.
-- @param path 记录日志的目录。
-- @return 没有返回
-- @usage logger.setPath("../logs/quickpay/")


function _M.setPath(path)


_M.path = path


local f, err = io.open(path, "r")
if not f then
os.execute(string.format("mkdir %s -p", path))
return
end 
f:close()


local f1, err = io.open(path .. "/tradelog", "r")
    if not f1 then
        os.execute(string.format("mkdir %s -p", path .. "/tradelog"))
        return
    end
    f1:close()


local f2, err = io.open(path .. "/monitor", "r")
    if not f2 then
        os.execute(string.format("mkdir %s -p", path .. "/monitor"))
        return
    end
    f2:close()


local f3, err = io.open(path .. "monitor.json", "r")
    if not f3 then
        os.execute(string.format("mkdir %s -p", path .. "/monitor.json"))
        return
    end
    f3:close()


end


--- 记录日志信息到文件traceYYYYMMDD.log中.
-- </br>文件被记录由setPath指定的目录中。
-- 格式 : [时间] [日志id] [文件, 行] 日志信息
-- @param str 记录的日志信息,如果str不是string类型,将会被转换为字符串。
-- @return 没有返回
-- @usage logger.log("retcode = " .. retcode)


function _M.log(uid, str, level)


-- 1. 如果不是string 会将变量转换为字符串。
if type(str) ~= "string" then
str = to_str(str)
end


local file


if _M.rotateType == _M.DAY then
file = string.format("%s/tradelog/trace%s.log", _M.path, os.date("%Y%m%d"))
else
file = string.format("%s/tradelog/trace%s.log", _M.path, os.date("%Y%m%d.%H"))
end


local f, err = io.open(file, "a")


-- 2. 如果打开文件失败直接返回,如果发现没有日志文件可以检查目录是否存在,还有权限。
if not f then return end


-- 3. 获取打日志时候的代码位置
level = tonumber(level) or 2


if level < 2 then 
level = 2
end


local debug_info = debug.getinfo(level, "Snl")


local i, j = debug_info.short_src:find("[^/]+$")
local filename = string.sub(debug_info.short_src, i, j)
local position = string.format("%s, %d", filename, debug_info.currentline)




    local tv = time.gettimeofday()
    local t = os.date("%H:%M:%S", tv.sec) .. ":" .. string.format("%03d", math.floor(tv.usec/1000))


-- 4. 每一行都要按照日志格式输出到日志文件中。
local lines = split(str, "\n")


for i, v in ipairs(lines) do
local line = string.format("[%s] [%s] [%s] [%s] %s\n", t, _M.id, uid, position, v)
f:write(line)
end

f:close()
end




--- 记录日志信息到文件traceYYYYMMDD.log中.
-- </br>文件被记录由setPath指定的目录中。
-- 格式 : [时间] [日志id] [文件, 行] 日志信息
-- @param str 记录的日志信息,如果str不是string类型,将会被转换为字符串。
-- @return 没有返回
-- @usage logger.debug("retcode = " .. retcode)


function _M.debug(str, level)


if not _M.debug then
return 
end


-- 1. 如果不是string 会将变量转换为字符串。
if type(str) ~= "string" then
str = to_str(str)
end


local file


if _M.rotateType == _M.DAY then
file = string.format("%s/trace%s.log", _M.path, os.date("%Y%m%d"))
else
file = string.format("%s/trace%s.log", _M.path, os.date("%Y%m%d.%H"))
end


local f, err = io.open(file, "a")


-- 2. 如果打开文件失败直接返回,如果发现没有日志文件可以检查目录是否存在,还有权限。
if not f then return end


-- 3. 获取打日志时候的代码位置


level = tonumber(level) or 2


if level < 2 then
level = 2
end


local debug_info = debug.getinfo(level, "Snl")


local i, j = debug_info.short_src:find("[^/]+$")
local filename = string.sub(debug_info.short_src, i, j)
local position = string.format("%s, %d", filename, debug_info.currentline)


-- 4. 每一行都要按照日志格式输出到日志文件中。
local lines = split(str, "\n")
lines = { str }


local tv = time.gettimeofday()
local t = os.date("%H:%M:%S", tv.sec) .. ":" .. tostring(math.floor(tv.usec/1000))


for i, v in ipairs(lines) do
local line = string.format("[%s] [%s] [%s] %s\n", t, _M.id, position, v)
f:write(line)
end

f:close()
end


local monitorData   = {}
local monitorDefine = {}
local monitorFields = {}


local placeholder   = "_"




--- 设置monitor的格式定义。
-- @param define monitor格式定义。
-- @return 没有返回
-- @usage logger.setMonitorDefine(require("paymentMonDefine"))


function _M.setMonitorDefine(define)


monitorDefine = define


for i, v in ipairs(monitorDefine) do
monitorFields[v.name] = placeholder
end


end




--- 设置monitor相关域的值。
-- @param key 要设置的域。
-- @param value 要设置的相关域对应的值。
-- @return 没有返回。
-- @usage logger.monitorSet("mcssn", mcssn)


function _M.monitorSet(key, value)


monitorFields[key] = value or placeholder


end




--- 记录monitor日志.
-- @return 没有返回
-- @usage logger.monitor()


function _M.monitor()


-- 1. 获取文件名
local file = string.format("%s/monitor/monitor%s.log", _M.path, os.date("%Y%m%d"))


local f, err = io.open(file, "a")


-- 2. 如果打开文件失败直接返回,如果发现没有日志文件可以检查目录是否存在,还有权限。
if not f then return end


local endTime = os.date("%H:%M:%S")


local line = string.format("%s %s %s", startTime, endTime, _M.id)


for i, v in ipairs(monitorDefine) do
local s = monitorFields[v.name]
s = trim(s)
if #s == 0 then s = placeholder end
s = s:sub(-tonumber(v.maxlen))
line = line .. string.format(" %-" .. v.maxlen .. "s", s)
end


line = line .. "\n"


f:write(line)
f:close()
end




---JSON log
local monitorDefine4Json = {}
local monitorFields4Json = {}


local placeholder4Json   = ""




function _M.setMonitorDefine4Json(define)


monitorFields4Json = define


for i, v in ipairs(monitorFields4Json) do
monitorFields4Json[v.name] = placeholder
end


end




--- 设置monitor相关域的值。
-- @param key 要设置的域。
-- @param value 要设置的相关域对应的值。
-- @return 没有返回。
-- @usage logger.monitorSet("mcssn", mcssn)


function _M.monitorSet4Json(key, value)


monitorFields4Json[key] = value or placeholder4Json


end




function _M.monitor4json()
  
-- 1. 获取文件名
local file = string.format("%s/monitor.json/Nposp_monitor_json.%s", _M.path, os.date("%Y%m%d"))


local f, err = io.open(file, "a")


-- 2. 如果打开文件失败直接返回,如果发现没有日志文件可以检查目录是否存在,还有权限。
if not f then return end


local endTime = os.date("%H:%M:%S")
  monitorFields4Json["logssn"] = _M.id
  monitorFields4Json["trans_start_time"] = startTime
  monitorFields4Json["trans_end_time"] = endTime
    
    
local line = cjson.encode(monitorFields4Json)


line = line .. "\n"


f:write(line)
f:close()
end


return _M

相关内容

    暂无相关文章