statisticLogSrv.lua 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. -- 服务端埋点日志服务
  2. local skynet = require "skynet"
  3. local nodeMgr = require "nodeMgr"
  4. local baseService = require("baseService")
  5. local timeUtil = require "utils.timeUtil"
  6. local serverLogUtil = require "utils.serverLogUtil"
  7. local lib_game_redis = require("lib_game_redis")
  8. local util_record_item = require("utils.util_record_item")
  9. local moduleData = require("data.module")
  10. local SEND_COUNT, ACTIVE_SEND_COUNT
  11. if IS_TEST then
  12. SEND_COUNT, ACTIVE_SEND_COUNT = 2, 10
  13. else
  14. SEND_COUNT, ACTIVE_SEND_COUNT = 50, 100
  15. end
  16. local logQueue = {}
  17. local lTimerLogSync = nil -- 同步日志定时器
  18. local timeSync = 600 * 100
  19. -- 资源变化日志
  20. local itemList = {}
  21. local timerItem = nil
  22. local logAddr
  23. local function l_sned_logs_to_resource(logList)
  24. logAddr = logAddr or nodeMgr.query_node_service_addr("resource", ".server_log")
  25. nodeMgr.send("resource", logAddr, "writeLogList", logList)
  26. end
  27. -- 发送日志
  28. local function l_send_log(stop)
  29. -- 销毁定时器
  30. if lTimerLogSync then
  31. lTimerLogSync.delete()
  32. lTimerLogSync = nil
  33. end
  34. local count = 0
  35. if stop then
  36. count = #logQueue
  37. else
  38. count = math.min(SEND_COUNT, #logQueue)
  39. end
  40. local data = {}
  41. for i = 1, count do
  42. table.insert(data, table.remove(logQueue, 1))
  43. end
  44. if #data <= 0 then
  45. return
  46. end
  47. l_sned_logs_to_resource(data)
  48. end
  49. -- 同步日志
  50. local function l_sync_log_data()
  51. if #logQueue >= SEND_COUNT then
  52. l_send_log()
  53. else
  54. if lTimerLogSync == nil then
  55. lTimerLogSync = create_timeout(timeSync, l_send_log)
  56. end
  57. end
  58. end
  59. -- 写入数据库
  60. local function _write_to_db(stop)
  61. -- 销毁定时器
  62. if timerItem then
  63. timerItem.delete()
  64. timerItem = nil
  65. end
  66. local count = 0
  67. if stop then
  68. count = #itemList
  69. else
  70. count = math.min(SEND_COUNT, #itemList)
  71. end
  72. local list = {}
  73. for i = 1, count do
  74. table.insert(list, table.remove(itemList, 1))
  75. end
  76. if #list <= 0 then
  77. return
  78. end
  79. util_record_item:add_item_record(list)
  80. if #itemList > 0 then
  81. if timerItem == nil then
  82. timerItem = create_timeout(timeSync, _write_to_db)
  83. end
  84. end
  85. end
  86. -- 同步资源日志
  87. local function l_sync_item_data()
  88. if #itemList >= SEND_COUNT then
  89. _write_to_db()
  90. else
  91. if timerItem == nil then
  92. timerItem = create_timeout(timeSync, _write_to_db)
  93. end
  94. end
  95. end
  96. local function l_sync_active_log_data(filename, dataStr)
  97. l_sned_logs_to_resource({{filename = filename, dataStr = dataStr}})
  98. end
  99. local root = {}
  100. function root.add_file_log(key, date, cnt)
  101. local filename = string.format("%s-%s", key, date)
  102. table.insert(logQueue, {filename = filename, dataStr = cnt})
  103. l_sync_log_data()
  104. -- 资源变化
  105. if key == "resource" then
  106. table.insert(itemList, cnt)
  107. l_sync_item_data()
  108. end
  109. end
  110. -- 活跃用户埋点
  111. local bagData = require("data.bag")
  112. local function l_log_user_active(uid, date)
  113. local lastLoginTime = timeUtil.toString(moduleData:hget_int(uid, "player", "lastLoginTime"))
  114. local data = {
  115. date,
  116. uid or 0,
  117. moduleData:get_channel(uid) or "", -- 渠道
  118. bagData:get_item_count(uid, 101), -- 金币持有量
  119. bagData:get_item_count(uid, 102), -- 钻石持有量
  120. lastLoginTime, -- 最后一次登录时间
  121. moduleData:get_nickname(uid)
  122. }
  123. return serverLogUtil.formatData(data)
  124. end
  125. -- 生成活跃用户日志(每日统计)
  126. local function l_log_day_before_active()
  127. local now = skynet_time()
  128. local logDate = timeUtil.toDate(now - 24 * 3600)
  129. local key = serverLogUtil.getActiveKey(logDate)
  130. local uidList = lib_game_redis:smembers(key)
  131. if is_empty(uidList) then
  132. return
  133. end
  134. log.warning("生成活跃用户日志 开始时间:%s", now)
  135. local filename = string.format("user-%s", logDate)
  136. local count, list = 0, {}
  137. for _, uid in ipairs(uidList) do
  138. count = count + 1
  139. local ok, actStr = pcall(l_log_user_active, tonumber(uid), logDate)
  140. if not ok then
  141. log.error("生成活跃用户日志error uid:%s err:%s", uid, actStr)
  142. else
  143. table.insert(list, actStr)
  144. end
  145. if count >= ACTIVE_SEND_COUNT then
  146. l_sync_active_log_data(filename, table.concat(list, "\n"))
  147. count, list = 0, {}
  148. skynet.sleep(10)
  149. end
  150. end
  151. if count > 0 then
  152. l_sync_active_log_data(filename, table.concat(list, "\n"))
  153. end
  154. log.error("生成活跃用户日志 结束时间:%s", skynet_time())
  155. -- 暂时先保存日志
  156. local newKey = string.format("%s:%s", "old", key)
  157. lib_game_redis:rename(key, newKey)
  158. end
  159. local function l_timer_next_day()
  160. -- 生成昨日活跃用户数据
  161. l_log_day_before_active()
  162. local now = skynet_time()
  163. local timeDiff = (timeUtil.getUnixtimeTomorrow() - now) + 60 -- 现在到第二天1分
  164. create_timeout(timeDiff * 100, l_timer_next_day)
  165. end
  166. function root.onStart()
  167. local nodename = skynet.getenv("nodeName")
  168. if nodename == "clientlog" then
  169. -- 每日 0 点在线统计
  170. l_timer_next_day()
  171. end
  172. end
  173. function root.onStop()
  174. l_send_log(true)
  175. end
  176. baseService.start(root, "statisticLog")