stat.js 9.5 KB

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