上个项目使用的syslog,发现效果很不错,也希望在skynet中添加syslog模块,顺便也搜索一下使用c为lua编写独立模块。
参考了一下skynet原有crypt模块的代码和lua文档,写的lua-syslog.c如下:
#include <syslog.h>
#include <lua.h>
#include <lauxlib.h>
static int
lsyslog(lua_State *L) {
size_t sz = 0;
const char * text = (const char *)luaL_checklstring(L,1, &sz);
syslog (LOG_INFO, text);
return 0;
}
int
luaopen_syslog(lua_State *L) {
luaL_checkversion(L);
luaL_Reg l[] = {
{ "log", lsyslog },
{ NULL, NULL}
};
luaL_newlib(L,l);
return 1;
}
代码量并不大,非常合适我这种已经N年不写C代码的人。
使用make编译出syslog.so模块,放出的Makefile只供参考,因为和项目目录存放关联密切,并不是直接COPY就可以使用。
PLATS = linux macosx
.PHONY : $(PLATS) all clean skynet
CC ?= gcc
PLAT ?= linux
linux : PLAT = linux
macosx : PLAT = macosx
GSHARED = -fPIC --shared
CFLAGS = -g -O2 -Wall -I$(GLUA_INC)
macosx : GSHARED := -fPIC -dynamiclib -Wl,-undefined,dynamic_lookup
linux macosx :
$(MAKE) all PLAT=$@ GSHARED="$(GSHARED)"
GLUA_INC ?= skynet/3rd/lua
GLUA_CLIB = cjson syslog
GLUA_CLIB_PATH ?= skynet/luaclib
all : skynet \
$(foreach v, $(GLUA_CLIB), $(GLUA_CLIB_PATH)/$(v).so)
$(GLUA_CLIB_PATH)/cjson.so : | $(GLUA_CLIB_PATH)
cd 3rd/lua-cjson && $(MAKE) LUA_INCLUDE_DIR=../../$(GLUA_INC) CC=$(CC) CJSON_LDFLAGS="$(GSHARED)" && cd ../.. && cp 3rd/lua-cjson/cjson.so $@
$(GLUA_CLIB_PATH)/syslog.so : 3rd/lua-syslog/lua-syslog.c | $(GLUA_CLIB_PATH)
$(CC) $(CFLAGS) $(GSHARED) $^ -o $@
skynet :
cd skynet && $(MAKE) CC=$(CC) $(PLAT)
clean :
cd 3rd/lua-cjson && $(MAKE) clean
cd skynet && $(MAKE) CC=$(CC) clean
测试代码:
package.cpath = "luaclib/?.so;"
.. "../luaclib/?.so;"
.. "../../luaclib/?.so;"
.. "../../../luaclib/?.so;"
.. "../../skynet/luaclib/?.so"
local log = require "syslog"
log.log("moon1 hello")
log.log("")
log.log("helloworld")
关于如何打开syslog及查看syslog,就不在这里多累述了,相信了解syslog的朋友已经对此很熟悉了。
如果使用mac os:
使用以下命令停止syslog launchctl unload /System/Library/LaunchDaemons/com.apple.syslogd.plist 使用以下命令启动syslog launchctl unload /System/Library/LaunchDaemons/com.apple.syslogd.plist
接收log的服务上的配置,仅供参考。
$EscapeControlCharactersOnReceive off
$template TraditionalFormat1,"%msg:R,ERE,1,DFLT:[0-9a-zA-Z]+ (.*$)--end%\n"
if re_match($syslogtag,'^game[0-9_a-zA-Z]+\\[[0-9]+\\]') then {
$ActionFileDefaultTemplate TraditionalFormat1
$template DynFile1,"/opt/logs/skynet-log/%syslogtag:R,ERE,1,DFLT:([0-9a-zA-Z]*).*--end%/%timegenerated:1:10:date-rfc3339%/%syslogtag:R,ERE,1,DFLT:([0-9a-zA-Z]*).*--end%-%msg:R,ERE,1,DFLT:([0-9a-zA-Z]+)--end%_%timegenerated:1:10:date-rfc3339%.log"
*.* -?DynFile1
stop
}
后记:
最初想法是直接向本系统的syslog发送消息,然后使用syslog用udp转发至日志服。
进行压力测试时,发现在macos上syslogd有 -mps_limit 限制,默认是500/s, 用户进程默认是36000/小时。超出的消息直接丢弃掉了。
Mar 30 11:01:20 localhost game1[45275]: game moon1 2016-03-30 11:01:20 DEBUG hello world 36039 1459306880.61 Mar 30 11:01:20 localhost game1[45275]: game moon1 2016-03-30 11:01:20 DEBUG hello world 36040 1459306880.61 Mar 30 11:01:20 localhost game1[45275]: *** LOG MESSAGE QUOTA EXCEEDED - SOME MESSAGES FROM THIS PROCESS HAVE BEEN DISCARDED *** Mar 30 11:01:21 localhost game1[45275]: game moon1 2016-03-30 11:01:21 DEBUG hello world 56029 1459306880.99 Mar 30 11:01:21 localhost game1[45275]: game moon1 2016-03-30 11:01:21 DEBUG hello world 56030 1459306880.99
转至linux上测试,也有相同的限制,想想也是合理:
Mar 30 11:18:13 iZu1fh2yq8yZ game1: game moon1 2016-03-30 11:18:13 DEBUG hello world 999 1459307893.8 Mar 30 11:18:13 iZu1fh2yq8yZ game1: game moon1 2016-03-30 11:18:13 DEBUG hello world 1000 1459307893.8 Mar 30 11:18:13 iZu1fh2yq8yZ game1: game moon1 2016-03-30 11:18:13 DEBUG hello world 1001 1459307893.8 Mar 30 11:18:43 iZu1fh2yq8yZ journal: Suppressed 320255 messages from /user.slice/user-0.slice Mar 30 11:18:43 iZu1fh2yq8yZ game1: game moon1 2016-03-30 11:18:43 DEBUG hello world 321257 1459307923.32 Mar 30 11:18:43 iZu1fh2yq8yZ game1: game moon1 2016-03-30 11:18:43 DEBUG hello world 321258 1459307923.32
再测试一下直接使用udp发送至远程日志服务器:
1、查看了一下syslog中并没有提供函数可以直接udp远程进行发送,文档也说的很明白,如果要远程发送需要自己使用tcp或udp发送。
2、查看了一下syslog的udp协议,也很简单,正好skynet中支持udp,连c库都省的写了, http://tools.ietf.org/html/rfc5424
function test3()
local c = socket.udp(function(str, from)
print("client recv", str, socket.udp_address(from))
end)
socket.udp_connect(c, "10.230.10.102", 514)
for i=1,20 do
socket.write(c, "<190>1 2003-10-11T22:14:15.003Z HOSTNAME skynet 11 MESSAGTEID A " .. i) -- write to the address by udp_connect binding
end
end
rsyslog中的系统属性列表:http://www.rsyslog.com/doc/v8-stable/configuration/properties.html
使用udp连续发送100万日志,发送砂时18秒左右。7万/s 日志,可以接受。但发现UDP有丢失包的现象。
内网也会丢包~~,为了确认使用:tcpdump udp port 514 > 1.log 将收到数据包记录下来,然后进行对比,发现,确实在网络一层丢失包。继续测试tcp ~~~
继续改为tcp测试一下。
tcp文献索引:http://tools.ietf.org/html/rfc3164
发送和udp有一点不同,需要在消息结尾附带 \r\n表示一条消息的结束。
测试发现,竟然达到了10万/s 日志的性能,-.-!! 而且没有丢包。
近期评论