Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | /** * SLO History API * * GET /api/admin/monitoring/slo-history * * Returns historical SLO data for trending and analysis. */ import { NextRequest, NextResponse } from 'next/server'; import { z } from 'zod'; import { logger } from '@/lib/logging'; import { getSLOHistory, getSLOHistoryByCategory, getAllSLOsWithTrends, getRecentTrend, } from '@/lib/observability/slo-history'; const QuerySchema = z.object({ sloName: z.string().optional(), category: z.string().optional(), startDate: z.string().optional(), endDate: z.string().optional(), granularity: z.enum(['hourly', 'daily']).optional().default('hourly'), mode: z.enum(['history', 'trends', 'sparkline']).optional().default('history'), points: z.coerce.number().min(1).max(100).optional().default(24), }); export async function GET(request: NextRequest) { try { const searchParams = Object.fromEntries(request.nextUrl.searchParams); const params = QuerySchema.parse(searchParams); // Mode: sparkline - just get recent trend data for a single SLO if (params.mode === 'sparkline') { if (!params.sloName) { return NextResponse.json( { error: 'sloName is required for sparkline mode' }, { status: 400 } ); } const trend = await getRecentTrend(params.sloName, params.points); return NextResponse.json({ trend }); } // Mode: trends - get all SLOs with their current state and recent trends if (params.mode === 'trends') { const slosWithTrends = await getAllSLOsWithTrends(); return NextResponse.json({ slos: slosWithTrends }); } // Mode: history - get historical data for analysis // Default date range: last 7 days const endDate = params.endDate ? new Date(params.endDate) : new Date(); const startDate = params.startDate ? new Date(params.startDate) : new Date(endDate.getTime() - 7 * 24 * 60 * 60 * 1000); // Get history for specific SLO if (params.sloName) { const history = await getSLOHistory( params.sloName, startDate, endDate, params.granularity ); if (!history) { return NextResponse.json( { error: 'SLO not found' }, { status: 404 } ); } return NextResponse.json(history); } // Get history for category if (params.category) { const histories = await getSLOHistoryByCategory( params.category, startDate, endDate ); return NextResponse.json({ category: params.category, slos: histories, }); } // Return all SLOs with trends as default const slosWithTrends = await getAllSLOsWithTrends(); return NextResponse.json({ slos: slosWithTrends }); } catch (error) { if (error instanceof z.ZodError) { return NextResponse.json( { error: 'Invalid query parameters', details: error.issues }, { status: 400 } ); } logger.error('SLO history API error', error instanceof Error ? error : new Error(String(error)), { category: 'API' }); return NextResponse.json( { error: 'Internal server error' }, { status: 500 } ); } } |