stat.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /**
  2. * @class UniStatDataStat uni统计-数据统计调度处理模块
  3. * @function cron 数据统计定时任务处理函数
  4. * @function stat 数据统计调度处理函数
  5. * @function cleanLog 日志清理调度处理函数
  6. */
  7. const {
  8. DateTime
  9. } = require('./lib')
  10. const {
  11. sleep
  12. } = require('../shared')
  13. const {
  14. BaseMod,
  15. SessionLog,
  16. PageLog,
  17. EventLog,
  18. ShareLog,
  19. ErrorLog,
  20. StatResult,
  21. ActiveDevices,
  22. ActiveUsers,
  23. PageResult,
  24. EventResult,
  25. ErrorResult,
  26. Loyalty,
  27. RunErrors,
  28. UserSessionLog
  29. } = require('./mod')
  30. class UniStatDataStat {
  31. /**
  32. * 数据统计定时任务处理函数
  33. * @param {Object} context 服务器请求上下文参数
  34. */
  35. async cron(context) {
  36. const baseMod = new BaseMod()
  37. const dateTime = new DateTime()
  38. console.log('Cron start time: ', dateTime.getDate('Y-m-d H:i:s'))
  39. //获取运行参数
  40. const timeInfo = dateTime.getTimeInfo(null, false)
  41. const cronConfig = baseMod.getConfig('cron')
  42. const cronMin = baseMod.getConfig('cronMin')
  43. const realtimeStat = baseMod.getConfig('realtimeStat')
  44. // 数据跑批
  45. let res = null
  46. if (cronConfig && cronConfig.length > 0) {
  47. for (var mi in cronConfig) {
  48. const cronType = cronConfig[mi].type
  49. const cronTime = cronConfig[mi].time.split(' ')
  50. //未开启分钟级定时任务,则设置为小时级定时任务
  51. if (cronTime.length === 4 && !cronMin) {
  52. cronTime.splice(3, 1)
  53. }
  54. if (baseMod.debug) {
  55. console.log('cronTime', cronTime)
  56. }
  57. //精度为分钟级的定时任务
  58. if (cronTime.length === 4) {
  59. if (cronTime[0] !== '*') {
  60. //周统计任务
  61. if (timeInfo.nWeek == cronTime[0] && timeInfo.nHour == cronTime[2] && timeInfo.nMinutes ==
  62. cronTime[3]) {
  63. console.log(cronType + '--week run')
  64. res = await this.stat({
  65. type: cronType,
  66. dimension: 'week'
  67. })
  68. }
  69. } else if (cronTime[1] !== '*') {
  70. //月统计任务
  71. if (timeInfo.nDay == cronTime[1] && timeInfo.nHour == cronTime[2] && timeInfo.nMinutes ==
  72. cronTime[3]) {
  73. console.log(cronType + '--month run')
  74. res = await this.stat({
  75. type: cronType,
  76. dimension: 'month'
  77. })
  78. }
  79. } else if (cronTime[2] !== '*') {
  80. //日统计任务
  81. if (timeInfo.nHour == cronTime[2] && timeInfo.nMinutes == cronTime[3]) {
  82. console.log(cronType + '--day run')
  83. res = await this.stat({
  84. type: cronType,
  85. dimension: 'day'
  86. })
  87. }
  88. } else if (cronTime[3] !== '*') {
  89. //实时统计任务
  90. if (timeInfo.nMinutes == cronTime[3] && realtimeStat) {
  91. console.log(cronType + '--hour run')
  92. res = await this.stat({
  93. type: cronType,
  94. dimension: 'hour'
  95. })
  96. }
  97. }
  98. }
  99. //精度为小时级的定时任务
  100. else if (cronTime.length === 3) {
  101. if (cronTime[0] !== '*') {
  102. //周统计任务
  103. if (timeInfo.nWeek == cronTime[0] && timeInfo.nHour == cronTime[2]) {
  104. console.log(cronType + '--week run')
  105. res = await this.stat({
  106. type: cronType,
  107. dimension: 'week'
  108. })
  109. }
  110. } else if (cronTime[1] !== '*') {
  111. //月统计任务
  112. if (timeInfo.nDay == cronTime[1] && timeInfo.nHour == cronTime[2]) {
  113. console.log(cronType + '--month run')
  114. res = await this.stat({
  115. type: cronType,
  116. dimension: 'month'
  117. })
  118. }
  119. } else if (cronTime[2] !== '*') {
  120. //日统计任务
  121. if (timeInfo.nHour == cronTime[2]) {
  122. console.log(cronType + '--day run')
  123. res = await this.stat({
  124. type: cronType,
  125. dimension: 'day'
  126. })
  127. }
  128. } else {
  129. //实时统计任务
  130. if (realtimeStat) {
  131. console.log(cronType + '--hour run')
  132. res = await this.stat({
  133. type: cronType,
  134. dimension: 'hour'
  135. })
  136. }
  137. }
  138. } else {
  139. console.error('Cron configuration error')
  140. }
  141. }
  142. }
  143. console.log('Cron end time: ', dateTime.getDate('Y-m-d H:i:s'))
  144. return {
  145. code: 0,
  146. msg: 'Task have done',
  147. lastCronResult: res
  148. }
  149. }
  150. /**
  151. * 数据统计调度处理函数
  152. * @param {Object} params 统计参数
  153. */
  154. async stat(params) {
  155. const {
  156. type,
  157. dimension,
  158. date,
  159. reset
  160. } = params
  161. let res = {
  162. code: 0,
  163. msg: 'success'
  164. }
  165. try {
  166. switch (type) {
  167. // 基础统计
  168. case 'stat': {
  169. const resultStat = new StatResult()
  170. res = await resultStat.stat(dimension, date, reset)
  171. break
  172. }
  173. // 活跃设备统计归集
  174. case 'active-device': {
  175. const activeDevices = new ActiveDevices()
  176. res = await activeDevices.stat(date, reset)
  177. break
  178. }
  179. // 活跃用户统计归集
  180. case 'active-user': {
  181. const activeUsers = new ActiveUsers()
  182. res = await activeUsers.stat(date, reset)
  183. break
  184. }
  185. // 设备留存统计
  186. case 'retention-device': {
  187. const retentionStat = new StatResult()
  188. res = await retentionStat.retentionStat(dimension, date)
  189. break
  190. }
  191. // 用户留存统计
  192. case 'retention-user': {
  193. const retentionStat = new StatResult()
  194. res = await retentionStat.retentionStat(dimension, date, 'user')
  195. break
  196. }
  197. // 页面统计
  198. case 'page': {
  199. const pageStat = new PageResult()
  200. res = await pageStat.stat(dimension, date, reset)
  201. break
  202. }
  203. // 事件统计
  204. case 'event': {
  205. const eventStat = new EventResult()
  206. res = await eventStat.stat(dimension, date, reset)
  207. break
  208. }
  209. // 错误统计
  210. case 'error': {
  211. const errorStat = new ErrorResult()
  212. res = await errorStat.stat(dimension, date, reset)
  213. break
  214. }
  215. // 设备忠诚度统计
  216. case 'loyalty': {
  217. const loyaltyStat = new Loyalty()
  218. res = await loyaltyStat.stat(dimension, date, reset)
  219. break
  220. }
  221. // 日志清理
  222. case 'clean': {
  223. res = await this.cleanLog()
  224. }
  225. }
  226. } catch (e) {
  227. const maxTryTimes = 2
  228. if (!this.tryTimes) {
  229. this.tryTimes = 1
  230. } else {
  231. this.tryTimes++
  232. }
  233. //报错则重新尝试2次, 解决部分云服务器偶现连接超时问题
  234. if (this.tryTimes <= maxTryTimes) {
  235. //休眠1秒后重新调用
  236. sleep(1000)
  237. params.reset = true
  238. res = await this.stat(params)
  239. } else {
  240. // 2次尝试失败后记录错误
  241. console.error('server error: ' + e)
  242. const runError = new RunErrors()
  243. runError.create({
  244. mod: 'stat',
  245. params: params,
  246. error: e,
  247. create_time: new DateTime().getTime()
  248. })
  249. res = {
  250. code: 500,
  251. msg: 'server error' + e
  252. }
  253. }
  254. }
  255. return res
  256. }
  257. /**
  258. * 日志清理调度处理函数
  259. */
  260. async cleanLog() {
  261. const baseMod = new BaseMod()
  262. const cleanLog = baseMod.getConfig('cleanLog')
  263. if (!cleanLog || !cleanLog.open) {
  264. return {
  265. code: 100,
  266. msg: 'The log cleanup service has not been turned on'
  267. }
  268. }
  269. const res = {
  270. code: 0,
  271. msg: 'success',
  272. data: {}
  273. }
  274. // 会话日志
  275. if (cleanLog.reserveDays.sessionLog > 0) {
  276. const sessionLog = new SessionLog()
  277. res.data.sessionLog = await sessionLog.clean(cleanLog.reserveDays.sessionLog)
  278. }
  279. // 用户会话日志
  280. if (cleanLog.reserveDays.userSessionLog > 0) {
  281. const userSessionLog = new UserSessionLog()
  282. res.data.userSessionLog = await userSessionLog.clean(cleanLog.reserveDays.userSessionLog)
  283. }
  284. // 页面日志
  285. if (cleanLog.reserveDays.pageLog > 0) {
  286. const pageLog = new PageLog()
  287. res.data.pageLog = await pageLog.clean(cleanLog.reserveDays.pageLog)
  288. }
  289. // 事件日志
  290. if (cleanLog.reserveDays.eventLog > 0) {
  291. const eventLog = new EventLog()
  292. res.data.eventLog = await eventLog.clean(cleanLog.reserveDays.eventLog)
  293. }
  294. // 分享日志
  295. if (cleanLog.reserveDays.shareLog > 0) {
  296. const shareLog = new ShareLog()
  297. res.data.shareLog = await shareLog.clean(cleanLog.reserveDays.shareLog)
  298. }
  299. // 错误日志
  300. if (cleanLog.reserveDays.errorLog > 0) {
  301. const errorLog = new ErrorLog()
  302. res.data.errorLog = await errorLog.clean(cleanLog.reserveDays.errorLog)
  303. }
  304. // 活跃设备日志
  305. const activeDevicesLog = new ActiveDevices()
  306. res.data.activeDevicesLog = await activeDevicesLog.clean()
  307. // 活跃用户日志
  308. const activeUsersLog = new ActiveUsers()
  309. res.data.activeUsersLog = await activeUsersLog.clean()
  310. // 实时统计日志
  311. const resultHourLog = new StatResult()
  312. res.data.resultHourLog = await resultHourLog.cleanHourLog()
  313. //原生应用崩溃日志
  314. const appCrashLogs = new AppCrashLogs()
  315. res.data.appCrashLogs = await appCrashLogs.clean()
  316. return res
  317. }
  318. }
  319. module.exports = UniStatDataStat