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
--[[
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
相关文章推荐
- 使用Aop面向切面技术实现记录详细操作日志功能
- Python实现日志自动记录功能(一个思路代码,详细可以自己扩展)
- 命令批处理实现对3389登录的日志记录
- JavaScript中AOP的实现和日志记录
- 日志记录组件[Log4net]详细介绍(转)
- 日志模块(一头文件就实现了日志记录)
- 日志记录组件[Log4net]详细介绍(转)
- log4j配置相对路径实现日志记录
- spring2.x使用aop实现声明式日志记录
- 在绑定控件中查询一条记录的详细信息的实现方法
- 日志记录组件[Log4net]详细介绍(转)
- C# 实现记录每个线程log日志
- 利用MSMQ实现高并发情况下快速日志和异常记录
- 日志记录组件[Log4net]详细介绍
- 装饰者模式---使用装饰者模式实现带日志记录功能的数据库命令执行类
- 日志记录组件[Log4net]详细介绍(转)
- 利用触发器实现日志记录
- 日志记录组件[Log4net]详细介绍(转)
- 如何覆盖PB的系统函数 比如Messagebox 以记录Messagebox错误日志 或者实现MESSAGEBOX信息的翻译
- MySQL用触发器实现日志记录