befly 3.24.18 → 3.24.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apis/admin/cacheRefresh.js +2 -2
- package/apis/dashboard/environmentInfo.js +6 -1
- package/apis/dashboard/performanceMetrics.js +11 -8
- package/apis/dashboard/serviceStatus.js +78 -60
- package/apis/tongJi/cacheHealth.js +214 -0
- package/apis/tongJi/errorReport.js +72 -1
- package/apis/tongJi/errorStats.js +160 -5
- package/apis/tongJi/fallbackReset.js +69 -0
- package/apis/tongJi/infoReport.js +116 -16
- package/apis/tongJi/infoStats.js +160 -68
- package/apis/tongJi/onlineReport.js +14 -23
- package/apis/tongJi/onlineStats.js +94 -91
- package/hooks/permission.js +6 -2
- package/hooks/rateLimit.js +245 -0
- package/lib/cacheHelper.js +105 -60
- package/lib/redisHelper.js +68 -0
- package/lib/requestMetrics.js +203 -0
- package/package.json +2 -2
- package/plugins/email.js +6 -2
- package/router/api.js +7 -0
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { getDateYmdNumber } from "#root/utils/datetime.js";
|
|
2
2
|
|
|
3
3
|
const ERROR_STATS_DAY_LIMIT = 30;
|
|
4
|
+
const ERROR_STATS_FALLBACK_COUNT_KEY = "stats:fallback:errorStats:count";
|
|
5
|
+
const ERROR_STATS_FALLBACK_DAILY_COUNT_KEY_PREFIX = "stats:fallback:errorStats:count:day:";
|
|
6
|
+
const ERROR_STATS_FALLBACK_TTL_SECONDS = 7 * 24 * 60 * 60;
|
|
7
|
+
|
|
8
|
+
function getErrorStatsFallbackDailyCountKey(bucketDate) {
|
|
9
|
+
return `${ERROR_STATS_FALLBACK_DAILY_COUNT_KEY_PREFIX}${bucketDate}`;
|
|
10
|
+
}
|
|
4
11
|
|
|
5
12
|
function toNumber(value) {
|
|
6
13
|
const num = Number(value);
|
|
@@ -35,6 +42,144 @@ function getErrorStatsRecentDateList(now = Date.now(), limit = ERROR_STATS_DAY_L
|
|
|
35
42
|
return list;
|
|
36
43
|
}
|
|
37
44
|
|
|
45
|
+
function getErrorStatsPeriodCountKey(periodType, periodValue) {
|
|
46
|
+
return `error:${periodType}:${periodValue}:count`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function getErrorStatsDayBucketsKey(bucketDate) {
|
|
50
|
+
return `error:day:${bucketDate}:buckets`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function getErrorStatsDayBucketCountKey(bucketDate, bucketTime) {
|
|
54
|
+
return `error:day:${bucketDate}:bucket:${bucketTime}:count`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function getErrorStatsDayTypesKey(bucketDate) {
|
|
58
|
+
return `error:day:${bucketDate}:types`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function getErrorStatsDayTypeCountKey(bucketDate, errorType) {
|
|
62
|
+
return `error:day:${bucketDate}:type:${encodeURIComponent(String(errorType || "unknown"))}:count`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function getErrorStatsRedisSummary(befly, periodType, periodValue) {
|
|
66
|
+
return {
|
|
67
|
+
count: toNumber(await befly.redis.getString(getErrorStatsPeriodCountKey(periodType, periodValue)))
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function getErrorStatsRedisTrend(befly, bucketDate) {
|
|
72
|
+
const bucketSet = await befly.redis.smembers(getErrorStatsDayBucketsKey(bucketDate));
|
|
73
|
+
const trend = [];
|
|
74
|
+
|
|
75
|
+
for (const bucketTime of bucketSet) {
|
|
76
|
+
const itemBucketTime = toNumber(bucketTime);
|
|
77
|
+
|
|
78
|
+
trend.push({
|
|
79
|
+
bucketTime: itemBucketTime,
|
|
80
|
+
bucketDate: bucketDate,
|
|
81
|
+
count: toNumber(await befly.redis.getString(getErrorStatsDayBucketCountKey(bucketDate, itemBucketTime)))
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
trend.sort((a, b) => a.bucketTime - b.bucketTime);
|
|
86
|
+
return trend;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function getErrorStatsRedisDays(befly, recentDateList) {
|
|
90
|
+
const days = [];
|
|
91
|
+
|
|
92
|
+
for (const item of recentDateList) {
|
|
93
|
+
days.push({
|
|
94
|
+
bucketDate: item,
|
|
95
|
+
count: toNumber(await befly.redis.getString(getErrorStatsPeriodCountKey("day", item)))
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return days;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async function getErrorStatsRedisTopTypes(befly, bucketDate) {
|
|
103
|
+
const typeSet = await befly.redis.smembers(getErrorStatsDayTypesKey(bucketDate));
|
|
104
|
+
const topTypes = [];
|
|
105
|
+
|
|
106
|
+
for (const errorType of typeSet) {
|
|
107
|
+
const name = String(errorType || "unknown");
|
|
108
|
+
const count = toNumber(await befly.redis.getString(getErrorStatsDayTypeCountKey(bucketDate, name)));
|
|
109
|
+
|
|
110
|
+
if (count <= 0) {
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
topTypes.push({
|
|
115
|
+
errorType: name,
|
|
116
|
+
count: count
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
topTypes.sort((a, b) => {
|
|
121
|
+
if (b.count !== a.count) {
|
|
122
|
+
return b.count - a.count;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return String(a.errorType).localeCompare(String(b.errorType), "zh-CN");
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
return topTypes.slice(0, 5);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async function getErrorStatsFromRedis(befly, bucketDate, weekStartDate, monthStartDate, recentDateList) {
|
|
132
|
+
const todaySummary = await getErrorStatsRedisSummary(befly, "day", bucketDate);
|
|
133
|
+
const weekSummary = await getErrorStatsRedisSummary(befly, "week", weekStartDate);
|
|
134
|
+
const monthSummary = await getErrorStatsRedisSummary(befly, "month", monthStartDate);
|
|
135
|
+
const trend = await getErrorStatsRedisTrend(befly, bucketDate);
|
|
136
|
+
const days = await getErrorStatsRedisDays(befly, recentDateList);
|
|
137
|
+
const topTypes = await getErrorStatsRedisTopTypes(befly, bucketDate);
|
|
138
|
+
|
|
139
|
+
if (todaySummary.count <= 0 && weekSummary.count <= 0 && monthSummary.count <= 0 && trend.length === 0 && topTypes.length === 0) {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
today: {
|
|
145
|
+
bucketDate: bucketDate,
|
|
146
|
+
count: todaySummary.count
|
|
147
|
+
},
|
|
148
|
+
week: {
|
|
149
|
+
startDate: weekStartDate,
|
|
150
|
+
endDate: bucketDate,
|
|
151
|
+
count: weekSummary.count
|
|
152
|
+
},
|
|
153
|
+
month: {
|
|
154
|
+
startDate: monthStartDate,
|
|
155
|
+
endDate: bucketDate,
|
|
156
|
+
count: monthSummary.count
|
|
157
|
+
},
|
|
158
|
+
trend: trend,
|
|
159
|
+
days: days,
|
|
160
|
+
topTypes: topTypes
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async function incrErrorStatsFallbackCount(befly, bucketDate) {
|
|
165
|
+
if (!befly.redis) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const dailyKey = getErrorStatsFallbackDailyCountKey(bucketDate);
|
|
170
|
+
|
|
171
|
+
if (typeof befly.redis.incrWithExpire === "function") {
|
|
172
|
+
await befly.redis.incrWithExpire(ERROR_STATS_FALLBACK_COUNT_KEY, ERROR_STATS_FALLBACK_TTL_SECONDS);
|
|
173
|
+
await befly.redis.incrWithExpire(dailyKey, ERROR_STATS_FALLBACK_TTL_SECONDS);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
await befly.redis.incr(ERROR_STATS_FALLBACK_COUNT_KEY);
|
|
178
|
+
await befly.redis.expire(ERROR_STATS_FALLBACK_COUNT_KEY, ERROR_STATS_FALLBACK_TTL_SECONDS);
|
|
179
|
+
await befly.redis.incr(dailyKey);
|
|
180
|
+
await befly.redis.expire(dailyKey, ERROR_STATS_FALLBACK_TTL_SECONDS);
|
|
181
|
+
}
|
|
182
|
+
|
|
38
183
|
async function getErrorStatsSummary(befly, startDate, endDate) {
|
|
39
184
|
const result = await befly.mysql.execute("SELECT SUM(hit_count) as count FROM befly_error_report WHERE state = 1 AND bucket_date BETWEEN ? AND ?", [startDate, endDate]);
|
|
40
185
|
const detail = result.data?.[0] || {};
|
|
@@ -56,6 +201,9 @@ export default {
|
|
|
56
201
|
const tableReady = tableExistsResult.data === true;
|
|
57
202
|
const now = Date.now();
|
|
58
203
|
const bucketDate = getDateYmdNumber(now);
|
|
204
|
+
const weekStartDate = getErrorStatsWeekStartDate(now);
|
|
205
|
+
const monthStartDate = getErrorStatsMonthStartDate(now);
|
|
206
|
+
const recentDateList = getErrorStatsRecentDateList(now);
|
|
59
207
|
|
|
60
208
|
if (!tableReady) {
|
|
61
209
|
return befly.tool.Yes("获取成功", {
|
|
@@ -64,12 +212,12 @@ export default {
|
|
|
64
212
|
count: 0
|
|
65
213
|
},
|
|
66
214
|
week: {
|
|
67
|
-
startDate:
|
|
215
|
+
startDate: weekStartDate,
|
|
68
216
|
endDate: bucketDate,
|
|
69
217
|
count: 0
|
|
70
218
|
},
|
|
71
219
|
month: {
|
|
72
|
-
startDate:
|
|
220
|
+
startDate: monthStartDate,
|
|
73
221
|
endDate: bucketDate,
|
|
74
222
|
count: 0
|
|
75
223
|
},
|
|
@@ -79,9 +227,16 @@ export default {
|
|
|
79
227
|
});
|
|
80
228
|
}
|
|
81
229
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
230
|
+
if (befly.redis) {
|
|
231
|
+
const redisResult = await getErrorStatsFromRedis(befly, bucketDate, weekStartDate, monthStartDate, recentDateList);
|
|
232
|
+
|
|
233
|
+
if (redisResult) {
|
|
234
|
+
return befly.tool.Yes("获取成功", redisResult);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
await incrErrorStatsFallbackCount(befly, bucketDate);
|
|
238
|
+
}
|
|
239
|
+
|
|
85
240
|
const todaySummary = await getErrorStatsSummary(befly, bucketDate, bucketDate);
|
|
86
241
|
const weekSummary = await getErrorStatsSummary(befly, weekStartDate, bucketDate);
|
|
87
242
|
const monthSummary = await getErrorStatsSummary(befly, monthStartDate, bucketDate);
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { getDateYmdNumber } from "#root/utils/datetime.js";
|
|
2
|
+
|
|
3
|
+
const INFO_STATS_FALLBACK_COUNT_KEY = "stats:fallback:infoStats:count";
|
|
4
|
+
const ERROR_STATS_FALLBACK_COUNT_KEY = "stats:fallback:errorStats:count";
|
|
5
|
+
|
|
6
|
+
function getInfoStatsFallbackDailyCountKey(reportDate) {
|
|
7
|
+
return `stats:fallback:infoStats:count:day:${reportDate}`;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function getErrorStatsFallbackDailyCountKey(reportDate) {
|
|
11
|
+
return `stats:fallback:errorStats:count:day:${reportDate}`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function toNumber(value) {
|
|
15
|
+
const num = Number(value);
|
|
16
|
+
|
|
17
|
+
if (!Number.isFinite(num)) {
|
|
18
|
+
return 0;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return num;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default {
|
|
25
|
+
name: "重置统计回退计数",
|
|
26
|
+
method: "POST",
|
|
27
|
+
body: "none",
|
|
28
|
+
auth: true,
|
|
29
|
+
fields: {},
|
|
30
|
+
required: [],
|
|
31
|
+
handler: async (befly) => {
|
|
32
|
+
if (!befly.redis) {
|
|
33
|
+
return befly.tool.No("Redis 不可用,无法重置", {
|
|
34
|
+
reset: false
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const reportDate = getDateYmdNumber(Date.now());
|
|
39
|
+
const infoDailyKey = getInfoStatsFallbackDailyCountKey(reportDate);
|
|
40
|
+
const errorDailyKey = getErrorStatsFallbackDailyCountKey(reportDate);
|
|
41
|
+
const resetKeys = [INFO_STATS_FALLBACK_COUNT_KEY, ERROR_STATS_FALLBACK_COUNT_KEY, infoDailyKey, errorDailyKey];
|
|
42
|
+
const before = {
|
|
43
|
+
infoStats: toNumber(await befly.redis.getString(INFO_STATS_FALLBACK_COUNT_KEY)),
|
|
44
|
+
errorStats: toNumber(await befly.redis.getString(ERROR_STATS_FALLBACK_COUNT_KEY)),
|
|
45
|
+
today: {
|
|
46
|
+
infoStats: toNumber(await befly.redis.getString(infoDailyKey)),
|
|
47
|
+
errorStats: toNumber(await befly.redis.getString(errorDailyKey))
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const removedCount = await befly.redis.delBatch(resetKeys);
|
|
52
|
+
|
|
53
|
+
return befly.tool.Yes("重置成功", {
|
|
54
|
+
reset: true,
|
|
55
|
+
reportDate: reportDate,
|
|
56
|
+
removedCount: toNumber(removedCount),
|
|
57
|
+
keys: resetKeys,
|
|
58
|
+
before: before,
|
|
59
|
+
after: {
|
|
60
|
+
infoStats: 0,
|
|
61
|
+
errorStats: 0,
|
|
62
|
+
today: {
|
|
63
|
+
infoStats: 0,
|
|
64
|
+
errorStats: 0
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
};
|
|
@@ -1,8 +1,27 @@
|
|
|
1
1
|
import { UAParser } from "ua-parser-js";
|
|
2
2
|
|
|
3
|
-
import { getDateYmdNumber } from "#root/utils/datetime.js";
|
|
3
|
+
import { addDays, getDateYmdNumber } from "#root/utils/datetime.js";
|
|
4
4
|
import { isValidPositiveInt } from "#root/utils/is.js";
|
|
5
5
|
|
|
6
|
+
const INFO_STATS_REDIS_TTL_SECONDS = 45 * 24 * 60 * 60;
|
|
7
|
+
const INFO_STATS_FIELDS = [
|
|
8
|
+
{ key: "sources", valueKey: "source" },
|
|
9
|
+
{ key: "productNames", valueKey: "productName" },
|
|
10
|
+
{ key: "productCodes", valueKey: "productCode" },
|
|
11
|
+
{ key: "productVersions", valueKey: "productVersion" },
|
|
12
|
+
{ key: "pagePaths", valueKey: "pagePath" },
|
|
13
|
+
{ key: "pageNames", valueKey: "pageName" },
|
|
14
|
+
{ key: "deviceTypes", valueKey: "deviceType" },
|
|
15
|
+
{ key: "browsers", valueKey: "browserName" },
|
|
16
|
+
{ key: "browserVersions", valueKey: "browserVersion" },
|
|
17
|
+
{ key: "osList", valueKey: "osName" },
|
|
18
|
+
{ key: "osVersions", valueKey: "osVersion" },
|
|
19
|
+
{ key: "deviceVendors", valueKey: "deviceVendor" },
|
|
20
|
+
{ key: "deviceModels", valueKey: "deviceModel" },
|
|
21
|
+
{ key: "engines", valueKey: "engineName" },
|
|
22
|
+
{ key: "cpuArchitectures", valueKey: "cpuArchitecture" }
|
|
23
|
+
];
|
|
24
|
+
|
|
6
25
|
function getInfoStatsMember(ctx) {
|
|
7
26
|
if (isValidPositiveInt(ctx.userId)) {
|
|
8
27
|
return `user:${ctx.userId}`;
|
|
@@ -11,6 +30,67 @@ function getInfoStatsMember(ctx) {
|
|
|
11
30
|
return `ip:${ctx.ip || "unknown"}`;
|
|
12
31
|
}
|
|
13
32
|
|
|
33
|
+
function getInfoStatsWeekStartDate(timestamp = Date.now()) {
|
|
34
|
+
const date = Reflect.construct(Date, [timestamp]);
|
|
35
|
+
const day = date.getDay();
|
|
36
|
+
const offset = day === 0 ? -6 : 1 - day;
|
|
37
|
+
|
|
38
|
+
return getDateYmdNumber(addDays(timestamp, offset));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function getInfoStatsMonthStartDate(timestamp = Date.now()) {
|
|
42
|
+
const date = Reflect.construct(Date, [timestamp]);
|
|
43
|
+
|
|
44
|
+
return getDateYmdNumber(Reflect.construct(Date, [date.getFullYear(), date.getMonth(), 1, 0, 0, 0, 0]).getTime());
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function getInfoStatsNamesKey(periodType, periodValue, fieldKey) {
|
|
48
|
+
return `info:${periodType}:${periodValue}:${fieldKey}:names`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function getInfoStatsCountKey(periodType, periodValue, fieldKey, value) {
|
|
52
|
+
return `info:${periodType}:${periodValue}:${fieldKey}:count:${encodeURIComponent(String(value || ""))}`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function getInfoStatsReportTimeKey(periodType, periodValue) {
|
|
56
|
+
return `info:${periodType}:${periodValue}:reportTime`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function updateInfoStatsPeriodRedis(befly, periodType, periodValue, statData, now) {
|
|
60
|
+
const reportTimeKey = getInfoStatsReportTimeKey(periodType, periodValue);
|
|
61
|
+
await befly.redis.setString(reportTimeKey, String(now), INFO_STATS_REDIS_TTL_SECONDS);
|
|
62
|
+
await befly.redis.expire(reportTimeKey, INFO_STATS_REDIS_TTL_SECONDS);
|
|
63
|
+
|
|
64
|
+
for (const item of INFO_STATS_FIELDS) {
|
|
65
|
+
const rawValue = String(statData[item.valueKey] || "").trim();
|
|
66
|
+
|
|
67
|
+
if (!rawValue) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const namesKey = getInfoStatsNamesKey(periodType, periodValue, item.key);
|
|
72
|
+
const countKey = getInfoStatsCountKey(periodType, periodValue, item.key, rawValue);
|
|
73
|
+
|
|
74
|
+
await befly.redis.sadd(namesKey, [rawValue]);
|
|
75
|
+
await befly.redis.incr(countKey);
|
|
76
|
+
await befly.redis.expire(namesKey, INFO_STATS_REDIS_TTL_SECONDS);
|
|
77
|
+
await befly.redis.expire(countKey, INFO_STATS_REDIS_TTL_SECONDS);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function updateInfoStatsRedis(befly, now, reportDate, statData) {
|
|
82
|
+
if (!befly.redis) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const weekStartDate = getInfoStatsWeekStartDate(now);
|
|
87
|
+
const monthStartDate = getInfoStatsMonthStartDate(now);
|
|
88
|
+
|
|
89
|
+
await updateInfoStatsPeriodRedis(befly, "day", reportDate, statData, now);
|
|
90
|
+
await updateInfoStatsPeriodRedis(befly, "week", weekStartDate, statData, now);
|
|
91
|
+
await updateInfoStatsPeriodRedis(befly, "month", monthStartDate, statData, now);
|
|
92
|
+
}
|
|
93
|
+
|
|
14
94
|
export default {
|
|
15
95
|
name: "上报访问信息统计",
|
|
16
96
|
method: "POST",
|
|
@@ -68,32 +148,52 @@ export default {
|
|
|
68
148
|
});
|
|
69
149
|
}
|
|
70
150
|
|
|
151
|
+
const statData = {
|
|
152
|
+
source: body.source || "",
|
|
153
|
+
productName: body.productName || "",
|
|
154
|
+
productCode: body.productCode || "",
|
|
155
|
+
productVersion: body.productVersion || "",
|
|
156
|
+
pagePath: body.pagePath || "",
|
|
157
|
+
pageName: body.pageName || "",
|
|
158
|
+
deviceType: uaResult.device.type || "desktop",
|
|
159
|
+
browserName: uaResult.browser.name || "",
|
|
160
|
+
browserVersion: uaResult.browser.version || "",
|
|
161
|
+
osName: uaResult.os.name || "",
|
|
162
|
+
osVersion: uaResult.os.version || "",
|
|
163
|
+
deviceVendor: uaResult.device.vendor || "",
|
|
164
|
+
deviceModel: uaResult.device.model || "",
|
|
165
|
+
engineName: uaResult.engine.name || "",
|
|
166
|
+
cpuArchitecture: uaResult.cpu.architecture || ""
|
|
167
|
+
};
|
|
168
|
+
|
|
71
169
|
await befly.mysql.insData({
|
|
72
170
|
table: "beflyInfoReport",
|
|
73
171
|
data: {
|
|
74
172
|
reportTime: now,
|
|
75
173
|
reportDate: reportDate,
|
|
76
174
|
memberKey: member,
|
|
77
|
-
source:
|
|
78
|
-
productName:
|
|
79
|
-
productCode:
|
|
80
|
-
productVersion:
|
|
81
|
-
pagePath:
|
|
82
|
-
pageName:
|
|
175
|
+
source: statData.source,
|
|
176
|
+
productName: statData.productName,
|
|
177
|
+
productCode: statData.productCode,
|
|
178
|
+
productVersion: statData.productVersion,
|
|
179
|
+
pagePath: statData.pagePath,
|
|
180
|
+
pageName: statData.pageName,
|
|
83
181
|
detail: body.detail || "",
|
|
84
182
|
userAgent: userAgent,
|
|
85
|
-
deviceType:
|
|
86
|
-
browserName:
|
|
87
|
-
browserVersion:
|
|
88
|
-
osName:
|
|
89
|
-
osVersion:
|
|
90
|
-
deviceVendor:
|
|
91
|
-
deviceModel:
|
|
92
|
-
engineName:
|
|
93
|
-
cpuArchitecture:
|
|
183
|
+
deviceType: statData.deviceType,
|
|
184
|
+
browserName: statData.browserName,
|
|
185
|
+
browserVersion: statData.browserVersion,
|
|
186
|
+
osName: statData.osName,
|
|
187
|
+
osVersion: statData.osVersion,
|
|
188
|
+
deviceVendor: statData.deviceVendor,
|
|
189
|
+
deviceModel: statData.deviceModel,
|
|
190
|
+
engineName: statData.engineName,
|
|
191
|
+
cpuArchitecture: statData.cpuArchitecture
|
|
94
192
|
}
|
|
95
193
|
});
|
|
96
194
|
|
|
195
|
+
await updateInfoStatsRedis(befly, now, reportDate, statData);
|
|
196
|
+
|
|
97
197
|
return befly.tool.Yes("上报成功", {
|
|
98
198
|
reportTime: now,
|
|
99
199
|
reportDate: reportDate,
|