我的学习笔记 Good Luck To You!

[引擎] 4.4 XOpenServer Log模块 设计及实现

一、log的作用
    程序中良好地记录log日志是非常重要的,一般log日志有一下几方面作用:
1、显示运行中的重要数据状态,如定时记录用户在线数量;
2、用于bug排查,特别是在游戏或应用已经上线的情况下,我们是无法断点调试程序,那么只能通过log来分析,适当的log有利于我们分析问题的所在, 另外一方面, 过多的log又会影响服务器的正常运作,所以适当的加log也是一门学问
3、记录玩家或用户的操作,即运营日志,方便以后做数据分析,以及用户反馈有记录可循,最后也有助于bug排查。
二、程序log的层级设计
    服务器的log要分清层级关系,可以根据不同的层级显示不同的内容,并且可以在必要的时候通过设置参数来控制是否输出log。
log层级包括
LogError:严重错误,必须修复,如个别数据错乱导致程序进入一些本不应该执行的位置
LogWarming:警告,非必修的bug但需要尽量避免, 如协议参数错误
LogInfo:普通信息输出
LogDebug:调试信息,调试信息是最多,最频繁的,一般在上线运营的时候会全部屏蔽,以免频繁的io操作导致服务器卡顿。
三、LuaLog模块的设计及实现
需要注意的问题:
    1、程序log和运营log要分开,因为两者存在的目的不同。程序log主要是用以bug排查,运营log则是做数据分析。
    2、程序log一般会比较多,所以一般会周期性新建一个log文件,或者log文件记录大于x条新建log文件。
    3、程序log中LogError以及LogWarming一般是比较重要的日志,同时也相对LogDebug算比较少的, 所以LogError以及LogWarming输出堆栈是比较合适的,LogInfo和LogDebug则不需要输出堆栈。
    4、记录运营log,一般每一条记录都会记录一些用户的重要基础数据,如操作时间,操作时的等级,金钱等。
以下是具体的实现:
一开始我这样实现
local LogFile = {}
function OpenLogFile(filename)
    if not filename then return end
    if LogFile[filename] then return LogFile[filename] end
    local errMsg
    LogFile[filename], errMsg = io.open(filename, "w+")
    if not LogFile[filename] then print("Open log file fail", errMsg) end
    return LogFile[filename]
end
function CloseLogFile(filename)
    if not LogFile[filename] then return end
    LogFile[filename]:close()
end
function WriteLog(filename, msg)
    if not LogFile[filename] then 
        if not OpenLogFile(filename) then
            return
        end
    end
    local result, errMsg, errNo
    result, errMsg, errNo = LogFile[filename]:write(msg)
    if not result then 
        print("Write log error!", errMsg, errNo)
        return 
    end
    result, errMsg, errNo = LogFile[filename]:flush()
    if not result then print("flush log error!", errMsg, errNo) end
end
其实上面这个基本功能也算可以用了, 不过考虑到应该支持周期性或者log文件记录大于x条新建一个log文件, 我将上面的代码改成以下代码。
-- 计算下一天时间
local function CalcNextDay()
    local t = os.date("*t", CURRENT_TIME)
    t.hour = 0
    t.min = 0
    t.sec = 0
    return os.time(t) + 3600*24
end
------------------------------------------------------------------
local LogFileList = {}
-- 初始化log文件
function CreateLogFile(keyname, path, filename, maxcount)
    if not keyname or not filename then return end
    if LogFileList[keyname] then return end
    local logFile = {}
    logFile.keyname = keyname
    logFile.path = path
    logFile.filename = filename
    logFile.maxcount = maxcount
    logFile.count = 0
    logFile.refreshTime = CalcNextDay()
    logFile.currFullName = path .. filename .. "_" .. os.date("%Y%m%d%H%M%S") .. ".log"
    LogFileList[keyname] = logFile
    OpenLogFile(keyname)
    return true
end
-- 打开log文件
function OpenLogFile(keyname)
    local logFile = LogFileList[keyname]
    if not logFile then return end
    if logFile.file then logFile.file:close() end
    logFile.refreshTime = CalcNextDay()
    logFile.currFullName = logFile.path .. logFile.filename .. "_" .. os.date("%Y%m%d%H%M%S") .. ".log"
    local errMsg
    logFile.file, errMsg = io.open(logFile.currFullName, "w+")
    if not logFile.file then print("Open log file fail", errMsg) end
    return logFile.file
end
-- 关闭
function CloseLogFile(keyname)
    local logFile = LogFileList[keyname]
    if not logFile then return end
    if logFile.file then logFile.file:close() end
end
-- 检查是否要新建文件
function CheckLogFile(keyname)
    local logFile = LogFileList[keyname]
    if not logFile then return end
    -- 一天刷新一次
    if logFile.refreshTime <= CURRENT_TIME then OpenLogFile(keyname) end
    -- 数据超过最大行数
    if logFile.maxcount and logFile.count >= logFile.maxcount then OpenLogFile(keyname) end
end
-- 写文件
function WriteLog(keyname, msg)
    local logFile = LogFileList[keyname]
    if not logFile then return print("file is not init ", msg) end
    CheckLogFile(keyname)
    local result, errMsg, errNo
    result, errMsg, errNo = logFile.file:write(msg)
    if not result then 
        print("Write log error!", errMsg, errNo)
        return 
    end
    logFile.count = logFile.count + 1
    result, errMsg, errNo = logFile.file:flush()
    if not result then print("flush log error!", errMsg, errNo) end
end
-- log 屏幕输出+文件输出
function LogAndPrint(keyname, level, f, ...)
    --if not DEBUG then return end
    if not keyname or not f then return end
    local msg1 = string.format(f, ...)
    print(msg1)
    local msg = "[" .. os.date("%X", os.time()) .. "]["..level.."] " .. msg1 .. "\n"
    WriteLog(keyname, msg)
end
------------------------------------------------------------------
-- 程序日志
CreateLogFile("programlog", PROGRAM_LOG_PATH , SERVER_NAME .. ServerID, LOGS_COUNT_MAX)
-- 打印堆栈
function Trace()
    --if not DEBUG then return end
    LogAndPrint("programlog", "TRACE", debug.traceback())
end
function LogDebug(f, ...)
    if not DEBUG then return end
    LogAndPrint("programlog", "DEBUG", f, ...)
end
function LogInfo(f, ...)
    LogAndPrint("programlog", "INFO", f, ...)
end
function LogWARNING(f, ...)
    LogAndPrint("programlog", "WARNING", f, ...)
    Trace()
end
function LogERROR(f, ...)
    LogAndPrint("programlog", "ERROR", f, ...)
    Trace()
end
-- 输出堆栈
function LogTrace(f, ...)
    if not DEBUG then return end
    LogAndPrint("programlog", "TRACE", f, ...)
    Trace()
end
项目版本地址:


作者:东风 分类:未分类 浏览:170 评论:0