diff --git a/src/generator/Stats.ts b/src/generator/Stats.ts index c1fa9de3..95f5c552 100644 --- a/src/generator/Stats.ts +++ b/src/generator/Stats.ts @@ -139,12 +139,23 @@ export class Stats { this.queryDurationStats(), // this.queryCountDuplicateViewStats(), this.queryTimeFrameStats(), - this.pushCountDuplicateViewStats(), + this.pushCountDuplicateViewStats() ]).then((ignored: any) => { console.log(debug(`Complete stats query took ${ (Date.now() - queryStart) / 1000 }s`)); }); } + + static async slowQuery(): Promise { + console.log(debug(`Querying stats (slow)...`)); + const queryStart = Date.now(); + return Promise.all([ + this.queryAccountCapeStats() + ]).then((ignored: any) => { + console.log(debug(`Slow stats query took ${ (Date.now() - queryStart) / 1000 }s`)); + }); + } + protected static async queryAccountStats(): Promise { const config = await getConfig(); const time = Date.now() / 1000; @@ -194,6 +205,37 @@ export class Stats { }); } + protected static async queryAccountCapeStats(): Promise{ + const accountCapes = await Account.aggregate([ + {$match:{ ownedCapes : { $exists : true, $ne : [ ] } }}, + { $unwind: "$ownedCapes" }, // flatten the ownedCapes array + { $group: { _id: "$ownedCapes", count: { $sum: 1 } } } // count the occurrences of each unique value in the ownedCapes field + ]); + + const points = accountCapes.map((entry) => { + return { + measurement: 'account_capes', + tags: { + cape: entry._id + }, + fields: { + count: entry.count + } + } + }); + + try { + const metrics = await MineSkinMetrics.get(); + await metrics.metrics!.influx.writePoints(points, { + database: 'mineskin', + precision: 's' + }) + } catch (e) { + console.warn(e); + Sentry.captureException(e); + } + } + protected static async queryDurationStats(): Promise { return Skin.aggregate([ {"$sort": {time: -1}}, diff --git a/src/index.ts b/src/index.ts index 7009b9d0..4e271295 100644 --- a/src/index.ts +++ b/src/index.ts @@ -403,6 +403,21 @@ async function init() { } }, 1000 * 60 * 2); + setInterval(() => { + try { + Stats.slowQuery(); + } catch (e) { + Sentry.captureException(e); + } + }, 1000 * 60 * 60); + setTimeout(() => { + try { + Stats.slowQuery(); + } catch (e) { + Sentry.captureException(e); + } + }, 1000 * 60) + if (config.migrateRedisStats) { console.log("running redis migration"); try { diff --git a/src/util/metrics.ts b/src/util/metrics.ts index fe0c923b..34a11254 100644 --- a/src/util/metrics.ts +++ b/src/util/metrics.ts @@ -31,6 +31,7 @@ export class MineSkinMetrics { public readonly hashMismatch: Metric; public readonly urlMismatch: Metric; public readonly accountNotifications: Metric; + public readonly accountCapes: Metric; public readonly tester: Metric; @@ -65,6 +66,7 @@ export class MineSkinMetrics { this.urlMismatch = this.metrics.metric('mineskin', 'url_mismatch'); this.tester = this.metrics.metric('mineskin', 'tester'); this.accountNotifications = this.metrics.metric('mineskin', 'account_notifications'); + this.accountCapes = this.metrics.metric('mineskin', 'account_capes'); } apiRequestsMiddleware(req: Request, res: Response, next: NextFunction) {