您的位置:首页 > 编程语言 > Lua

lua实现详细日志记录

2016-10-27 09:46 253 查看
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  lua openresty nginx linux