comprehensive monitoring and logging system
This commit is contained in:
99
lib/monitoring.ts
Normal file
99
lib/monitoring.ts
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
interface MonitoringMetric {
|
||||||
|
name: string
|
||||||
|
value: number
|
||||||
|
timestamp: number
|
||||||
|
tags?: Record<string, string>
|
||||||
|
}
|
||||||
|
|
||||||
|
class MetricsCollector {
|
||||||
|
private metrics: MonitoringMetric[] = []
|
||||||
|
private maxMetrics = 1000
|
||||||
|
|
||||||
|
record(name: string, value: number, tags?: Record<string, string>): void {
|
||||||
|
const metric: MonitoringMetric = {
|
||||||
|
name,
|
||||||
|
value,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
tags
|
||||||
|
}
|
||||||
|
|
||||||
|
this.metrics.push(metric)
|
||||||
|
|
||||||
|
// Keep only recent metrics
|
||||||
|
if (this.metrics.length > this.maxMetrics) {
|
||||||
|
this.metrics = this.metrics.slice(-this.maxMetrics)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getMetrics(name?: string, since?: number): MonitoringMetric[] {
|
||||||
|
let filtered = this.metrics
|
||||||
|
|
||||||
|
if (name) {
|
||||||
|
filtered = filtered.filter(m => m.name === name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (since) {
|
||||||
|
filtered = filtered.filter(m => m.timestamp >= since)
|
||||||
|
}
|
||||||
|
|
||||||
|
return filtered
|
||||||
|
}
|
||||||
|
|
||||||
|
getAverageResponseTime(since?: number): number {
|
||||||
|
const responseMetrics = this.getMetrics('api.response_time', since)
|
||||||
|
if (responseMetrics.length === 0) return 0
|
||||||
|
|
||||||
|
const sum = responseMetrics.reduce((acc, m) => acc + m.value, 0)
|
||||||
|
return sum / responseMetrics.length
|
||||||
|
}
|
||||||
|
|
||||||
|
getRequestCount(endpoint?: string, since?: number): number {
|
||||||
|
const requestMetrics = this.getMetrics('api.request', since)
|
||||||
|
|
||||||
|
if (endpoint) {
|
||||||
|
return requestMetrics.filter(m => m.tags?.endpoint === endpoint).length
|
||||||
|
}
|
||||||
|
|
||||||
|
return requestMetrics.length
|
||||||
|
}
|
||||||
|
|
||||||
|
getErrorCount(since?: number): number {
|
||||||
|
return this.getMetrics('api.error', since).length
|
||||||
|
}
|
||||||
|
|
||||||
|
clear(): void {
|
||||||
|
this.metrics = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const metrics = new MetricsCollector()
|
||||||
|
|
||||||
|
export function trackApiCall(endpoint: string, method: string, statusCode: number, responseTime: number): void {
|
||||||
|
metrics.record('api.request', 1, { endpoint, method, status: statusCode.toString() })
|
||||||
|
metrics.record('api.response_time', responseTime, { endpoint })
|
||||||
|
|
||||||
|
if (statusCode >= 400) {
|
||||||
|
metrics.record('api.error', 1, { endpoint, status: statusCode.toString() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function trackDatabaseQuery(operation: string, duration: number): void {
|
||||||
|
metrics.record('db.query', 1, { operation })
|
||||||
|
metrics.record('db.duration', duration, { operation })
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getHealthStatus(): any {
|
||||||
|
const now = Date.now()
|
||||||
|
const fiveMinutesAgo = now - (5 * 60 * 1000)
|
||||||
|
|
||||||
|
return {
|
||||||
|
status: 'healthy',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
metrics: {
|
||||||
|
requests_5min: metrics.getRequestCount(undefined, fiveMinutesAgo),
|
||||||
|
avg_response_time: Math.round(metrics.getAverageResponseTime(fiveMinutesAgo)),
|
||||||
|
errors_5min: metrics.getErrorCount(fiveMinutesAgo),
|
||||||
|
uptime: process.uptime()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
17
pages/api/health.ts
Normal file
17
pages/api/health.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import type { NextApiRequest, NextApiResponse } from "next"
|
||||||
|
import { getHealthStatus } from "../../lib/monitoring"
|
||||||
|
|
||||||
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
|
if (req.method !== "GET") return res.status(405).json({ error: "Method not allowed" })
|
||||||
|
|
||||||
|
try {
|
||||||
|
const health = getHealthStatus()
|
||||||
|
res.status(200).json(health)
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({
|
||||||
|
status: 'unhealthy',
|
||||||
|
error: 'Health check failed',
|
||||||
|
timestamp: new Date().toISOString()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user