Use Scope.REQUEST so a new interceptor instance is created per request — safe for storing request-level state. Inject the REQUEST token to access the request object. Use tap() to log the response body after the handler completes and catchError() to log failures before re-throwing.
Scope.REQUEST ensures a fresh instance per request — no state leaks between requests.
@Inject(REQUEST) gives direct access to the request object including headers, body, and user.
tap() logs on success without changing the response value.
catchError() logs the error but re-throws — exception filters still format the error response.
Register via APP_INTERCEPTOR with useClass so NestJS manages the REQUEST scope correctly.