A Logging Interceptor
Use an interceptor to log every request's method, path, and duration.
app.useGlobalInterceptors(new LoggingInterceptor())Interceptors are ideal for cross-cutting concerns like logging. A single logging interceptor can time every request in your app.
How it works
Before the handler runs, record the start time and request info. After the handler completes, use the RxJS tap operator to log the elapsed time. Register it globally with app.useGlobalInterceptors() to cover all routes.
Example
import { CallHandler, ExecutionContext, Injectable, Logger, NestInterceptor } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
private logger = new Logger('HTTP');
intercept(ctx: ExecutionContext, next: CallHandler): Observable<any> {
const req = ctx.switchToHttp().getRequest();
const start = Date.now();
return next.handle().pipe(
tap(() => this.logger.log(`${req.method} ${req.url} +${Date.now() - start}ms`)),
);
}
}When to use it
- A developer applies a LoggingInterceptor globally to log every request method, URL, and response time to stdout in production.
- A team configures the interceptor to emit a warning log when a handler takes longer than 1000 ms, helping identify slow endpoints.
- An engineer uses the interceptor to add an X-Response-Time header to every response so clients can measure server-side latency.
More examples
Basic logging interceptor
Logs the HTTP method, URL, and elapsed time for every request using NestJS Logger and an RxJS tap operator.
import { Injectable, NestInterceptor, ExecutionContext, CallHandler, Logger } from '@nestjs/common';
import { Observable, tap } from 'rxjs';
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
private readonly logger = new Logger('HTTP');
intercept(ctx: ExecutionContext, next: CallHandler): Observable<any> {
const req = ctx.switchToHttp().getRequest();
const start = Date.now();
return next.handle().pipe(
tap(() => this.logger.log(`${req.method} ${req.url} - ${Date.now() - start}ms`)),
);
}
}Warn on slow handlers
Emits a warning log only when a handler exceeds 1000 ms, making slow endpoints easy to spot without logging every fast request.
intercept(ctx: ExecutionContext, next: CallHandler): Observable<any> {
const req = ctx.switchToHttp().getRequest();
const start = Date.now();
return next.handle().pipe(
tap(() => {
const ms = Date.now() - start;
if (ms > 1000) {
this.logger.warn(`SLOW ${req.method} ${req.url} took ${ms}ms`);
}
}),
);
}Register logging interceptor globally
Registers the interceptor globally via the APP_INTERCEPTOR token so the DI container can inject services into the interceptor itself.
import { APP_INTERCEPTOR } from '@nestjs/core';
import { LoggingInterceptor } from './logging.interceptor';
@Module({
providers: [
{ provide: APP_INTERCEPTOR, useClass: LoggingInterceptor },
],
})
export class AppModule {}
Discussion