File

src/utils/logger/session-logger.interceptor.ts

Description

Interceptor for logging session-related requests and responses.

Index

Methods

Constructor

constructor(reflector: Reflector, sessionLoggerService: SessionLoggerService)

Constructor for SessionLoggerInterceptor.

Parameters :
Name Type Optional Description
reflector Reflector No
  • Reflector instance for accessing metadata.
sessionLoggerService SessionLoggerService No
  • Session Logger service for consistent logging behavior.

Methods

intercept
intercept(context: ExecutionContext, next: CallHandler)

Intercepts the request and logs session-related information.

Parameters :
Name Type Optional Description
context ExecutionContext No
  • Execution context of the request.
next CallHandler No
  • Call handler to proceed with the request.
Returns : Observable<any>

An observable that emits the response data.

Private sanitizeBody
sanitizeBody(body: any)

Sanitizes the request body to remove sensitive information.

Parameters :
Name Type Optional Description
body any No
  • The request body to sanitize.
Returns : any

Sanitized body.

import {
    CallHandler,
    ExecutionContext,
    Injectable,
    NestInterceptor,
} from "@nestjs/common";
import { Reflector } from "@nestjs/core";
import { Observable } from "rxjs";
import { catchError, tap } from "rxjs/operators";
import { SESSION_LOGGER_KEY } from "./session-logger.decorator";
import { SessionLoggerService } from "./session-logger.service";
import { SessionLogContext } from "./session-logger-context";

/**
 * Interceptor for logging session-related requests and responses.
 */
@Injectable()
export class SessionLoggerInterceptor implements NestInterceptor {
    /**
     * Constructor for SessionLoggerInterceptor.
     * @param reflector - Reflector instance for accessing metadata.
     * @param sessionLoggerService - Session Logger service for consistent logging behavior.
     */
    constructor(
        private readonly reflector: Reflector,
        private readonly sessionLoggerService: SessionLoggerService,
    ) {}

    /**
     * Intercepts the request and logs session-related information.
     * @param context - Execution context of the request.
     * @param next - Call handler to proceed with the request.
     * @returns An observable that emits the response data.
     */
    intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
        const metadata = this.reflector.get(
            SESSION_LOGGER_KEY,
            context.getHandler(),
        );

        // Skip if no metadata or logger is disabled (the service will check enablement)
        if (!metadata) {
            return next.handle();
        }

        const { sessionIdParam, flowType } = metadata;
        const request = context.switchToHttp().getRequest();
        const response = context.switchToHttp().getResponse();

        const sessionId = request.params[sessionIdParam];
        const tenantId = request.params?.tenantId;
        const method = request.method;
        const url = request.url;

        // Create log context for consistent logging
        const logContext: SessionLogContext = {
            sessionId,
            tenantId,
            flowType,
            endpoint: `${method} ${url}`,
        };

        // Log the start of the request using SessionLoggerService
        this.sessionLoggerService.logSession(
            logContext,
            `Starting ${method} ${url}`,
            {
                event: "request_start",
                method,
                url,
                headers: {
                    "user-agent": request.headers["user-agent"],
                    "content-type": request.headers["content-type"],
                },
                body: this.sanitizeBody(request.body),
            },
        );

        const startTime = Date.now();

        return next.handle().pipe(
            tap((data) => {
                const duration = Date.now() - startTime;
                // Log successful request completion
                this.sessionLoggerService.logSession(
                    logContext,
                    `Completed ${method} ${url} in ${duration}ms`,
                    {
                        event: "request_success",
                        method,
                        url,
                        statusCode: response.statusCode,
                        duration,
                        responseSize: JSON.stringify(data || {}).length,
                    },
                );
            }),
            catchError((error) => {
                const duration = Date.now() - startTime;
                // Log request error
                this.sessionLoggerService.logSessionError(
                    logContext,
                    error,
                    `Error in ${method} ${url}`,
                    {
                        event: "request_error",
                        method,
                        url,
                        duration,
                    },
                );
                throw error;
            }),
        );
    }

    /**
     * Sanitizes the request body to remove sensitive information.
     * @param body - The request body to sanitize.
     * @returns Sanitized body.
     */
    private sanitizeBody(body: any): any {
        if (!body) return body;

        // Create a copy to avoid modifying the original
        const sanitized = { ...body };

        // Remove sensitive fields
        const sensitiveFields = [
            "password",
            "token",
            "secret",
            "key",
            "private_key",
            "access_token",
            "refresh_token",
        ];

        sensitiveFields.forEach((field) => {
            if (sanitized[field]) {
                sanitized[field] = "[REDACTED]";
            }
        });

        return sanitized;
    }
}

results matching ""

    No results matching ""