Server-Timing
This commit is contained in:
+2
-2
@@ -42,5 +42,5 @@ SMS_SENDER=
|
||||
# SMS_TRANSPORT=soap
|
||||
# SMS_DOMAIN=0098
|
||||
|
||||
# Minimum minutes before a booking can be scheduled (default 60)
|
||||
BOOKING_MIN_LEAD_MINUTES=60
|
||||
# Optional: log Server-Timing to PM2 stdout (total;dur=… per request)
|
||||
# LOG_SERVER_TIMING=true
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import {
|
||||
CallHandler,
|
||||
ExecutionContext,
|
||||
Injectable,
|
||||
Logger,
|
||||
NestInterceptor,
|
||||
} from '@nestjs/common';
|
||||
import { Observable } from 'rxjs';
|
||||
import { finalize } from 'rxjs/operators';
|
||||
|
||||
@Injectable()
|
||||
export class ServerTimingInterceptor implements NestInterceptor {
|
||||
private readonly logger = new Logger(ServerTimingInterceptor.name);
|
||||
|
||||
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {
|
||||
const http = context.switchToHttp();
|
||||
const response = http.getResponse<{
|
||||
setHeader(name: string, value: string): void;
|
||||
getHeader(name: string): string | number | string[] | undefined;
|
||||
}>();
|
||||
const request = http.getRequest<{ method?: string; url?: string }>();
|
||||
const start = performance.now();
|
||||
|
||||
return next.handle().pipe(
|
||||
finalize(() => {
|
||||
const dur = Math.max(0, Math.round(performance.now() - start));
|
||||
const existing = response.getHeader('Server-Timing');
|
||||
const total = `total;dur=${dur}`;
|
||||
response.setHeader(
|
||||
'Server-Timing',
|
||||
existing ? `${String(existing)}, ${total}` : total,
|
||||
);
|
||||
if (process.env.LOG_SERVER_TIMING === 'true') {
|
||||
const route = request.url ?? '';
|
||||
this.logger.log(
|
||||
`${request.method ?? '?'} ${route} total;dur=${dur}`,
|
||||
);
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
+14
-2
@@ -5,17 +5,28 @@ import { NestExpressApplication } from '@nestjs/platform-express';
|
||||
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
|
||||
import { join } from 'path';
|
||||
import { TypeOrmExceptionFilter } from './common/filters/typeorm-exception.filter';
|
||||
import { ServerTimingInterceptor } from './common/interceptors/server-timing.interceptor';
|
||||
import { AppModule } from './app.module';
|
||||
|
||||
const CORS_EXPOSE_HEADERS = ['Server-Timing'];
|
||||
|
||||
function configureCors(app: Awaited<ReturnType<typeof NestFactory.create>>) {
|
||||
const raw = process.env.CORS_ORIGINS?.trim();
|
||||
if (raw) {
|
||||
const origins = raw.split(',').map((o) => o.trim()).filter(Boolean);
|
||||
app.enableCors({ origin: origins, credentials: true });
|
||||
app.enableCors({
|
||||
origin: origins,
|
||||
credentials: true,
|
||||
exposedHeaders: CORS_EXPOSE_HEADERS,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
app.enableCors({ origin: true, credentials: true });
|
||||
app.enableCors({
|
||||
origin: true,
|
||||
credentials: true,
|
||||
exposedHeaders: CORS_EXPOSE_HEADERS,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +43,7 @@ async function bootstrap() {
|
||||
}),
|
||||
);
|
||||
app.useGlobalFilters(new TypeOrmExceptionFilter());
|
||||
app.useGlobalInterceptors(new ServerTimingInterceptor());
|
||||
|
||||
const swaggerConfig = new DocumentBuilder()
|
||||
.setTitle('Montime API')
|
||||
|
||||
Reference in New Issue
Block a user