NGTools/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/errorResult.js
ldeyun 9dbfdc6c71 V1.0.0
微信小程序运行成功;
H5运行成功
2024-09-30 01:30:39 +08:00

460 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @class ErrorResult 错误结果统计模型
*/
const BaseMod = require('./base')
const Platform = require('./platform')
const Channel = require('./channel')
const Version = require('./version')
const ErrorLog = require('./errorLog')
const AppCrashLogs = require('./appCrashLogs')
const SessionLog = require('./sessionLog')
const {
DateTime
} = require('../lib')
module.exports = class ErrorResult extends BaseMod {
constructor() {
super()
this.tableName = 'error-result'
this.platforms = []
this.channels = []
this.versions = []
this.errors = []
}
/**
* 错误结果统计
* @param {String} type 统计类型 hour实时统计 day按天统计week按周统计 month按月统计
* @param {Date|Time} date 指定日期或时间戳
* @param {Boolean} reset 是否重置为ture时会重置该批次数据
*/
async stat(type, date, reset) {
//前端js错误统计
const resJs = await this.statJs(type, date, reset)
//原生应用崩溃错误统计
const resCrash = await this.statCrash(type, date, reset)
return {
code: 0,
msg: 'success',
data: {
resJs,
resCrash
}
}
}
/**
* 前端js错误结果统计
* @param {String} type 统计类型 hour实时统计 day按天统计week按周统计 month按月统计
* @param {Date|Time} date 指定日期或时间戳
* @param {Boolean} reset 是否重置为ture时会重置该批次数据
*/
async statJs(type, date, reset) {
const allowedType = ['day']
if (!allowedType.includes(type)) {
return {
code: 1002,
msg: 'This type is not allowed'
}
}
this.fillType = type
const dateTime = new DateTime()
const dateDimension = dateTime.getTimeDimensionByType(type, -1, date)
this.startTime = dateDimension.startTime
this.endTime = dateDimension.endTime
if (this.debug) {
console.log('dimension time', this.startTime + '--' + this.endTime)
}
// 查看当前时间段日志是否已存在,防止重复生成
if (!reset) {
const checkRes = await this.getCollection(this.tableName).where({
type: 'js',
start_time: this.startTime,
end_time: this.endTime
}).get()
if (checkRes.data.length > 0) {
console.log('error log have existed')
return {
code: 1003,
msg: 'This log have existed'
}
}
} else {
const delRes = await this.delete(this.tableName, {
type: 'js',
start_time: this.startTime,
end_time: this.endTime
})
console.log('delete old data result:', JSON.stringify(delRes))
}
// 数据获取
this.errorLog = new ErrorLog()
const statRes = await this.aggregate(this.errorLog.tableName, {
project: {
appid: 1,
version: 1,
platform: 1,
channel: 1,
error_hash: 1,
create_time: 1
},
match: {
create_time: {
$gte: this.startTime,
$lte: this.endTime
}
},
group: {
_id: {
appid: '$appid',
version: '$version',
platform: '$platform',
channel: '$channel',
error_hash: '$error_hash'
},
error_count: {
$sum: 1
}
},
sort: {
error_count: 1
},
getAll: true
})
let res = {
code: 0,
msg: 'success'
}
if (this.debug) {
console.log('statRes', JSON.stringify(statRes))
}
if (statRes.data.length > 0) {
this.fillData = []
for (const i in statRes.data) {
await this.fillJs(statRes.data[i])
}
if (this.fillData.length > 0) {
res = await this.batchInsert(this.tableName, this.fillData)
}
}
return res
}
/**
* 前端js错误统计结果数据填充
* @param {Object} data 数据集合
*/
async fillJs(data) {
// 平台信息
let platformInfo = null
if (this.platforms && this.platforms[data._id.platform]) {
//暂存下数据,减少读库
platformInfo = this.platforms[data._id.platform]
} else {
const platform = new Platform()
platformInfo = await platform.getPlatformAndCreate(data._id.platform, null)
if (!platformInfo || platformInfo.length === 0) {
platformInfo._id = ''
}
this.platforms[data._id.platform] = platformInfo
if (this.debug) {
console.log('platformInfo', JSON.stringify(platformInfo))
}
}
// 渠道信息
let channelInfo = null
const channelKey = data._id.appid + '_' + platformInfo._id + '_' + data._id.channel
if (this.channels && this.channels[channelKey]) {
channelInfo = this.channels[channelKey]
} else {
const channel = new Channel()
channelInfo = await channel.getChannelAndCreate(data._id.appid, platformInfo._id, data._id.channel)
if (!channelInfo || channelInfo.length === 0) {
channelInfo._id = ''
}
this.channels[channelKey] = channelInfo
if (this.debug) {
console.log('channelInfo', JSON.stringify(channelInfo))
}
}
// 版本信息
let versionInfo = null
const versionKey = data._id.appid + '_' + data._id.platform + '_' + data._id.version
if (this.versions && this.versions[versionKey]) {
versionInfo = this.versions[versionKey]
} else {
const version = new Version()
versionInfo = await version.getVersionAndCreate(data._id.appid, data._id.platform, data._id.version)
if (!versionInfo || versionInfo.length === 0) {
versionInfo._id = ''
}
this.versions[versionKey] = versionInfo
if (this.debug) {
console.log('versionInfo', JSON.stringify(versionInfo))
}
}
// 错误信息
let errorInfo = null
if (this.errors && this.errors[data._id.error_hash]) {
errorInfo = this.errors[data._id.error_hash]
} else {
const cacheKey = 'uni-stat-errors-' + data._id.error_hash
errorInfo = await this.getCache(cacheKey)
if (!errorInfo) {
errorInfo = await this.getCollection(this.errorLog.tableName).where({
error_hash: data._id.error_hash
}).limit(1).get()
if (!errorInfo || errorInfo.data.length === 0) {
errorInfo.error_msg = ''
} else {
errorInfo = errorInfo.data[0]
await this.setCache(cacheKey, errorInfo)
}
}
this.errors[data._id.error_hash] = errorInfo
}
// 最近一次报错时间
const matchCondition = data._id
Object.assign(matchCondition, {
create_time: {
$gte: this.startTime,
$lte: this.endTime
}
})
const lastErrorLog = await this.getCollection(this.errorLog.tableName).where(matchCondition).orderBy(
'create_time', 'desc').limit(1).get()
let lastErrorTime = ''
if (lastErrorLog && lastErrorLog.data.length > 0) {
lastErrorTime = lastErrorLog.data[0].create_time
}
//数据填充
const datetime = new DateTime()
const insertParams = {
appid: data._id.appid,
platform_id: platformInfo._id,
channel_id: channelInfo._id,
version_id: versionInfo._id,
type: 'js',
hash: data._id.error_hash,
msg: errorInfo.error_msg,
count: data.error_count,
last_time: lastErrorTime,
dimension: this.fillType,
stat_date: datetime.getDate('Ymd', this.startTime),
start_time: this.startTime,
end_time: this.endTime
}
this.fillData.push(insertParams)
return insertParams
}
/**
* 原生应用错误结果统计
* @param {String} type 统计类型 hour实时统计 day按天统计week按周统计 month按月统计
* @param {Date|Time} date 指定日期或时间戳
* @param {Boolean} reset 是否重置为ture时会重置该批次数据
*/
async statCrash(type, date, reset) {
const allowedType = ['day']
if (!allowedType.includes(type)) {
return {
code: 1002,
msg: 'This type is not allowed'
}
}
this.fillType = type
const dateTime = new DateTime()
const dateDimension = dateTime.getTimeDimensionByType(type, -1, date)
this.startTime = dateDimension.startTime
this.endTime = dateDimension.endTime
if (this.debug) {
console.log('dimension time', this.startTime + '--' + this.endTime)
}
// 查看当前时间段日志是否已存在,防止重复生成
if (!reset) {
const checkRes = await this.getCollection(this.tableName).where({
type: 'crash',
start_time: this.startTime,
end_time: this.endTime
}).get()
if (checkRes.data.length > 0) {
console.log('error log have existed')
return {
code: 1003,
msg: 'This log have existed'
}
}
} else {
const delRes = await this.delete(this.tableName, {
type: 'crash',
start_time: this.startTime,
end_time: this.endTime
})
console.log('delete old data result:', JSON.stringify(delRes))
}
// 数据获取
this.crashLogs = new AppCrashLogs()
const statRes = await this.aggregate(this.crashLogs.tableName, {
project: {
appid: 1,
version: 1,
platform: 1,
channel: 1,
create_time: 1
},
match: {
create_time: {
$gte: this.startTime,
$lte: this.endTime
}
},
group: {
_id: {
appid: '$appid',
version: '$version',
platform: '$platform',
channel: '$channel'
},
error_count: {
$sum: 1
}
},
sort: {
error_count: 1
},
getAll: true
})
let res = {
code: 0,
msg: 'success'
}
if (this.debug) {
console.log('statRes', JSON.stringify(statRes))
}
if (statRes.data.length > 0) {
this.fillData = []
for (const i in statRes.data) {
await this.fillCrash(statRes.data[i])
}
if (this.fillData.length > 0) {
res = await this.batchInsert(this.tableName, this.fillData)
}
}
return res
}
async fillCrash(data) {
// 平台信息
let platformInfo = null
if (this.platforms && this.platforms[data._id.platform]) {
//暂存下数据,减少读库
platformInfo = this.platforms[data._id.platform]
} else {
const platform = new Platform()
platformInfo = await platform.getPlatformAndCreate(data._id.platform, null)
if (!platformInfo || platformInfo.length === 0) {
platformInfo._id = ''
}
this.platforms[data._id.platform] = platformInfo
if (this.debug) {
console.log('platformInfo', JSON.stringify(platformInfo))
}
}
// 渠道信息
let channelInfo = null
data._id.channel = data._id.channel ? data._id.channel : '1001'
const channelKey = data._id.appid + '_' + platformInfo._id + '_' + data._id.channel
if (this.channels && this.channels[channelKey]) {
channelInfo = this.channels[channelKey]
} else {
const channel = new Channel()
channelInfo = await channel.getChannelAndCreate(data._id.appid, platformInfo._id, data._id.channel)
if (!channelInfo || channelInfo.length === 0) {
channelInfo._id = ''
}
this.channels[channelKey] = channelInfo
if (this.debug) {
console.log('channelInfo', JSON.stringify(channelInfo))
}
}
// 版本信息
let versionInfo = null
const versionKey = data._id.appid + '_' + data._id.platform + '_' + data._id.version
if (this.versions && this.versions[versionKey]) {
versionInfo = this.versions[versionKey]
} else {
const version = new Version()
versionInfo = await version.getVersionAndCreate(data._id.appid, data._id.platform, data._id.version)
if (!versionInfo || versionInfo.length === 0) {
versionInfo._id = ''
}
this.versions[versionKey] = versionInfo
if (this.debug) {
console.log('versionInfo', JSON.stringify(versionInfo))
}
}
//app启动次数
const sessionLog = new SessionLog()
const sessionTimesRes = await this.getCollection(sessionLog.tableName).where({
appid: data._id.appid,
version: data._id.version,
platform: data._id.platform,
channel: data._id.channel,
create_time: {
$gte: this.startTime,
$lte: this.endTime
}
}).count()
let sessionTimes = 0
if(sessionTimesRes && sessionTimesRes.total > 0) {
sessionTimes = sessionTimesRes.total
} else {
console.log('Not found session logs')
return false
}
//数据填充
const datetime = new DateTime()
const insertParams = {
appid: data._id.appid,
platform_id: platformInfo._id,
channel_id: channelInfo._id,
version_id: versionInfo._id,
type: 'crash',
count: data.error_count,
app_launch_count: sessionTimes,
dimension: this.fillType,
stat_date: datetime.getDate('Ymd', this.startTime),
start_time: this.startTime,
end_time: this.endTime
}
this.fillData.push(insertParams)
return insertParams
}
}