From 04f9eaea4935008e5af6c6407c1088929798b983 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=91=E9=A3=8E?= Date: Mon, 13 Aug 2012 14:26:00 +0800 Subject: [PATCH] lua logger --- lualib/log.lua | 87 ++++++++++++ lualib/logger.lua | 320 ++++++++++++++++++++++++++++++++++++++++++++ service/lualog.lua | 44 ++++++ service/main.lua | 4 +- service/testlog.lua | 7 + 5 files changed, 461 insertions(+), 1 deletion(-) create mode 100644 lualib/log.lua create mode 100644 lualib/logger.lua create mode 100644 service/lualog.lua create mode 100644 service/testlog.lua diff --git a/lualib/log.lua b/lualib/log.lua new file mode 100644 index 00000000..2c782b06 --- /dev/null +++ b/lualib/log.lua @@ -0,0 +1,87 @@ +local Logger = require("logger") + +local l = Logger:new() +l.stack_level = l.stack_level + 1 + +local logging = {} + +logging.NOLOG = l.NOLOG +logging.DEBUG = l.DEBUG +logging.INFO = l.INFO +logging.WARNING = l.WARNING +logging.ERROR = l.ERROR +logging.CRITICAL = l.CRITICAL +logging.FATAL = l.FATAL +-- +-- public interface +-- +function logging.Debug(...) + l:Debug(...) +end +function logging.Debugf(format, ...) + l:Debugf(format, ...) +end + +function logging.Info(...) + l:Info(...) +end +function logging.Infof(format, ...) + l:Infof(format, ...) +end + +function logging.Warning(...) + l:Warning(...) +end +function logging.Warningf(format, ...) + l:Warningf(format, ...) +end + +function logging.Error(...) + l:Error(...) +end +function logging.Errorf(format, ...) + l:Errorf(format, ...) +end + +function logging.Critical(...) + l:Critical(...) +end +function logging.Criticalf(format, ...) + l:Criticalf(format, ...) +end + +function logging.Fatal(...) + l:Fatal(...) +end + +function logging.Fatalf(format, ...) + l:Fatalf(format,...) +end + +function logging.Assert(v, message) + return l:Assert(v,message) +end + +function logging.SError(message, level) + level = level and level+1 or 2 + return l:SError(message, level) +end + +function logging.Tag(key, value) + l:Tag(key,value) +end + +function logging.Untag(key) + l:Untag(key) +end + +function logging.set_modname(name) + l:set_modname(name) +end + +function logging.config(t) + l:config(t) +end + +return logging + diff --git a/lualib/logger.lua b/lualib/logger.lua new file mode 100644 index 00000000..48fbffe8 --- /dev/null +++ b/lualib/logger.lua @@ -0,0 +1,320 @@ +local Skynet = require("skynet") +local assert = assert +local error = error +local print = print +local tconcat = table.concat +local tinsert = table.insert +local srep = string.rep +local type = type +local pairs = pairs +local tostring = tostring +local next = next + +local logger = {} + +-- public field +logger.NOLOG = 0 +logger.DEBUG = 10 +logger.INFO = 20 +logger.WARNING = 30 +logger.ERROR = 40 +logger.CRITICAL = 50 +logger.FATAL = 60 + +local function log_to_disk(...) + Skynet.send(".lualog" , Skynet.pack(...)) +end + +local function dump_log_to_disk(t) + for i=1,#t do + log_to_disk(table.unpack(t[i])) + end +end + +-- +-- log helper fun +-- + +local function get_log_src(level) + local info = debug.getinfo(level+1, "Sl") + local src = info.source + return src .. ":" .. info.currentline .. ":" +end + +local starttime = Skynet.starttime() + +local function log_timestamp(timestamp) + local sec = timestamp / 100 + local ms = timestamp % 100 + local f = os.date("%Y-%m-%d %H:%M:%S",starttime + sec) + f = string.format("%s.%02d",f,ms) + return f +end + +local function table_serialize(root) + local cache = { [root] = "." } + local function _dump(t,space,name) + local temp = {} + for k,v in pairs(t) do + local key = tostring(k) + if cache[v] then + tinsert(temp,"+" .. key .. " {" .. cache[v].."}") + elseif type(v) == "table" then + local new_key = name .. "." .. key + cache[v] = new_key + tinsert(temp,"+" .. key .. _dump(v,space .. (next(t,k) and "|" or " " ).. srep(" ",#key),new_key)) + else + tinsert(temp,"+" .. key .. " [" .. tostring(v).."]") + end + end + return tconcat(temp,"\n"..space) + end + return (_dump(root, "","")) +end + +local function log_format(level, ...) + local t = {...} + local out = '' + for _,v in pairs(t) do + if level <= logger.DEBUG and type(v) == "table" then + v_str = "table:" .. table_serialize(v) + else + v_str = tostring(v) + end + + if out == '' then + out = v_str + else + out = out .. "\t" .. v_str + end + end + return out +end + +local function tag_table_to_tags(tag_table) + if tag_table and next(tag_table) then + local tags = {} + for k,v in pairs(tag_table) do + tags[#tags + 1] = k..":"..v + end + return tags + end +end +-- +-- end log helper fun +-- + +-- +-- dump list mgr +-- +local function _lnew(n) + local l = {} + l.tail = 1 + l.len = n + return l +end + +local function _lreset(l) + l.tail = 1 + return l +end + +local function _lpush(l,...) + l[l.tail] = {...} + l[l.tail - l.len] = nil + l.tail = l.tail + 1 +end + +local function _lempty(l) + return l.tail == 1 +end + +local function _lrange(l) + if l.tail <= l.len then + return 1, l.tail-1 + end + + return l.tail - l.len, l.tail-1 +end + +-- +-- end dump list mgr +-- + +function logger:cache(...) + _lpush(self.dump_list,...) +end + +-- 构造符合 lualog 次序的 message, 由 pack_log_message 使用 +function logger:get_log_message(level, timestamp, src, ...) + local msg = log_format(level, ...) + local modname = self.module_name or self.default_module_name + local name = self.logger_name or modname + local timestamp = log_timestamp(timestamp) + return name, modname, level, timestamp,msg, src, tags +end + +function logger:dump() + if _lempty(self.dump_list) then + return + end + + local head, tail = _lrange(self.dump_list) + + local log_message_list = {} + for i= head,tail do + log_message_list[#log_message_list + 1] = {self:get_log_message(table.unpack(self.dump_list[i]))} + end + dump_log_to_disk(log_message_list) + _lreset(self.dump_list) +end + +function logger:log_i(...) + log_to_disk(self:get_log_message(...)) +end + +function logger:log(level, ...) + -- 过滤掉信息的条件:未设置dump_level,且level低于log_level + if self.dump_level == logger.NOLOG and level < self.log_level then + return + end + + local timestamp = Skynet.now() + local src = self.log_src and get_log_src(self.stack_level) or '' + + if level < self.log_level then -- 低于记录级别, 缓存 + self:cache(level, timestamp, src, ...) + else + self:log_i(level, timestamp, src, ...) -- 低于dump级别,直接记录 + if self.dump_level ~= logger.NOLOG and level >= self.dump_level then -- dump缓存 + self:dump() + end + end +end + +-- +-- public interface +-- +function logger:Debug(...) + self:log(logger.DEBUG, ...) +end +function logger:Debugf(format, ...) + self:log(logger.DEBUG, string.format(format, ...)) +end + +function logger:Info(...) + self:log(logger.INFO, ...) +end +function logger:Infof(format, ...) + self:log(logger.INFO, string.format(format, ...)) +end + +function logger:Warning(...) + self:log(logger.WARNING, ...) +end +function logger:Warningf(format, ...) + self:log(logger.WARNING, string.format(format,...)) +end + +function logger:Error(...) + self:log(logger.ERROR, ...) +end +function logger:Errorf(format, ...) + self:log(logger.ERROR, string.format(format,...)) +end + +function logger:Critical(...) + self:log(logger.CRITICAL, ...) +end +function logger:Criticalf(format, ...) + self:log(logger.CRITICAL, string.format(format,...)) +end + +function logger:Fatal(...) + self:log(logger.FATAL, ...) +end + +function logger:Fatalf(format, ...) + self:log(logger.FATAL, string.format(format,...)) +end + +function logger:Assert(v, message) + if not v then + self:log(logger.ERROR, "assert:"..tostring(message)) + end + return assert(v, message) +end + +function logger:SError(message, level) + level = level and level+1 or 2 + self:log(logger.CRITICAL, "error:" .. tostring(message)) + error(message, level) +end + +function logger:Tag(key, value) + self.tag_table[key] = value + self.tags = tag_table_to_tags(tag_table) +end + +function logger:Untag(key) + self.tag_table[key]=nil + self.tags = tag_table_to_tags(self.tag_table) +end + +function logger:set_modname(name) + self.module_name = name +end + +function logger:config(t) + if t["name"] ~= nil then + self.logger_name = t["name"] + end + + if t["module_name"] ~= nil then + self.module_name = t["module_name"] + end + + if t["to_screen"] ~= nil then + self.to_screen = t["to_screen"] + end + + if t["level"] ~= nil then + self.log_level = t["level"] + end + + if t["log_src"] ~= nil then + self.log_src = t["log_src"] + end + + if t["dump_level"] ~= nil then + self.dump_level = t["dump_level"] + end + + if self.dump_level ~= logger.NOLOG then + assert(self.dump_level > self.log_level) + end +end + +function logger:new() + -- private field + local obj = {} + obj.default_module_name = "skynet" + obj.logger_name = nil + obj.module_name = nil + obj.to_screen = true + obj.log_level = logger.DEBUG + obj.log_src = true + obj.dump_level = logger.NOLOG + obj.dump_num = 100 + self.dump_list = _lnew(obj.dump_num) + obj.tag_table = {} + obj.tags = nil + obj.stack_level = 3 + + setmetatable(obj, logger) + logger.__index = logger + return obj +end + +return logger + diff --git a/service/lualog.lua b/service/lualog.lua new file mode 100644 index 00000000..1e60a957 --- /dev/null +++ b/service/lualog.lua @@ -0,0 +1,44 @@ +local skynet = require "skynet" + +local log_level_desc = { + [0] = "NOLOG", + [10] = "DEBUG", + [20] = "INFO", + [30] = "WARNING", + [40] = "ERROR", + [50] = "CRITICAL", + [60] = "FATAL", +} + +-- +-- log object +-- +function log_format(self) + if self.tags and next(self.tags) then + return string.format("[%s %s *%s*] [%s]%s %s", self.timestamp,self.level,self.name,table.concat(self.tags, ","),self.src,self.msg) + else + return string.format("[%s %s *%s*]%s %s", self.timestamp,self.level,self.name,self.src,self.msg) + end +end + +-- +-- end log object +-- + +local function log(name, modname, level, timestamp, msg, src, tags) + print(log_format { + name = name, + modname = modname, + level = log_level_desc[level], + timestamp = timestamp, + msg = msg, + src = src or '', + tags = tags, + }) +end + +skynet.dispatch(function(msg, sz , session , from) + log(skynet.unpack(msg,sz)) +end) + +skynet.register ".lualog" \ No newline at end of file diff --git a/service/main.lua b/service/main.lua index f364f525..a87e9917 100644 --- a/service/main.lua +++ b/service/main.lua @@ -4,6 +4,8 @@ skynet.dispatch() skynet.start(function() print("Server start") + local lualog = skynet.launch("snlua","lualog") + print("lualog",lualog) local launcher = skynet.launch("snlua","launcher") print("launcher", launcher) local console = skynet.launch("snlua","console") @@ -17,4 +19,4 @@ skynet.start(function() local redis = skynet.call(".launcher", "broker .redis snlua redis-cli 127.0.0.1:6379") print("redis",redis) skynet.exit() -end) \ No newline at end of file +end) diff --git a/service/testlog.lua b/service/testlog.lua new file mode 100644 index 00000000..b2d042c4 --- /dev/null +++ b/service/testlog.lua @@ -0,0 +1,7 @@ +local skynet = require "skynet" +local log = require "log" + +skynet.dispatch() + +log.Info("hello world") +