···
96
+
// Create request analytics table
98
+
CREATE TABLE IF NOT EXISTS request_analytics (
99
+
id TEXT PRIMARY KEY,
100
+
endpoint TEXT NOT NULL,
101
+
method TEXT NOT NULL,
102
+
status_code INTEGER NOT NULL,
105
+
timestamp INTEGER NOT NULL,
106
+
response_time INTEGER
110
+
// Create index for faster queries
112
+
CREATE INDEX IF NOT EXISTS idx_request_analytics_timestamp
113
+
ON request_analytics(timestamp)
117
+
CREATE INDEX IF NOT EXISTS idx_request_analytics_endpoint
118
+
ON request_analytics(endpoint)
// check if there are any emojis in the db
if (this.onEmojiExpired) {
···
const result2 = this.db.run("DELETE FROM emojis WHERE expiration < ?", [
155
+
// Clean up old analytics data (older than 30 days)
156
+
const thirtyDaysAgo = Date.now() - 30 * 24 * 60 * 60 * 1000;
157
+
this.db.run("DELETE FROM request_analytics WHERE timestamp < ?", [
if (this.onEmojiExpired) {
···
expiration: new Date(result.expiration),
422
+
* Records a request for analytics
423
+
* @param endpoint The endpoint that was accessed
424
+
* @param method HTTP method
425
+
* @param statusCode HTTP status code
426
+
* @param userAgent User agent string
427
+
* @param ipAddress IP address of the client
428
+
* @param responseTime Response time in milliseconds
430
+
async recordRequest(
433
+
statusCode: number,
434
+
userAgent?: string,
435
+
ipAddress?: string,
436
+
responseTime?: number,
439
+
const id = crypto.randomUUID();
441
+
`INSERT INTO request_analytics
442
+
(id, endpoint, method, status_code, user_agent, ip_address, timestamp, response_time)
443
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
452
+
responseTime || null,
456
+
console.error("Error recording request analytics:", error);
461
+
* Gets request analytics statistics
462
+
* @param days Number of days to look back (default: 7)
463
+
* @returns Analytics data
465
+
async getAnalytics(days: number = 7): Promise<{
466
+
totalRequests: number;
467
+
requestsByEndpoint: Array<{
470
+
averageResponseTime: number;
472
+
requestsByStatus: Array<{
475
+
averageResponseTime: number;
477
+
requestsByDay: Array<{
480
+
averageResponseTime: number;
482
+
averageResponseTime: number | null;
483
+
topUserAgents: Array<{ userAgent: string; count: number }>;
485
+
const cutoffTime = Date.now() - days * 24 * 60 * 60 * 1000;
488
+
const totalResult = this.db
490
+
"SELECT COUNT(*) as count FROM request_analytics WHERE timestamp > ?",
492
+
.get(cutoffTime) as { count: number };
494
+
// Requests by endpoint with average response time
495
+
const endpointResultsRaw = this.db
498
+
SELECT endpoint, COUNT(*) as count, AVG(response_time) as averageResponseTime
499
+
FROM request_analytics
500
+
WHERE timestamp > ?
502
+
ORDER BY count DESC
505
+
.all(cutoffTime) as Array<{
508
+
averageResponseTime: number | null;
511
+
const endpointResults = endpointResultsRaw.map((e) => ({
512
+
endpoint: e.endpoint,
514
+
averageResponseTime: e.averageResponseTime ?? 0,
517
+
// Requests by status code with average response time
518
+
const statusResultsRaw = this.db
521
+
SELECT status_code as status, COUNT(*) as count, AVG(response_time) as averageResponseTime
522
+
FROM request_analytics
523
+
WHERE timestamp > ?
524
+
GROUP BY status_code
525
+
ORDER BY count DESC
528
+
.all(cutoffTime) as Array<{
531
+
averageResponseTime: number | null;
534
+
const statusResults = statusResultsRaw.map((s) => ({
537
+
averageResponseTime: s.averageResponseTime ?? 0,
540
+
// Requests by day with average response time
541
+
const dayResultsRaw = this.db
545
+
DATE(timestamp / 1000, 'unixepoch') as date,
547
+
AVG(response_time) as averageResponseTime
548
+
FROM request_analytics
549
+
WHERE timestamp > ?
550
+
GROUP BY DATE(timestamp / 1000, 'unixepoch')
554
+
.all(cutoffTime) as Array<{
557
+
averageResponseTime: number | null;
560
+
const dayResults = dayResultsRaw.map((d) => ({
563
+
averageResponseTime: d.averageResponseTime ?? 0,
566
+
// Average response time
567
+
const avgResponseResult = this.db
570
+
SELECT AVG(response_time) as avg
571
+
FROM request_analytics
572
+
WHERE timestamp > ? AND response_time IS NOT NULL
575
+
.get(cutoffTime) as { avg: number | null };
578
+
const userAgentResults = this.db
581
+
SELECT user_agent as userAgent, COUNT(*) as count
582
+
FROM request_analytics
583
+
WHERE timestamp > ? AND user_agent IS NOT NULL
584
+
GROUP BY user_agent
585
+
ORDER BY count DESC
589
+
.all(cutoffTime) as Array<{ userAgent: string; count: number }>;
592
+
totalRequests: totalResult.count,
593
+
requestsByEndpoint: endpointResults,
594
+
requestsByStatus: statusResults,
595
+
requestsByDay: dayResults,
596
+
averageResponseTime: avgResponseResult.avg,
597
+
topUserAgents: userAgentResults,