- Add /api/metrics endpoint for Prometheus scraping - Add /api/track endpoint for metrics tracking - Add metrics library with HTTP request counters - Add middleware for request tracking - Add instrumentation for Next.js 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
76 lines
2.2 KiB
TypeScript
76 lines
2.2 KiB
TypeScript
import { NextResponse } from 'next/server';
|
|
import type { NextRequest } from 'next/server';
|
|
|
|
// Routes only accessible when not authenticated
|
|
const authRoutes = ['/login', '/register'];
|
|
|
|
// Routes à ne pas tracker
|
|
const excludedPaths = ['/api/track', '/api/metrics', '/_next', '/favicon.ico'];
|
|
|
|
export function middleware(request: NextRequest) {
|
|
const { pathname } = request.nextUrl;
|
|
const startTime = Date.now();
|
|
|
|
// Get token from cookies or headers
|
|
const token = request.cookies.get('auth_token')?.value ||
|
|
request.headers.get('authorization')?.replace('Bearer ', '');
|
|
|
|
// Check if route is auth route
|
|
const isAuthRoute = authRoutes.some(route => pathname.startsWith(route));
|
|
|
|
// Préparer la réponse
|
|
let response: NextResponse;
|
|
|
|
// If accessing auth routes with token in cookies, redirect to home
|
|
if (isAuthRoute && token) {
|
|
response = NextResponse.redirect(new URL('/', request.url));
|
|
} else {
|
|
response = NextResponse.next();
|
|
}
|
|
|
|
// Tracker les métriques HTTP (fire and forget)
|
|
const shouldTrack = !excludedPaths.some(path => pathname.startsWith(path));
|
|
|
|
if (shouldTrack) {
|
|
const durationMs = Date.now() - startTime;
|
|
const statusCode = response.status || 200;
|
|
|
|
// Envoyer les métriques de manière asynchrone (non bloquant)
|
|
const trackUrl = new URL('/api/track', request.url);
|
|
|
|
// Utiliser waitUntil pour ne pas bloquer la réponse
|
|
// Note: waitUntil n'est pas disponible dans tous les environnements
|
|
try {
|
|
fetch(trackUrl.toString(), {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
method: request.method,
|
|
path: pathname,
|
|
statusCode,
|
|
durationMs,
|
|
}),
|
|
}).catch(() => {
|
|
// Ignorer les erreurs de tracking
|
|
});
|
|
} catch {
|
|
// Ignorer les erreurs de tracking
|
|
}
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
export const config = {
|
|
matcher: [
|
|
/*
|
|
* Match all request paths except for the ones starting with:
|
|
* - _next/static (static files)
|
|
* - _next/image (image optimization files)
|
|
* - favicon.ico (favicon file)
|
|
* - public files (public folder)
|
|
*/
|
|
'/((?!_next/static|_next/image|favicon.ico|.*\\..*|public).*)',
|
|
],
|
|
};
|