89
handlers/analytics.js
Normal file
89
handlers/analytics.js
Normal file
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* In-memory analytics and error tracking.
|
||||
*/
|
||||
const { logError } = require('../services/debugLog');
|
||||
|
||||
const analytics = {
|
||||
commands: {},
|
||||
buttons: {},
|
||||
modals: {},
|
||||
contextMenus: {},
|
||||
errors: [],
|
||||
startTime: Date.now()
|
||||
};
|
||||
|
||||
function trackInteraction(type, name, userId = 'unknown') {
|
||||
analytics[type][name] = (analytics[type][name] || 0) + 1;
|
||||
console.log(`📊 Analytics: ${type}/${name} by ${userId}`);
|
||||
}
|
||||
|
||||
function getTotalInteractions() {
|
||||
let total = 0;
|
||||
for (const type of ['commands', 'buttons', 'modals', 'contextMenus']) {
|
||||
for (const key in analytics[type]) {
|
||||
total += analytics[type][key];
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
function trackError(context, error, interaction = null) {
|
||||
const errorEntry = {
|
||||
context,
|
||||
message: error.message,
|
||||
stack: error.stack,
|
||||
timestamp: Date.now(),
|
||||
user: interaction?.user?.tag || 'system',
|
||||
command: interaction?.commandName || 'N/A'
|
||||
};
|
||||
|
||||
analytics.errors.push(errorEntry);
|
||||
|
||||
if (analytics.errors.length > 100) {
|
||||
analytics.errors.shift();
|
||||
}
|
||||
|
||||
console.error(`❌ Error tracked: ${context}:`, error.message);
|
||||
|
||||
logError(context, error, interaction);
|
||||
|
||||
const recentErrors = analytics.errors.filter(e =>
|
||||
Date.now() - e.timestamp < 3600000
|
||||
);
|
||||
|
||||
const errorRate = recentErrors.length / Math.max(1, getTotalInteractions());
|
||||
|
||||
if (errorRate > 0.05) {
|
||||
console.warn(`⚠️ HIGH ERROR RATE: ${(errorRate * 100).toFixed(2)}% in last hour`);
|
||||
}
|
||||
}
|
||||
|
||||
function getAnalyticsSummary() {
|
||||
const uptime = Math.floor((Date.now() - analytics.startTime) / 1000);
|
||||
const totalInteractions = getTotalInteractions();
|
||||
const recentErrors = analytics.errors.filter(e =>
|
||||
Date.now() - e.timestamp < 3600000
|
||||
);
|
||||
|
||||
return {
|
||||
uptime: `${Math.floor(uptime / 3600)}h ${Math.floor((uptime % 3600) / 60)}m`,
|
||||
totalInteractions,
|
||||
commandsUsed: Object.keys(analytics.commands).length,
|
||||
mostUsedCommand: Object.entries(analytics.commands)
|
||||
.sort((a, b) => b[1] - a[1])[0]?.[0] || 'None',
|
||||
errorsLastHour: recentErrors.length,
|
||||
errorRate: `${((recentErrors.length / Math.max(1, totalInteractions)) * 100).toFixed(2)}%`,
|
||||
topCommands: Object.entries(analytics.commands)
|
||||
.sort((a, b) => b[1] - a[1])
|
||||
.slice(0, 5)
|
||||
.map(([cmd, count]) => `${cmd}: ${count}`)
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
analytics,
|
||||
trackInteraction,
|
||||
trackError,
|
||||
getTotalInteractions,
|
||||
getAnalyticsSummary
|
||||
};
|
||||
Reference in New Issue
Block a user