xpeditis2.0/apps/backend/src/application/logs/logs.controller.ts
David bbf059cce9
Some checks failed
CD Preprod / Backend — Lint (push) Successful in 10m22s
CD Preprod / Frontend — Lint & Type-check (push) Successful in 10m55s
CD Preprod / Backend — Unit Tests (push) Successful in 10m12s
CD Preprod / Frontend — Unit Tests (push) Successful in 10m33s
CD Preprod / Backend — Integration Tests (push) Successful in 9m57s
CD Preprod / Build Backend (push) Successful in 7m51s
CD Preprod / Build Log Exporter (push) Successful in 34s
CD Preprod / Build Frontend (push) Successful in 19m46s
CD Preprod / Deploy to Preprod (push) Failing after 1s
CD Preprod / Notify Failure (push) Has been skipped
CD Preprod / Smoke Tests (push) Has been skipped
CD Preprod / Notify Success (push) Has been skipped
fix preprod
2026-04-06 14:21:32 +02:00

99 lines
2.7 KiB
TypeScript

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<string>(
'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);
}
}
}