← back to Wine Finder Next

app/api/monitoring/performance/route.ts

110 lines

// Performance Monitoring Dashboard API
// GET /api/monitoring/performance

import { NextRequest, NextResponse } from 'next/server';
import { perfMonitor, queryCache } from '@/lib/membershipDatabase.optimized';
import { getTimingStats } from '@/lib/apiOptimization';
import { getConnectionPool } from '@/lib/connectionPool';

export async function GET(request: NextRequest) {
  const { searchParams } = new URL(request.url);
  const operation = searchParams.get('operation');

  try {
    // Get database operation metrics
    const dbMetrics = {
      'bottle.getAll': perfMonitor.getAverageTime('bottle.getAll'),
      'bottle.getById': perfMonitor.getAverageTime('bottle.getById'),
      'bottle.create': perfMonitor.getAverageTime('bottle.create'),
      'bottle.update': perfMonitor.getAverageTime('bottle.update'),
      'unit.getByBottleId': perfMonitor.getAverageTime('unit.getByBottleId'),
      'unit.getByOwnerId': perfMonitor.getAverageTime('unit.getByOwnerId'),
      'vote.getActive': perfMonitor.getAverageTime('vote.getActive'),
      'vote.cast': perfMonitor.getAverageTime('vote.cast'),
      'marketplace.getActive': perfMonitor.getAverageTime('marketplace.getActive')
    };

    // Get API endpoint metrics
    const apiMetrics = {
      'bottles.GET': getTimingStats('bottles.GET'),
      'bottles.POST': getTimingStats('bottles.POST')
    };

    // Get cache statistics
    const cacheStats = queryCache.getStats();

    // Get connection pool stats (if available)
    let poolStats = null;
    try {
      poolStats = getConnectionPool().getDetailedStats();
    } catch (e) {
      // Pool might not be initialized
    }

    // Memory usage
    const memoryUsage = process.memoryUsage();

    const response = {
      timestamp: new Date().toISOString(),
      database: {
        operations: dbMetrics,
        slowQueries: Object.entries(dbMetrics)
          .filter(([_, time]) => time > 50)
          .map(([op, time]) => ({ operation: op, avgTime: time }))
      },
      api: {
        endpoints: apiMetrics,
        slowEndpoints: Object.entries(apiMetrics)
          .filter(([_, stats]) => stats && stats.avg > 100)
          .map(([endpoint, stats]) => ({ endpoint, ...stats }))
      },
      cache: {
        size: cacheStats.size,
        totalHits: cacheStats.totalHits,
        averageHits: cacheStats.avgHits,
        hitRate: cacheStats.totalHits > 0
          ? ((cacheStats.totalHits / (cacheStats.totalHits + cacheStats.size)) * 100).toFixed(2)
          : 0
      },
      connectionPool: poolStats,
      memory: {
        heapUsed: Math.round(memoryUsage.heapUsed / 1024 / 1024),
        heapTotal: Math.round(memoryUsage.heapTotal / 1024 / 1024),
        rss: Math.round(memoryUsage.rss / 1024 / 1024),
        external: Math.round(memoryUsage.external / 1024 / 1024)
      },
      uptime: Math.round(process.uptime()),
      nodeVersion: process.version
    };

    return NextResponse.json(response, {
      headers: {
        'Cache-Control': 'no-store, max-age=0'
      }
    });
  } catch (error) {
    return NextResponse.json(
      { error: 'Failed to fetch performance metrics' },
      { status: 500 }
    );
  }
}

// Clear metrics
export async function DELETE(request: NextRequest) {
  try {
    perfMonitor.clearMetrics();
    queryCache.invalidate();

    return NextResponse.json({
      success: true,
      message: 'Performance metrics cleared'
    });
  } catch (error) {
    return NextResponse.json(
      { error: 'Failed to clear metrics' },
      { status: 500 }
    );
  }
}