Commit df883a114d53e40339eded5e5d209566565812ce
1 parent
cfeb432d
日志处理
Showing
2 changed files
with
228 additions
and
126 deletions
Show diff stats
src/models/RoleLog.lua
1 | 1 | |
2 | - | |
3 | --- logType 日志 mapping 信息(确定后不能更改类型) 修改需要设置 es 日志mapping | |
4 | - | |
5 | - | |
6 | - | |
2 | +-- logType | |
7 | 3 | local LogType = { |
8 | - create = { | |
9 | - ip = "string" | |
10 | - }, | |
11 | - login = { | |
12 | - ip = "string" | |
13 | - }, | |
14 | - logout = { | |
15 | - online = "number" | |
16 | - }, | |
17 | - | |
4 | + create = "common", | |
5 | + login = "common", | |
6 | + logout = "common", | |
18 | 7 | } |
19 | 8 | |
9 | +-- 如要修改 要提前修改 _template mapping -- 对应 mapping 为 gamelog-* | |
10 | +local Mapping = { | |
11 | + -- 预留一些数据格式 | |
12 | + common = { | |
13 | + desc = "keyword",--索引的短字符串 | |
14 | + ucode = "keyword",--关联日志对应ucode | |
15 | + key1 = "keyword", --可索引的短字符串 | |
16 | + key2 = "keyword", --可索引的短字符串 | |
17 | + -- 几乎不用的长文本 | |
18 | + text1 = "text", --长字符串不索引的类型 | |
19 | + -- 五个不同类型的数字 基本上满足数量要求 尽量从低到高用 | |
20 | + short1 = "short", | |
21 | + int1 = "integer", | |
22 | + int2 = "integer", | |
23 | + long1 = "long", | |
24 | + float1 = "float", | |
25 | + } | |
26 | +} | |
20 | 27 | |
21 | --- 所有的日志都包括的部分 role 里面的信息 | |
22 | -local commonField = { | |
23 | - name = "string", | |
24 | - id = "number", | |
25 | - uid = "string", | |
26 | - sId = "number", | |
27 | - device = "string", | |
28 | - ctime = "number", | |
29 | - ltime = "number", | |
30 | - level = "number", | |
31 | - rmbC = "number", | |
28 | +-- 所有的日志都包括的部分 role 里面的信息 -- mapping 信息在 gamelog-role | |
29 | +local commonRoleField = { | |
30 | + name = "keyword", | |
31 | + id = "integer", | |
32 | + uid = "keyword", | |
33 | + sid = "short", | |
34 | + device = "keyword", | |
35 | + ctime = "integer", | |
36 | + ltime = "integer", | |
37 | + level = "short", | |
38 | + rmbC = "integer", | |
32 | 39 | } |
33 | 40 | |
34 | -local RoleLog = {} | |
35 | 41 | |
36 | -function RoleLog.bind(Role) | |
42 | +local function checkType(logType, field, value, ctype) | |
43 | + local typecheckfunc = { | |
44 | + keyword = function() | |
45 | + --长度不超过256 | |
46 | + if type(value) ~= "string" then | |
47 | + value = tostring(value) | |
48 | + print(string.format("LOG ERROR: logType [%s] field [%s] isn't [keyword]", logType, field)) | |
49 | + else | |
50 | + if #value > 256 then | |
51 | + print(string.format("LOG ERROR: logType [%s] field [%s] [keyword] type to long.", logType, field)) | |
52 | + end | |
53 | + end | |
54 | + return value | |
55 | + end, | |
56 | + text = function() | |
57 | + if type(value) ~= "string" then | |
58 | + value = tostring(value) | |
59 | + print(string.format("LOG ERROR: logType [%s] field [%s] isn't [text]", logType, field)) | |
60 | + end | |
61 | + return value | |
62 | + end, | |
63 | + integer = function() | |
64 | + if type(value) ~= "number" then | |
65 | + value = tonumber(value) | |
66 | + print(string.format("LOG ERROR: logType [%s] field [%s] isn't [integer]", logType, field)) | |
67 | + end | |
68 | + if value then | |
69 | + if math.type(value) ~= "integer" then | |
70 | + local oldValue = value | |
71 | + value = math.floor(value) | |
72 | + if value ~= oldValue then | |
73 | + print(string.format("LOG ERROR: logType [%s] field [%s] isn't [integer], is float", logType, field)) | |
74 | + end | |
75 | + end | |
76 | + if -2147483648 > value or value > 2147483647 then | |
77 | + value = nil | |
78 | + print(string.format("LOG ERROR: logType [%s] field [%s] isn't [integer], too big", logType, field)) | |
79 | + end | |
80 | + end | |
81 | + return value | |
82 | + end, | |
83 | + short = function() | |
84 | + if type(value) ~= "number" then | |
85 | + value = tonumber(value) | |
86 | + print(string.format("LOG ERROR: logType [%s] field [%s] isn't [short]", logType, field)) | |
87 | + end | |
88 | + if value then | |
89 | + if math.type(value) ~= "integer" then | |
90 | + local oldValue = value | |
91 | + value = math.floor(value) | |
92 | + if value ~= oldValue then | |
93 | + print(string.format("LOG ERROR: logType [%s] field [%s] isn't [short], is float", logType, field)) | |
94 | + end | |
95 | + end | |
96 | + | |
97 | + if -32768 > value or value > 32768 then | |
98 | + value = nil | |
99 | + print(string.format("LOG ERROR: logType [%s] field [%s] isn't [short], too big", logType, field)) | |
100 | + end | |
101 | + end | |
102 | + return value | |
103 | + end, | |
104 | + long = function() | |
105 | + if type(value) ~= "number" then | |
106 | + value = tonumber(value) | |
107 | + print(string.format("LOG ERROR: logType [%s] field [%s] isn't [long]", logType, field)) | |
108 | + end | |
109 | + if value then | |
110 | + if math.type(value) ~= "integer" then | |
111 | + local oldValue = value | |
112 | + value = math.floor(value) | |
113 | + if type(value) ~= "integer" then | |
114 | + value = nil | |
115 | + print(string.format("LOG ERROR: logType [%s] field [%s] isn't [long], too big", logType, field)) | |
116 | + elseif value ~= oldValue then | |
117 | + print(string.format("LOG ERROR: logType [%s] field [%s] isn't [long], is float", logType, field)) | |
118 | + end | |
119 | + end | |
120 | + end | |
121 | + return value | |
122 | + end, | |
123 | + float = function() | |
124 | + if type(value) ~= "number" then | |
125 | + value = tonumber(value) | |
126 | + print(string.format("LOG ERROR: logType [%s] field [%s] isn't [float]", logType, field)) | |
127 | + end | |
128 | + return value | |
129 | + end, | |
130 | + } | |
131 | + | |
132 | + if typecheckfunc[ctype] then | |
133 | + return typecheckfunc[ctype]() | |
134 | + else | |
135 | + print(string.format("LOG ERROR: logType [%s] field [%s] have a new type [%s] need add check.", logType, field, ctype)) | |
136 | + return nil | |
137 | + end | |
138 | +end | |
37 | 139 | |
140 | +local RoleLog = {} | |
141 | +function RoleLog.bind(Role) | |
38 | 142 | function Role:log(logType, contents) |
39 | - | |
40 | - local _logType = LogType[logType] | |
41 | - if not _logType then return end | |
42 | - | |
43 | - | |
44 | - if not logd then return end | |
45 | - | |
46 | 143 | contents = contents or {} |
144 | + local _logType = LogType[logType] | |
145 | + if not _logType then | |
146 | + print(string.format("LOG ERROR: new logType [%s] need Add Maping.", logType)) | |
147 | + return | |
148 | + end | |
47 | 149 | local doc = {} |
48 | - for field, _typ in pairs(commonField) do | |
49 | - doc[field] = self:getProperty(field) | |
150 | + for field, ctype in pairs(commonRoleField) do | |
151 | + if contents[field] then | |
152 | + print(string.format("LOG ERROR: logType [%s] had field [%s] overwrite default.", logType, field)) | |
153 | + end | |
154 | + doc[field] = checkType("commonRoleField", field, self:getProperty(field), ctype) | |
50 | 155 | end |
156 | + | |
157 | + local mapping = Mapping[_logType] | |
158 | + | |
51 | 159 | for field, value in pairs(contents) do |
52 | - if _logType[field] then | |
53 | - doc[field] = value | |
160 | + local ftype = mapping[field] | |
161 | + if ftype then | |
162 | + doc[field] = checkType(logType, field, value, ftype) | |
54 | 163 | else |
55 | - print(string.format("LOG ERROR: %s had new field %s no type.", logType, field)) | |
164 | + print(string.format("LOG ERROR: logType [%s] have new field [%s] no type in mapping.", logType, field)) | |
56 | 165 | end |
57 | 166 | end |
58 | - | |
59 | - doc.mid = doc.uid:sub(-2, -1) | |
60 | - pcall(skynet.send, logd, "lua", "log", logType, doc) | |
167 | + if not logd then return end | |
168 | + pcall(skynet.send, logd, "lua", "log", logType, doc, _logType) | |
61 | 169 | end |
62 | - | |
63 | 170 | end |
64 | - | |
65 | 171 | return RoleLog |
66 | 172 | \ No newline at end of file | ... | ... |
src/services/logd.lua
1 | 1 | local skynet = require "skynet" |
2 | -local mongo = require "mongo" | |
3 | 2 | local queue = require "skynet.queue" |
4 | 3 | local bson = require "bson" |
5 | -local socketdriver = require "socketdriver" | |
4 | +local socketdriver = require "skynet.socketdriver" | |
6 | 5 | |
7 | 6 | local serverId = tonumber(skynet.getenv("servId")) |
8 | 7 | |
... | ... | @@ -14,105 +13,102 @@ local pairs = pairs |
14 | 13 | local ipairs = ipairs |
15 | 14 | local string_format = string.format |
16 | 15 | |
17 | -local CMD, cache, client, cs = {}, {} | |
18 | -local auto = {} | |
19 | - | |
20 | -local rsyslog_fd | |
21 | - | |
22 | --- function getNextSequence(collect) | |
23 | --- local index = auto[collect] | |
24 | --- if not index then | |
25 | --- local res = client.counters:findAndModify({ | |
26 | --- query = {}, | |
27 | --- update = {["$inc"] = {[collect] = 1}}, | |
28 | --- upsert = true, | |
29 | --- new = true, | |
30 | --- }) | |
31 | --- index = res.value[collect] | |
32 | --- else | |
33 | --- index = index + 1 | |
34 | --- end | |
35 | --- auto[collect] = index | |
36 | --- return index | |
37 | --- end | |
38 | - | |
39 | -local dateTypes = {"timestamp", "createTime", "lastLoginTime"} | |
40 | -local stringTypes = {"s1", "s2", "s3"} | |
41 | -local intTypes = {"int1", "int2", "int3", "int4"} | |
42 | -function CMD.log(collect, doc) | |
43 | - -- write to rsyslog | |
44 | - local now = skynet.timex() | |
45 | - doc["timestamp"] = now | |
46 | - doc["server"] = serverId | |
16 | +local CMD, cs = {} | |
17 | +local log_fd, connecting = nil , false | |
18 | + | |
19 | + | |
20 | +local socket_message = {} | |
21 | +-- read skynet_socket.h for these macro | |
22 | +-- SKYNET_SOCKET_TYPE_DATA = 1 | |
23 | +socket_message[1] = function(id, size, data) | |
24 | + skynet.error(string.format("LOG SOCKET: data: ", skynet.tostring(data, size))) | |
25 | + socketdriver.drop(data, size) | |
26 | +end | |
27 | + | |
28 | +-- SKYNET_SOCKET_TYPE_CONNECT = 2 | |
29 | +socket_message[2] = function(id, _ , addr) | |
30 | + skynet.error("LOG SOCKET: connect: ", addr) | |
31 | + connecting = false | |
32 | +end | |
33 | + | |
34 | +-- SKYNET_SOCKET_TYPE_CLOSE = 3 | |
35 | +socket_message[3] = function(id) | |
36 | + skynet.error("LOG SOCKET: closed") | |
37 | + connecting = false | |
38 | +end | |
39 | + | |
40 | +-- SKYNET_SOCKET_TYPE_ERROR = 5 | |
41 | +socket_message[5] = function(id, _, err) | |
42 | + skynet.error("LOG SOCKET: error: ", err) | |
43 | + connecting = false | |
44 | +end | |
47 | 45 | |
48 | - for _, field in pairs(stringTypes) do | |
49 | - if doc[field] then | |
50 | - doc[field] = tostring(doc[field]) | |
46 | + | |
47 | +skynet.register_protocol { | |
48 | + name = "socket", | |
49 | + id = skynet.PTYPE_SOCKET, -- PTYPE_SOCKET = 6 | |
50 | + unpack = socketdriver.unpack, | |
51 | + dispatch = function (_, _, t, ...) | |
52 | + if socket_message[t] then | |
53 | + socket_message[t](...) | |
51 | 54 | end |
52 | 55 | end |
53 | - for _, field in pairs(intTypes) do | |
54 | - if doc[field] then | |
55 | - doc[field] = tonumber(doc[field]) | |
56 | +} | |
57 | + | |
58 | + | |
59 | + | |
60 | +-- 日志 index 不包含 日期的 index_suffix | |
61 | +local IndexNoDate = { | |
62 | + online = true, | |
63 | +} | |
64 | +-- 不走 role log 的日志都要自行注意 mapping 设置【重要】 | |
65 | +-- index_suffix index 后缀 默认为 common | |
66 | +function CMD.log(logType, doc, index_suffix) | |
67 | + index_suffix = index_suffix or "common" | |
68 | + if index_suffix == "common" then | |
69 | + doc["@type"] = logType | |
70 | + else | |
71 | + if logType ~= index_suffix then -- 定制后缀 不一定有type 不相等时才有type | |
72 | + doc["@type"] = logType | |
56 | 73 | end |
57 | 74 | end |
58 | - for _, field in pairs(dateTypes) do | |
59 | - if doc[field] then | |
60 | - doc[field .. "_t"] = tonumber(os.date("%Y%m%d%H%M%S", doc[field])) | |
75 | + | |
76 | + local now = skynet.timex() | |
77 | + doc["timestamp"] = now | |
78 | + doc["@timestamp"] = os.date("%Y-%m-%d %H:%M:%S", now) | |
79 | + doc["server"] = serverId | |
80 | + | |
81 | + -- 自己加好 index | |
82 | + if IndexNoDate[index_suffix] then | |
83 | + doc["@index"] = string.format("gamelog-%s", index_suffix) | |
84 | + else | |
85 | + doc["@index"] = string.format("gamelog-%s-%s", os.date("%Y%m%d", now), index_suffix) | |
86 | + end | |
87 | + if not socketdriver.send(log_fd, json.encode(doc) .. "\n") then | |
88 | + if not connecting then | |
89 | + CMD.open() -- 连一下试试 | |
61 | 90 | end |
62 | 91 | end |
63 | - -- Local-6 + Info | |
64 | - socketdriver.send(rsyslog_fd, string.format("<182>%s: %s\n", collect, json.encode(doc))) | |
65 | - | |
66 | - -- if not cache[collect] then cache[collect] = {} end | |
67 | - -- doc["timestamp"] = now | |
68 | - -- doc["_id"] = getNextSequence(collect) | |
69 | - -- table_insert(cache[collect], doc) | |
70 | 92 | end |
71 | 93 | |
72 | -function CMD.open(conf) | |
73 | - rsyslog_fd = socketdriver.connect("127.0.0.1", 514) | |
74 | - socketdriver.start(rsyslog_fd) | |
75 | - | |
76 | - -- local db = mongo.client { | |
77 | - -- host = conf.mongohost, | |
78 | - -- port = conf.mongoport or 27017, | |
79 | - -- username = conf.mongouser, | |
80 | - -- password = conf.mongopswd, | |
81 | - -- } | |
82 | - | |
83 | - -- assert(db, "mongo connect error") | |
84 | - | |
85 | - -- local servId = skynet.getenv "servId" | |
86 | - -- client = db["s"..servId] | |
94 | +function CMD.open() | |
95 | + log_fd = socketdriver.connect("127.0.0.1", 5170) | |
96 | + connecting = true | |
87 | 97 | end |
88 | 98 | |
89 | --- local function __loop__() | |
90 | --- while true do | |
91 | --- cs(function () | |
92 | --- for col, docs in pairs(cache) do | |
93 | --- client[col]:batch_insert(docs) | |
94 | --- client.counters:update({}, {["$set"]={[col]=auto[col]}}) | |
95 | --- end | |
96 | --- cache = {} | |
97 | --- end) | |
98 | --- skynet.sleep(200) | |
99 | --- end | |
100 | --- end | |
101 | - | |
102 | 99 | local function __init__() |
103 | - skynet.dispatch("lua", function (_, _, command, ...) | |
100 | + skynet.dispatch("lua", function (session, address, command, ...) | |
104 | 101 | local f = CMD[command] |
105 | 102 | if command == "open" then |
106 | 103 | skynet.ret(skynet.pack(f(...))) |
107 | 104 | else |
108 | - local collect, doc = ... | |
109 | - cs(function() f(collect, doc) end) | |
105 | + local logType, doc, index_suffix = ... | |
106 | + cs(function() f(logType, doc, index_suffix) end) | |
110 | 107 | end |
111 | 108 | end) |
112 | 109 | cs = queue() |
113 | 110 | |
114 | - -- skynet.fork(__loop__) | |
115 | - skynet.register "LOGD" | |
111 | + skynet.register(".LOGD") | |
116 | 112 | end |
117 | 113 | |
118 | 114 | skynet.start(__init__) | ... | ... |