import { Controller, Get, Query, Res, UseGuards, HttpException, HttpStatus } from '@nestjs/common'; import { Response } from 'express'; import { ConfigService } from '@nestjs/config'; import { JwtAuthGuard } from '../guards/jwt-auth.guard'; import { RolesGuard } from '../guards/roles.guard'; import { Roles } from '../decorators/roles.decorator'; @Controller('logs') @UseGuards(JwtAuthGuard, RolesGuard) @Roles('admin') export class LogsController { private readonly logExporterUrl: string; constructor(private readonly configService: ConfigService) { this.logExporterUrl = this.configService.get( 'LOG_EXPORTER_URL', 'http://xpeditis-log-exporter:3200' ); } /** * GET /api/v1/logs/services * Proxy → log-exporter /api/logs/services */ @Get('services') async getServices() { try { const res = await fetch(`${this.logExporterUrl}/api/logs/services`, { signal: AbortSignal.timeout(5000), }); if (!res.ok) throw new Error(`log-exporter error: ${res.status}`); return res.json(); } catch (err: any) { throw new HttpException({ error: err.message }, HttpStatus.BAD_GATEWAY); } } /** * GET /api/v1/logs/export * Proxy → log-exporter /api/logs/export (JSON or CSV) */ @Get('export') async exportLogs( @Query('service') service: string, @Query('level') level: string, @Query('search') search: string, @Query('start') start: string, @Query('end') end: string, @Query('limit') limit: string, @Query('format') format: string = 'json', @Res() res: Response ) { try { const params = new URLSearchParams(); if (service) params.set('service', service); if (level) params.set('level', level); if (search) params.set('search', search); if (start) params.set('start', start); if (end) params.set('end', end); if (limit) params.set('limit', limit); params.set('format', format); const upstream = await fetch(`${this.logExporterUrl}/api/logs/export?${params}`, { signal: AbortSignal.timeout(30000), }); if (!upstream.ok) { const body = await upstream.json().catch(() => ({})); throw new HttpException(body, upstream.status); } res.status(upstream.status); upstream.headers.forEach((value, key) => { if (['content-type', 'content-disposition'].includes(key.toLowerCase())) { res.setHeader(key, value); } }); const buffer = await upstream.arrayBuffer(); res.send(Buffer.from(buffer)); } catch (err: any) { if (err instanceof HttpException) throw err; throw new HttpException({ error: err.message }, HttpStatus.BAD_GATEWAY); } } }