diff --git a/.luacheckrc b/.luacheckrc index 8818f09..4ad7b6c 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -16,6 +16,7 @@ globals = { "instanceof", "mixin", "handler", + "fmt", "Property", "Enum", "Option", diff --git a/docs/README.md b/docs/README.md index f9cec89..a220c18 100644 --- a/docs/README.md +++ b/docs/README.md @@ -4,8 +4,15 @@ https://github.com/Tencent/secguide 本地 dns 系统: https://github.com/mafintosh/dns-discovery +100个gdb小技巧 +https://github.com/hellogcc/100-gdb-tips + +Modern Unix Command +https://github.com/ibraheemdev/modern-unix + https://github.com/cloudwu/skynet/issues/288 + 启动服务器流程要理清楚(架构图) 凡是 道具生成都是 一套 掉落系统 diff --git a/framework/lualib-src/Makefile b/framework/lualib-src/Makefile index dac8545..1513ba6 100644 --- a/framework/lualib-src/Makefile +++ b/framework/lualib-src/Makefile @@ -12,6 +12,7 @@ LFLAGS = $(SHARED) -I$(SKYNET_LUA_INC) LUA_CLIB_PATH ?= ../luaclib ##################################################### + LFS_SO = $(LUA_CLIB_PATH)/lfs.so CJSON_SO = $(LUA_CLIB_PATH)/cjson.so PROFILE_SO = $(LUA_CLIB_PATH)/profile.so @@ -27,6 +28,7 @@ TERMFX_SO = $(LUA_CLIB_PATH)/termfx.so RC4_SO = $(LUA_CLIB_PATH)/rc4.so MATH_SO = $(LUA_CLIB_PATH)/math3d.so CFFI_SO = $(LUA_CLIB_PATH)/cffi.so +LSYSLOG_SO = $(LUA_CLIB_PATH)/lsyslog.so ##################################################### @@ -44,6 +46,7 @@ all: $(LFS_SO) \ $(CLUA_SO) \ $(MATH_SO) \ $(CFFI_SO) \ + $(LSYSLOG_SO) \ $(LUASOCKET_SO) ##################################################### @@ -84,6 +87,9 @@ $(MATH_SO): $(CFFI_SO): cd ../3rd/ffi-lua && $(MAKE) PLAT=$(PLAT) +$(LSYSLOG_SO): + cd lua-syslog && $(MAKE) PLAT=$(PLAT) + $(RC4_SO): cd lua-rc4 && $(MAKE) PLAT=$(PLAT) diff --git a/framework/lualib-src/lua-syslog/Makefile b/framework/lualib-src/lua-syslog/Makefile new file mode 100755 index 0000000..fec3cd4 --- /dev/null +++ b/framework/lualib-src/lua-syslog/Makefile @@ -0,0 +1,29 @@ +SKYNET_ROOT ?= ../../skynet +include $(SKYNET_ROOT)/platform.mk + +PLAT ?= none + +TARGET = ../../luaclib/lsyslog.so + +ifeq ($(PLAT), macosx) + CFLAGS = -g -O2 -dynamiclib -Wl,-undefined,dynamic_lookup -std=gnu99 +else +ifeq ($(PLAT), linux) + CFLAGS = -g -O2 -shared -fPIC -std=gnu99 +endif +endif + +LUA_LIB ?= $(SKYNET_ROOT)/3rd/lua/ +LUA_INC ?= $(SKYNET_ROOT)/3rd/lua/ + +SRC = . + +.PHONY: all clean + +all: $(TARGET) + +$(TARGET): $(foreach dir, $(SRC), $(wildcard $(dir)/*.c)) + $(CC) $(CFLAGS) $(SHARED) -I$(LUA_INC) $^ -o $@ + +clean: + rm -f *.o $(TARGET) \ No newline at end of file diff --git a/framework/lualib-src/lua-syslog/lsyslog.c b/framework/lualib-src/lua-syslog/lsyslog.c new file mode 100644 index 0000000..415d363 --- /dev/null +++ b/framework/lualib-src/lua-syslog/lsyslog.c @@ -0,0 +1,102 @@ +// #include + +#include +#include +#include + +#include +#include +#include + + +static int +lsyslog_open(lua_State *L) +{ + static char *persistent_ident = NULL; + const char *ident = luaL_checkstring(L, 1); + int facility = luaL_checkinteger(L, 2); + + if (persistent_ident != NULL) { + free(persistent_ident); + } + + persistent_ident = strdup(ident); + openlog(persistent_ident, LOG_PID, facility); + return 0; +} + +static int +lsyslog_log(lua_State *L) +{ + int level = luaL_checkinteger(L, 1); + const char *line = luaL_checkstring(L, 2); + + syslog(level, "%s", line); + return 0; +} + +static int +lsyslog_close(lua_State *L) +{ + closelog(); + return 0; +} + + +#define set_field(f,v) lua_pushliteral(L, v); \ + lua_setfield(L, -2, f) +#define add_constant(c) lua_pushinteger(L, LOG_##c); \ + lua_setfield(L, -2, #c) + +int +luaopen_lsyslog(lua_State *L) +{ + const luaL_Reg API[] = { + { "open", lsyslog_open }, + { "close", lsyslog_close }, + { "log", lsyslog_log }, + { NULL, NULL } + }; + + luaL_newlib(L, API); + + // set_field("_COPYRIGHT", "Copyright (C) 2014 " PACKAGE_AUTHOR); + // set_field("_DESCRIPTION", PACKAGE_DESCRIPTION); + // set_field("_VERSION", PACKAGE_VERSION); + + lua_newtable(L); + add_constant(AUTH); + add_constant(AUTHPRIV); + add_constant(CRON); + add_constant(DAEMON); + add_constant(FTP); + add_constant(KERN); + add_constant(LOCAL0); + add_constant(LOCAL1); + add_constant(LOCAL2); + add_constant(LOCAL3); + add_constant(LOCAL4); + add_constant(LOCAL5); + add_constant(LOCAL6); + add_constant(LOCAL7); + add_constant(LPR); + add_constant(MAIL); + add_constant(NEWS); + add_constant(SYSLOG); + add_constant(USER); + add_constant(UUCP); + lua_setfield(L, -2, "FACILITY"); + + lua_newtable(L); + add_constant(EMERG); + add_constant(ALERT); + add_constant(CRIT); + add_constant(ERR); + add_constant(WARNING); + add_constant(NOTICE); + add_constant(INFO); + add_constant(DEBUG); + lua_setfield(L, -2, "LEVEL"); + + return 1; +} diff --git a/framework/lualib-src/testluaclib.lua b/framework/lualib-src/testluaclib.lua index b579565..90bed98 100644 --- a/framework/lualib-src/testluaclib.lua +++ b/framework/lualib-src/testluaclib.lua @@ -40,13 +40,13 @@ print("skipset", skipset) local math3d = require "math3d" print("math3d", math3d) -local fmt = require "fmt" -print("fmt", fmt) - local ffi = require("cffi") if ffi.abi("64bit") then assert(ffi.sizeof("void *") == 8) elseif ffi.abi("32bit") then assert(ffi.sizeof("void *") == 4) end -print("ffi", ffi) \ No newline at end of file +print("ffi", ffi) + +local syslog = require 'lsyslog' +print("syslog", syslog) diff --git a/framework/lualib/3rd/oop/fstrings.lua b/framework/lualib/3rd/oop/fstrings.lua new file mode 100644 index 0000000..d35089a --- /dev/null +++ b/framework/lualib/3rd/oop/fstrings.lua @@ -0,0 +1,77 @@ +-- https://github.com/hishamhm/f-strings + +local F = {} + +local load = load + +if _VERSION == "Lua 5.1" then + load = function(code, name, _, env) + local fn, err = loadstring(code, name) + if fn then + setfenv(fn, env) + return fn + end + return nil, err + end +end + +local function scan_using(scanner, arg, searched) + local i = 1 + repeat + local name, value = scanner(arg, i) + if name == searched then + return true, value + end + i = i + 1 + until name == nil + return false +end + +local function snd(_, b) + return b +end + +local function format(_, str) + local outer_env = _ENV and + (snd(scan_using(debug.getlocal, 3, "_ENV")) or + snd(scan_using(debug.getupvalue, debug.getinfo(2, "f").func, "_ENV")) or _ENV) or + getfenv(2) + return (str:gsub("%b{}", function(block) + local code, fmt = block:match("{(.*):(%%.*)}") + code = code or block:match("{(.*)}") + local exp_env = {} + setmetatable(exp_env, { + __index = function(_, k) + local level = 6 + while true do + local funcInfo = debug.getinfo(level, "f") + if not funcInfo then + break + end + local ok, value = scan_using(debug.getupvalue, funcInfo.func, k) + if ok then + return value + end + ok, value = scan_using(debug.getlocal, level + 1, k) + if ok then + return value + end + level = level + 1 + end + return rawget(outer_env, k) + end, + }) + local fn, err = load("return " .. code, "expression `" .. code .. "`", "t", exp_env) + if fn then + return fmt and string.format(fmt, fn()) or tostring(fn()) + else + error(err, 0) + end + end)) +end + +setmetatable(F, { + __call = format, +}) + +return F diff --git a/framework/lualib/3rd/oop/init.lua b/framework/lualib/3rd/oop/init.lua index ca350ee..e77368d 100644 --- a/framework/lualib/3rd/oop/init.lua +++ b/framework/lualib/3rd/oop/init.lua @@ -3,6 +3,7 @@ require "oop.mixin" require "oop.property" require "oop.enum" +fmt = require "oop.fstrings" handler = require "oop.handler" Option = require "oop.option" Try = require "oop.try" \ No newline at end of file diff --git a/framework/lualib/zeus/zlog/console.lua b/framework/lualib/zeus/zlog/console.lua new file mode 100644 index 0000000..731f6d3 --- /dev/null +++ b/framework/lualib/zeus/zlog/console.lua @@ -0,0 +1,23 @@ +------------------------------------------------------------------------------- +-- Prints logging information to console +-- +-- @author Thiago Costa Ponte (thiago@ideais.com.br) +-- +-- @copyright 2004-2021 Kepler Project +-- +------------------------------------------------------------------------------- +local logging = require "zlog.logging" + +function logging.console(params, ...) + params = logging.getDeprecatedParams({"logPattern"}, params, ...) + local logPattern = params.logPattern + local timestampPattern = params.timestampPattern + + return logging.new(function(self, level, message) + io.stdout:write(logging.prepareLogMsg(logPattern, os.date(timestampPattern), level, message)) + return true + end) +end + +return logging.console + diff --git a/framework/lualib/zeus/zlog/file.lua b/framework/lualib/zeus/zlog/file.lua new file mode 100644 index 0000000..a5e23f7 --- /dev/null +++ b/framework/lualib/zeus/zlog/file.lua @@ -0,0 +1,67 @@ +------------------------------------------------------------------------------- +-- Saves logging information in a file +-- +-- @author Thiago Costa Ponte (thiago@ideais.com.br) +-- +-- @copyright 2004-2021 Kepler Project +-- +------------------------------------------------------------------------------- +local logging = require "zlog.logging" + +local lastFileNameDatePattern +local lastFileHandler + +local buffer_mode +do + local dir_separator = _G.package.config:sub(1, 1) + local is_windows = dir_separator == '\\' + if is_windows then + -- Windows does not support "line" buffered mode, see + -- https://github.com/lunarmodules/lualogging/pull/9 + buffer_mode = "no" + else + buffer_mode = "line" + end +end + +local openFileLogger = function(fname, datePattern) + local filename = string.format(fname, os.date(datePattern)) + if (lastFileNameDatePattern ~= filename) then + local f = io.open(filename, "a") + if (f) then + f:setvbuf(buffer_mode) + lastFileNameDatePattern = filename + lastFileHandler = f + return f + else + return nil, string.format("file `%s' could not be opened for writing", filename) + end + else + return lastFileHandler + end +end + +function logging.file(params, ...) + params = logging.getDeprecatedParams({"filename", "datePattern", "logPattern"}, params, ...) + local filename = params.filename + local datePattern = params.datePattern + local logPattern = params.logPattern + local timestampPattern = params.timestampPattern + + if type(filename) ~= "string" then + filename = "zeus.log" + end + + return logging.new(function(self, level, message) + local f, msg = openFileLogger(filename, datePattern) + if not f then + return nil, msg + end + local s = logging.prepareLogMsg(logPattern, os.date(timestampPattern), level, message) + f:write(s) + return true + end) +end + +return logging.file + diff --git a/framework/lualib/zeus/zlog/logging.lua b/framework/lualib/zeus/zlog/logging.lua new file mode 100644 index 0000000..7ee51e0 --- /dev/null +++ b/framework/lualib/zeus/zlog/logging.lua @@ -0,0 +1,251 @@ +------------------------------------------------------------------------------- +-- includes a new tostring function that handles tables recursively +-- +-- @author Danilo Tuler (tuler@ideais.com.br) +-- @author Andre Carregal (info@keplerproject.org) +-- @author Thiago Costa Ponte (thiago@ideais.com.br) +-- +-- @copyright 2004-2021 Kepler Project +------------------------------------------------------------------------------- +local type, table, string, _tostring, tonumber = type, table, string, tostring, tonumber +local select = select +local error = error +local format = string.format +local pairs = pairs +local ipairs = ipairs + +local logging = { + -- Meta information + _COPYRIGHT = "Copyright (C) 2004-2021 Kepler Project", + _DESCRIPTION = "A simple API to use logging features in Lua", + _VERSION = "LuaLogging 1.5.1", +} + +local LEVELS = {"DEBUG", "INFO", "WARN", "ERROR", "FATAL", "OFF"} +local MAX_LEVELS = #LEVELS +for i, level in ipairs(LEVELS) do + LEVELS[level] = i + logging[level] = level +end + +local function rewrite_stacktrace() + -- prettify stack-trace, remove lualogging entries and reformat to 1 line + local result = '' + local trace = debug.traceback() + for entry in trace:gmatch("%s*(.-)\n") do + if entry:match("%:%d+%:") and not entry:find('logging.lua') then + result = result .. ' | ' .. entry + end + end + return result +end + +-- private log function, with support for formating a complex log message. +local function LOG_MSG(self, level, fmt, ...) + local f_type = type(fmt) + if f_type == 'string' then + if select('#', ...) > 0 then + local status, msg = pcall(format, fmt, ...) + if status then + return self:append(level, msg) + else + return self:append(level, "Error formatting log message: " .. msg .. rewrite_stacktrace()) + end + else + -- only a single string, no formating needed. + return self:append(level, fmt) + end + elseif f_type == 'function' then + -- fmt should be a callable function which returns the message to log + return self:append(level, fmt(...)) + end + -- fmt is not a string and not a function, just call tostring() on it. + return self:append(level, logging.tostring(fmt)) +end + +-- do nothing function for disabled levels. +local function disable_level() +end + +-- a generic print function that prints to the log +local function print_to_log(logger, level, ...) + local args = { + n = select("#", ...), + ..., + } + for i = 1, args.n do + args[i] = _tostring(args[i]) + end + args = table.concat(args, " ") .. "\n" + for line in args:gmatch("(.-)\n") do + logger:log(level, line) + end +end + +-- improved assertion function. +local function assert(exp, ...) + -- if exp is true, we are finished so don't do any processing of the parameters + if exp then + return exp, ... + end + -- assertion failed, raise error + error(format(...), 2) +end + +------------------------------------------------------------------------------- +-- Creates a new logger object +-- @param append Function used by the logger to append a message with a +-- log-level to the log stream. +-- @return Table representing the new logger object. +-- @return String if there was any error setting the custom levels if provided +------------------------------------------------------------------------------- +function logging.new(append) + if type(append) ~= "function" then + return nil, "Appender must be a function." + end + + local LEVEL_FUNCS = {} + + local logger = {} + logger.append = append + + logger.setLevel = function(self, level) + local order = LEVELS[level] + assert(order, "undefined level '%s'", _tostring(level)) + local old_level = self.level + self.level = level + self.level_order = order + -- enable/disable levels + for i = 1, MAX_LEVELS do + local name = LEVELS[i]:lower() + if i >= order and i ~= MAX_LEVELS then + self[name] = LEVEL_FUNCS[i] + else + self[name] = disable_level + end + end + if old_level and old_level ~= level then + self:log(LEVELS[1], "Logger: changing loglevel from %s to %s", old_level, level) + end + end + + -- generic log function. + logger.log = function(self, level, ...) + local order = LEVELS[level] + assert(order, "undefined level `%s'", _tostring(level)) + if order < self.level_order then + return + end + return LOG_MSG(self, level, ...) + end + + -- a print function generator + logger.getPrint = function(self, level) + local order = LEVELS[level] + assert(order, "undefined level `%s'", _tostring(level)) + return function(...) + if order >= self.level_order then + print_to_log(self, level, ...) + end + end + end + + -- create the proxy functions for each log level. + for i = 1, MAX_LEVELS do + local level = LEVELS[i] + if logger[level:lower()] then + return nil, "'" .. level .. "' is not a proper level name since there is already a property '" .. + level:lower() .. "'" + end + LEVEL_FUNCS[i] = function(self, ...) + -- no level checking needed here, this function will only be called if it's level is active. + return LOG_MSG(self, level, ...) + end + end + + -- insert log level constants + for i = 1, MAX_LEVELS do + logger[LEVELS[i]] = LEVELS[i] + end + + -- initialize log level. + logger:setLevel(LEVELS[1]) + return logger +end + +------------------------------------------------------------------------------- +-- Prepares the log message +------------------------------------------------------------------------------- +function logging.prepareLogMsg(pattern, dt, level, message) + local logMsg = pattern or "%date %level %message\n" + message = string.gsub(message, "%%", "%%%%") + logMsg = string.gsub(logMsg, "%%date", dt) + logMsg = string.gsub(logMsg, "%%level", level) + logMsg = string.gsub(logMsg, "%%message", message) + return logMsg +end + +------------------------------------------------------------------------------- +-- Converts a Lua value to a string +-- +-- Converts Table fields in alphabetical order +------------------------------------------------------------------------------- +local function tostring(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, tostring(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 = tostring(value[tonumber(fieldName)]) + else + entry = fieldName .. " = " .. tostring(value[fieldName]) + end + str = str .. separator .. entry + separator = ", " + end + str = str .. '}' + end + return str +end +logging.tostring = tostring + +------------------------------------------------------------------------------- +-- Backward compatible parameter handling +------------------------------------------------------------------------------- +function logging.getDeprecatedParams(lst, ...) + local args = { + n = select("#", ...), + ..., + } + if type(args[1]) == "table" then + -- this is the new format of a single params-table + return args[1] + end + + local params = {} + for i, param_name in ipairs(lst) do + params[param_name] = args[i] + end + return params +end + +return logging diff --git a/framework/lualib/zeus/zlog/rolling_file.lua b/framework/lualib/zeus/zlog/rolling_file.lua new file mode 100644 index 0000000..d9d3198 --- /dev/null +++ b/framework/lualib/zeus/zlog/rolling_file.lua @@ -0,0 +1,89 @@ +--------------------------------------------------------------------------- +-- RollingFileAppender is a FileAppender that rolls over the logfile +-- once it has reached a certain size limit. It also mantains a +-- maximum number of log files. +-- +-- @author Tiago Cesar Katcipis (tiagokatcipis@gmail.com) +-- +-- @copyright 2004-2021 Kepler Project +--------------------------------------------------------------------------- +local logging = require "zlog.logging" + +local buffer_mode +do + local dir_separator = _G.package.config:sub(1, 1) + local is_windows = dir_separator == '\\' + if is_windows then + -- Windows does not support "line" buffered mode, see + -- https://github.com/lunarmodules/lualogging/pull/9 + buffer_mode = "no" + else + buffer_mode = "line" + end +end + +local function openFile(self) + self.file = io.open(self.filename, "a") + if not self.file then + return nil, string.format("file `%s' could not be opened for writing", self.filename) + end + self.file:setvbuf(buffer_mode) + return self.file +end + +local rollOver = function(self) + for i = self.maxIndex - 1, 1, -1 do + -- files may not exist yet, lets ignore the possible errors. + os.rename(self.filename .. "." .. i, self.filename .. "." .. i + 1) + end + + self.file:close() + self.file = nil + + local _, msg = os.rename(self.filename, self.filename .. "." .. "1") + + if msg then + return nil, string.format("error %s on log rollover", msg) + end + + return openFile(self) +end + +local openRollingFileLogger = function(self) + if not self.file then + return openFile(self) + end + + local filesize = self.file:seek("end", 0) + + if (filesize < self.maxSize) then + return self.file + end + + return rollOver(self) +end + +function logging.rolling_file(params, ...) + params = logging.getDeprecatedParams({"filename", "maxFileSize", "maxBackupIndex", "logPattern"}, params, ...) + local logPattern = params.logPattern + local timestampPattern = params.timestampPattern + + local obj = { + filename = type(params.filename) == "string" and params.filename or "lualogging.log", + maxSize = params.maxFileSize, + maxIndex = params.maxBackupIndex or 1, + } + + return logging.new(function(self, level, message) + local f, msg = openRollingFileLogger(obj) + if not f then + return nil, msg + end + local s = logging.prepareLogMsg(logPattern, os.date(timestampPattern), level, message) + f:write(s) + return true + end) +end + +return logging.rolling_file + diff --git a/framework/lualib/zeus/zlog/syslog.lua b/framework/lualib/zeus/zlog/syslog.lua new file mode 100644 index 0000000..d94563e --- /dev/null +++ b/framework/lualib/zeus/zlog/syslog.lua @@ -0,0 +1,26 @@ +local logging = require 'zlog.logging' + +function logging.syslog(ident, facility) + local lsyslog = require 'lsyslog' + + local convert = { + [logging.DEBUG] = lsyslog.LEVEL.DEBUG, + [logging.INFO] = lsyslog.LEVEL.INFO, + [logging.WARN] = lsyslog.LEVEL.WARNING, + [logging.ERROR] = lsyslog.LEVEL.ERR, + [logging.FATAL] = lsyslog.LEVEL.ALERT, + } + + if type(ident) ~= 'string' then + ident = 'lua' + end + + lsyslog.open(ident, facility or lsyslog.FACILITY.USER) + + return logging.new(function(self, level, message) + lsyslog.log(convert[level] or lsyslog.LEVEL.ERR, message) + return true + end) +end + +return logging.syslog