文章目录
概述
日志模块主要用于格式化输出程序日志,方便后续从日志中定位程序运行过程中出现的问题。当然日志除了日志内容本身之外,还应该包括文件名、行号、时间戳、线程、协程号、日志级别等信息。在输出错误日志时,还应附加程序的函数调用栈信息,便于后续分析和排查问题。
日志系统一般分为 5 个等级:
- DEBUG :调试用的日志,线上运行时屏蔽不输出
- INFO :普通日志,线上运行时输出,流程的关键步骤都需要有 INFO 日志
- WARN :数据异常,但不影响正常流程的时候输出
- ERROR :数据异常,且需要人工处理的时候输出
- FATAL :致命错误, 将会导致应用程序的退出。
基本配置
-- config
logger = "./skynet.log" --日志输出的目录文件
logservice = "logger" --默认为 “logger” 如果配置 "snlua "可使用Lua定制日志服务
使用Lua定制日志服务
注 : 修改自 Veinin/skynet-logger
-- config
logger = "logger" --日志输出的目录文件
logservice = "snlua" --默认为 “logger” 如果配置 "snlua "可使用Lua定制日志服务
logpath = "./log/" --日志存放的目录路径
loggroup = "test" -- 日志文件分组名
-- lualib/log.lua
local skynet = require "skynet"
local log = {}
local LOG_LEVEL = {
DEBUG = 1,
INFO = 2,
WARN = 3,
ERROR = 4,
FATAL = 5
}
local OUT_PUT_LEVEL = LOG_LEVEL.DEBUG
local LOG_LEVEL_DESC = {
[1] = "DEBUG",
[2] = "INFO",
[3] = "WARN",
[4] = "ERROR",
[5] = "FATAL",
}
local function format(fmt, ...)
local ok, str = pcall(string.format, fmt, ...)
if ok then
return str
else
return "error format : " .. fmt
end
end
local function send_log(level, ...)
if level < OUT_PUT_LEVEL then
return
end
local str
if select("#", ...) == 1 then
str = tostring(...)
else
str = format(...)
end
local info = debug.getinfo(3)
if info then
local filename = string.match(info.short_src, "[^/.]+.lua$")
str = string.format("[%s:%d] %s", filename, info.currentline, str)
end
skynet.send(".logger", "lua", "logging", LOG_LEVEL_DESC[level], str)
end
function log.debug(fmt, ...)
send_log(LOG_LEVEL.DEBUG, fmt, ...)
end
function log.info(fmt, ...)
send_log(LOG_LEVEL.INFO, fmt, ...)
end
function log.warn(fmt, ...)
send_log(LOG_LEVEL.WARN, fmt, ...)
end
function log.error(fmt, ...)
send_log(LOG_LEVEL.ERROR, fmt, ...)
end
function log.fatal(fmt, ...)
send_log(LOG_LEVEL.FATAL, fmt, ...)
end
return log
-- service/logger.lua
local skynet = require "skynet"
require "skynet.manager"
local last_hour = -1
local log_path = skynet.getenv("logpath")
local log_file = nil
local log_group = skynet.getenv("loggroup")
local is_daemon = skynet.getenv("daemon") ~= nil
local function check_exists(path)
if not os.rename(path, path) then
os.execute("mkdir " .. path)
end
end
local function file_path(date)
if log_group ~= nil then
return string.format("%s%s_%04d-%02d-%02d-%02d.log", log_path, log_group,
date.year, date.month, date.day, date.hour)
else
return string.format("%s%04d-%02d-%02d-%02d.log", log_path,
date.year, date.month, date.day, date.hour)
end
end
local function open_file(date)
check_exists(log_path)
if log_file then
log_file:close()
log_file = nil
end
local f, e = io.open(file_path(date), "a")
if not f then
print("logger error:", tostring(e))
return
end
log_file = f
last_hour = date.hour
end
local function log_time(date)
return string.format("%02d:%02d:%02d.%02d", date.hour, date.min, date.sec,
math.floor(skynet.time()*100%100))
end
local CMD = {}
function CMD.logging(source, type, str)
local date = os.date("*t")
str = string.format("[:%08x][%s][%s]%s", source, type, log_time(date), str)
if not log_file or date.hour ~= last_hour then
open_file(date)
end
log_file:write(str .. '\n')
log_file:flush()
if not is_daemon then
print(str)
end
end
skynet.register_protocol {
name = "text",
id = skynet.PTYPE_TEXT,
unpack = skynet.tostring,
dispatch = function(_, source, msg)
CMD.logging(source, "DEBUG", msg)
end
}
skynet.register_protocol {
name = "SYSTEM",
id = skynet.PTYPE_SYSTEM,
unpack = function(...) return ... end,
dispatch = function(_, source)
-- reopen signal
print("SIGHUP")
CMD.logging(source, "FATAL", "SIGHUP")
end
}
skynet.start(function()
skynet.register(".logger")
skynet.dispatch("lua", function(_, source, cmd, ...)
local f = assert(CMD[cmd], cmd .. " not found")
f(source, ...)
end)
end)
-- service/main.lua
local skynet = require "skynet"
local log = require "log"
skynet.start(function()
--初始化
log.debug("Value of Pi = %f", math.pi)
log.debug("Value of Pi = 3.14159")
log.debug("debug")
log.info("info")
log.warn("warn")
log.error("error")
log.fatal("fatal")
--退出自身
skynet.exit()
end)
最后打印日志结果
每行日志信息为:[服务ID][日志等级][日志输出时间(精确到毫秒级别)][日志输出文件名:文件行数] 日志内容,如下面一行行日志信息: