@algoan/nestjs-logging-interceptor

中文文档
2.9.0发布于 2026/09/24ISCTypeScriptCommonJS构建来源已验证近 30 天下载 2万

一个简单的 NestJS 截取器来记录输入/输出请求

中文使用文档
文档目录9 节
  1. 安装
  2. 使用量
  3. 默认使用
  4. 工厂
  5. 日志消息
  6. 默认 Logger 信件
  7. 化妆
  8. 截断
  9. 使用自定义锁定器

Nest Logo

A 类 鸟巢 用于登录进/出请求的截取器.

NestJS 记录拦截器

一个简单的NestJS截取器 捕捉请求的细节并使用内置记录 锁定器 课。 它会使用默认的 Logger 执行, 除非您将自己的程序传递给您的巢穴应用程序 .

安装

npm install --save @algoan/nestjs-logging-interceptor

使用量

默认使用

使用截取器作为全局截取器(参见 最后段落 (详见本节).

示例

import { Module } from '@nestjs/common';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { LoggingInterceptor } from '@algoan/nestjs-logging-interceptor';

/**
 * Core module: This module sets the logging interceptor as a global interceptor
 */
@Module({
  providers: [
    {
      provide: APP_INTERCEPTOR,
      useClass: LoggingInterceptor,
    },
  ],
})
export class CoreModule {}

在上述例子中,拦截器由CoreModule提供. 它可以设置在您主模块使用的任何模块上 .

工厂

也可以手动通过工厂函数传递截取器实例. 这样,就有可能制定 userPrefix 默认上下文消息的首端:

示例

import { Module } from '@nestjs/common';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { LoggingInterceptor } from '@algoan/nestjs-logging-interceptor';

/**
 * Core module: This module sets the logging interceptor as a global interceptor
 */
@Module({
  providers: [
    {
      provide: APP_INTERCEPTOR,
      useFactory: () => new LoggingInterceptor({ userPrefix: 'ExampleApp'}),
    },
  ],
})
export class CoreModule {}

上下文消息将预先由提供的 userPrefix数字 :

[LoggingInterceptor - GET - /error] Incoming request - GET - /error
==>
[ExampleApp - LoggingInterceptor - GET - /error] Incoming request - GET - /error

日志消息

截取器日志 :

  • 收到的请求细节
  • 发出答复的细节

默认 Logger 信件

# Incoming request details

# info level
[Nest] 27080   - 04/06/2020, 10:11:54 AM   [LoggingInterceptor - GET - /] Object:
{
  "message": "LoggingInterceptor - GET - /",
  "method": "GET",
  "body": {},
  "headers": {
    "host": "localhost:3000",
    "user-agent": "insomnia/7.1.1",
    "authorization": "Bearer 1234",
    "accept": "*/*"
  }
}
  • 发送请求细节( info + (debug qq警告qq错误))
# Success example

# Info level
[Nest] 27080   - 04/06/2020, 10:11:54 AM   [LoggingInterceptor - 200 - GET - /] Object:
{
  "message": "LoggingInterceptor - 200 - GET - /",
  "body": "Hello World!"
}

# Warning example

# warn level
[Nest] 27080   - 04/06/2020, 10:12:44 AM   [LoggingInterceptor - 400 - GET - /badrequest] Object:
{
  "method": "GET",
  "url": "/badrequest",
  "error": {
    "response": {
      "statusCode": 400,
      "message": "Bad Request"
    },
    "status": 400,
    "message": "Bad Request"
  },
  "body": {},
  "message": "LoggingInterceptor - 400 - GET - /badrequest"
}

# Error example

# error level
[Nest] 27080   - 04/06/2020, 10:12:17 AM   [LoggingInterceptor - 500 - GET - /error] Object:
{
  "method": "GET",
  "url": "/error",
  "body": {},
  "message": "LoggingInterceptor - 500 - GET - /error"
}
 +2ms
Error: Internal Server Error
    at AppController.error (/Users/philippediep/Documents/workspace/algoan/examples/example-manager/dist/app.controller.js:25:15)
    at /Users/philippediep/Documents/workspace/algoan/examples/example-manager/node_modules/@nestjs/core/router/router-execution-context.js:37:29
    at InterceptorsConsumer.transformDeffered (/Users/philippediep/Documents/workspace/algoan/examples/example-manager/node_modules/@nestjs/core/interceptors/interceptors-consumer.js:30:28)
    at /Users/philippediep/Documents/workspace/algoan/examples/example-manager/node_modules/@nestjs/core/interceptors/interceptors-consumer.js:14:48
    at Observable._subscribe (/Users/philippediep/Documents/workspace/algoan/examples/example-manager/node_modules/rxjs/internal/observable/defer.js:10:21)
    at Observable._trySubscribe (/Users/philippediep/Documents/workspace/algoan/examples/example-manager/node_modules/rxjs/internal/Observable.js:44:25)
    at Observable.subscribe (/Users/philippediep/Documents/workspace/algoan/examples/example-manager/node_modules/rxjs/internal/Observable.js:30:22)
    at Object.subscribeToResult (/Users/philippediep/Documents/workspace/algoan/examples/example-manager/node_modules/rxjs/internal/util/subscribeToResult.js:12:23)
    at MergeMapSubscriber._innerSub (/Users/philippediep/Documents/workspace/algoan/examples/example-manager/node_modules/rxjs/internal/operators/mergeMap.js:82:53)
    at MergeMapSubscriber._tryNext (/Users/philippediep/Documents/workspace/algoan/examples/example-manager/node_modules/rxjs/internal/operators/mergeMap.js:76:14)

化妆

默认情况下,整个请求和回复的正文会被登录. 然而,有效载荷可能包含您想隐藏在日志中的敏感数据. 这个 Log 装饰器提供遮盖选项,可以覆盖每个端点所记录的默认属性. 您只需要提供属性的路径来掩盖请求和/或响应. 相应的值将被占位符所取代 **** 在结果的日志中.

例如:

import { Log } from '@algoan/nestjs-logging-interceptor'
import { Body, Controller } from '@nestjs/common';

@Controller('users')
export class UsersController {

  @Post()
  @Log({
    mask: {
      request: [
        'lastName', // simple property
        'maritalSituation', // object property
        'contact.phone', // nested property
        'friends.lastName' // property of an array element
        ],
      response: ['lastName'],
    },
  })
  public createUser(@Body() payload: UserDto) {
    // create and return the new user
  }
}

如果终点被调用为:

{
  "firstName": "John",
  "lastName": "Doe",
  "maritalSituation": {
    "status": "MARRIED",
    "wife": { "firstName": "Jane", "lastName": "Doe" }
  },
  "contact": { "email": "[email protected]", "phone": "+330102030405" },
  "friends": [
    { "firstName": "James", "lastName": "Smith" },
    { "firstName": "Emma", "lastName": "Cole" }
  ]
}

登录请求中的机构为:

{
  "firstName": "John",
  "lastName": "****",
  "maritalSituation": "****",
  "contact": { "email": "[email protected]", "phone": "****" },
  "friends": [
    { "firstName": "James", "lastName": "****" },
    { "firstName": "Emma", "lastName": "****" }
  ]
}

如果你想掩盖请求/答复的整个内容,你可以通过 true 而不是包含详尽属性列表的数组.

此外,还可以在拦截器级别设置其他选项:

import { Module } from '@nestjs/common';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { LoggingInterceptor } from '@algoan/nestjs-logging-interceptor';

@Module({
  providers: [
    {
      provide: APP_INTERCEPTOR,
      useFactory: () =>
        new LoggingInterceptor({
          disableMasking: true, // Ignore masking options in the entire applications
          maskingPlaceholder: 'hidden', // Replace the default placeholder '****' by a custom one
          mask: {
            requestHeader: {
              password: true, // Mask the header 'password' in the request
              authorization: (header: string | string[]) => {
                ... // Handle the header value to keep non sensitive data for instance
              }
            },
          },
        }),
    },
  ],
})
export class CoreModule {}

截断

默认情况下,整个请求和回复的正文会被登录. 然而,您可能用来存储和访问您的日志的监测平台,其日志大小限制会低于您的身体要求. 这个 Log 装饰器提供了可为每个端点截取默认截取选项的截取选项. 你只需要提供极限。 身体记录将在限定时间被截取,或者如果您提供了 truncate 函数.

例如:

import { Log } from '@algoan/nestjs-logging-interceptor'
import { Body, Controller } from '@nestjs/common';

@Controller('users')
export class UsersController {

  @Post()
  @Log({
    truncation: {
      limit: 10000,
      truncate: (body) => ({
        ...body,
        friends: 'TRUNCATED'
      }),
    }
  })
  public createUser(@Body() payload: UserDto) {
    // create and return the new user
  }
}

如果终点被调用为:

{
  "firstName": "John",
  "lastName": "Doe",
  "maritalSituation": {
    "status": "MARRIED",
    "wife": { "firstName": "Jane", "lastName": "Doe" }
  },
  "contact": { "email": "[email protected]", "phone": "+330102030405" },
  "friends": [
    { "firstName": "James", "lastName": "Smith" },
    { "firstName": "Emma", "lastName": "Cole" }
    // ... thousands of other friends
  ]
}

登录请求中的机构为:

{
  "firstName": "John",
  "lastName": "Doe",
  "maritalSituation": {
    "status": "MARRIED",
    "wife": { "firstName": "Jane", "lastName": "Doe" }
  },
  "contact": { "email": "[email protected]", "phone": "+330102030405" },
  "friends": "TRUNCATED"
}

如果没有截取选项,它将被转换为字符串并切入极限.

该选项也可以同时适用于所有路线:

import { Module } from '@nestjs/common';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { LoggingInterceptor } from '@algoan/nestjs-logging-interceptor';

@Module({
  providers: [
    {
      provide: APP_INTERCEPTOR,
      useFactory: () =>
        new LoggingInterceptor({
          truncation: {
            limit: 10000
          }
        }),
    },
  ],
})
export class CoreModule {}

使用自定义锁定器

鸟巢

在这个例子中,我们将用一个 Pino 日志来覆盖默认的 Logger 执行(参见 此 NestJS 的官方文档(中文(简体) )

import { Module } from '@nestjs/common';
import { CoreModule } from './core/core.module'; // the module importing the @algoan/nestjs-logging-interceptor
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { LoggerModule } from 'nestjs-pino';

@Module({
  imports: [LoggerModule.forRoot(), CoreModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

然后在应用的靴子,设置 皮诺伐木机 以代替默认的Logger.

import { NestFactory} from '@nestjs/core';
import { Logger } from "nestjs-pino";
import { MainModule } from './main.module';

async function bootstrap() {
  const app = await NestFactory.create(MainModule,{
    logger: false
  });

  app.useLogger(app.get(Logger))
  await app.listen(3000);
}
bootstrap();

Pino 日志将被设定为 Logger 执行程序.

# With default Logger
[Nest] 84392   - 04/03/2020, 2:02:04 PM   [RoutesResolver] AppController {}: +7ms
[Nest] 84392   - 04/03/2020, 2:02:04 PM   [RouterExplorer] Mapped {, GET} route +3ms
[Nest] 84392   - 04/03/2020, 2:02:04 PM   [RouterExplorer] Mapped {/badrequest, GET} route +0ms
[Nest] 84392   - 04/03/2020, 2:02:04 PM   [RouterExplorer] Mapped {/error, GET} route +0ms
[Nest] 84392   - 04/03/2020, 2:02:04 PM   [NestApplication] Nest application successfully started +3ms

# With Pino Logger
{"level":30,"time":1585915251917,"pid":83826,"hostname":"computername.local","context":"RoutesResolver","msg":"AppController {}: true","v":1}
{"level":30,"time":1585915251919,"pid":83826,"hostname":"computername.local","context":"RouterExplorer","msg":"Mapped {, GET} route true","v":1}
{"level":30,"time":1585915251919,"pid":83826,"hostname":"computername.local","context":"RouterExplorer","msg":"Mapped {/badrequest, GET} route true","v":1}
{"level":30,"time":1585915251919,"pid":83826,"hostname":"computername.local","context":"RouterExplorer","msg":"Mapped {/error, GET} route true","v":1}
{"level":30,"time":1585915251921,"pid":83826,"hostname":"computername.local","context":"NestApplication","msg":"Nest application successfully started true","v":1}

版本与发布记录

@algoan/nestjs-logging-interceptor 共发布 35 个版本,首次发布于 2020/04/03;过去 12 个月发布了 2 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
2.9.0latest2026/09/241 个月前
2.8.12026/09/221 个月前
2.8.02025/08/251.2 年前
2.7.02024/09/162 年前
2.6.02024/02/162 年前
2.5.12023/12/112 年前

关于 @algoan/nestjs-logging-interceptor 的常见问题

@algoan/nestjs-logging-interceptor 是什么?

一个简单的 NestJS 截取器来记录输入/输出请求

如何安装 @algoan/nestjs-logging-interceptor?

在项目目录运行 npm install @algoan/nestjs-logging-interceptor,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:rxjs(>=6)、express(>=4)、@nestjs/core(>=5)、@nestjs/common(>=5)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@algoan/nestjs-logging-interceptor 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@algoan/nestjs-logging-interceptor 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@algoan/nestjs-logging-interceptor 可以商用吗?

@algoan/nestjs-logging-interceptor 使用 ISC 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@algoan/nestjs-logging-interceptor 的下载量有多少?

根据 npm 官方下载统计,@algoan/nestjs-logging-interceptor 在 2026/10/06 – 2026/11/04 这 30 天内被下载 19,667 次,日均约 656 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@algoan/nestjs-logging-interceptor 还在维护吗?

最新版本 2.9.0 发布于 2026/09/24(1 个月前);至今共发布 35 个版本,其中过去 12 个月发布了 2 个;首次发布于 2020/04/03。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。