stat.js 10 KB

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