···
+
// Create request analytics table
+
CREATE TABLE IF NOT EXISTS request_analytics (
+
endpoint TEXT NOT NULL,
+
status_code INTEGER NOT NULL,
+
timestamp INTEGER NOT NULL,
+
// Create index for faster queries
+
CREATE INDEX IF NOT EXISTS idx_request_analytics_timestamp
+
ON request_analytics(timestamp)
+
CREATE INDEX IF NOT EXISTS idx_request_analytics_endpoint
+
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 < ?", [
+
// Clean up old analytics data (older than 30 days)
+
const thirtyDaysAgo = Date.now() - 30 * 24 * 60 * 60 * 1000;
+
this.db.run("DELETE FROM request_analytics WHERE timestamp < ?", [
if (this.onEmojiExpired) {
···
expiration: new Date(result.expiration),
+
* Records a request for analytics
+
* @param endpoint The endpoint that was accessed
+
* @param method HTTP method
+
* @param statusCode HTTP status code
+
* @param userAgent User agent string
+
* @param ipAddress IP address of the client
+
* @param responseTime Response time in milliseconds
+
const id = crypto.randomUUID();
+
`INSERT INTO request_analytics
+
(id, endpoint, method, status_code, user_agent, ip_address, timestamp, response_time)
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
+
console.error("Error recording request analytics:", error);
+
* Gets request analytics statistics
+
* @param days Number of days to look back (default: 7)
+
* @returns Analytics data
+
async getAnalytics(days: number = 7): Promise<{
+
requestsByEndpoint: Array<{
+
averageResponseTime: number;
+
requestsByStatus: Array<{
+
averageResponseTime: number;
+
averageResponseTime: number;
+
averageResponseTime: number | null;
+
topUserAgents: Array<{ userAgent: string; count: number }>;
+
const cutoffTime = Date.now() - days * 24 * 60 * 60 * 1000;
+
const totalResult = this.db
+
"SELECT COUNT(*) as count FROM request_analytics WHERE timestamp > ?",
+
.get(cutoffTime) as { count: number };
+
// Requests by endpoint with average response time
+
const endpointResultsRaw = this.db
+
SELECT endpoint, COUNT(*) as count, AVG(response_time) as averageResponseTime
+
.all(cutoffTime) as Array<{
+
averageResponseTime: number | null;
+
const endpointResults = endpointResultsRaw.map((e) => ({
+
averageResponseTime: e.averageResponseTime ?? 0,
+
// Requests by status code with average response time
+
const statusResultsRaw = this.db
+
SELECT status_code as status, COUNT(*) as count, AVG(response_time) as averageResponseTime
+
.all(cutoffTime) as Array<{
+
averageResponseTime: number | null;
+
const statusResults = statusResultsRaw.map((s) => ({
+
averageResponseTime: s.averageResponseTime ?? 0,
+
// Requests by day with average response time
+
const dayResultsRaw = this.db
+
DATE(timestamp / 1000, 'unixepoch') as date,
+
AVG(response_time) as averageResponseTime
+
GROUP BY DATE(timestamp / 1000, 'unixepoch')
+
.all(cutoffTime) as Array<{
+
averageResponseTime: number | null;
+
const dayResults = dayResultsRaw.map((d) => ({
+
averageResponseTime: d.averageResponseTime ?? 0,
+
// Average response time
+
const avgResponseResult = this.db
+
SELECT AVG(response_time) as avg
+
WHERE timestamp > ? AND response_time IS NOT NULL
+
.get(cutoffTime) as { avg: number | null };
+
const userAgentResults = this.db
+
SELECT user_agent as userAgent, COUNT(*) as count
+
WHERE timestamp > ? AND user_agent IS NOT NULL
+
.all(cutoffTime) as Array<{ userAgent: string; count: number }>;
+
totalRequests: totalResult.count,
+
requestsByEndpoint: endpointResults,
+
requestsByStatus: statusResults,
+
requestsByDay: dayResults,
+
averageResponseTime: avgResponseResult.avg,
+
topUserAgents: userAgentResults,