夜猫子的知识栈 夜猫子的知识栈
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《Web Api》
    • 《ES6教程》
    • 《Vue》
    • 《React》
    • 《TypeScript》
    • 《Git》
    • 《Uniapp》
    • 小程序笔记
    • 《Electron》
    • JS设计模式总结
  • 《前端架构》

    • 《微前端》
    • 《权限控制》
    • monorepo
  • 全栈项目

    • 任务管理日历
    • 无代码平台
    • 图书管理系统
  • HTML
  • CSS
  • Nodejs
  • Midway
  • Nest
  • MySql
  • 其他
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • Ajax
  • Vite
  • Vitest
  • Nuxt
  • UI库文章
  • Docker
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

夜猫子

前端练习生
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《Web Api》
    • 《ES6教程》
    • 《Vue》
    • 《React》
    • 《TypeScript》
    • 《Git》
    • 《Uniapp》
    • 小程序笔记
    • 《Electron》
    • JS设计模式总结
  • 《前端架构》

    • 《微前端》
    • 《权限控制》
    • monorepo
  • 全栈项目

    • 任务管理日历
    • 无代码平台
    • 图书管理系统
  • HTML
  • CSS
  • Nodejs
  • Midway
  • Nest
  • MySql
  • 其他
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • Ajax
  • Vite
  • Vitest
  • Nuxt
  • UI库文章
  • Docker
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Node基础

  • 《MySQL》学习笔记

  • Midway

  • Nest

    • 开篇词
    • 学习理由
    • nest概念扫盲
    • 快速掌握 nestcli
    • 5种http数据传输方式
    • IoC 解决了什么痛点问题?
    • 如何调试 Nest 项目
    • Provider注入对象
    • 全局模块和生命周期
    • AOP 架构有什么好处?
    • 一网打尽 Nest 全部装饰器
    • Nest如何自定义装饰器
    • Metadata和Reflector
    • ExecutionContext切换上下文
    • Module和Provider的循环依赖处理
    • 如何创建动态模块
    • Nest和Express,fastify
    • Nest的Middleware
    • RxJS和Interceptor
    • 内置Pipe和自定义Pipe
    • ValidationPipe验证post请求参数
    • 如何自定义 Exception Filter
    • 图解串一串 Nest 核心概念
    • 接口如何实现多版本共存
    • Express如何使用multer实现文件上传
    • Nest使用multer实现文件上传
    • 图书管理系统
    • 大文件分片上传
    • 最完美的 OSS 上传方案
    • Nest里如何打印日志
      • 测试打印日志
      • 控制日志
        • 控制是否开启
        • 控制可输出的日志类型
        • 自定义日志输出方式
        • 自定义日志注入依赖
        • 设置全局模块实现任意注入
        • 动态模块注入实现不同配置
      • 总结
    • 为什么Node里要用Winston打印日志
    • Nest 集成日志框架 Winston
    • 通过Desktop学Docker也太简单了
    • 你的第一个 Dockerfile
  • 其他

  • 服务端
  • Nest
神说要有光
2025-03-10
目录

Nest里如何打印日志

前面我们都是用 console.log 打印的日志,这样有不少弊端:没有日志的不同级别的区分,不能通过开关控制是否打印等。

其实 Nest 提供了打印日志的 api,这节我们就来学习一下吧。

还是先创建个项目:

nest new logger-test -p npm
1

进入目录,执行 nest start --watch 把服务跑起来。

Nest 会打印这些日志:

它也同样提供了打印这种日志的 api。

# 测试打印日志

我们在 AppController 里创建个 logger 对象,使用它的 api 打印日志:

import { ConsoleLogger, Controller, Get, Logger } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  private logger = new Logger();

  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    this.logger.debug('aaa', AppController.name);
    this.logger.error('bbb', AppController.name);
    this.logger.log('ccc', AppController.name);
    this.logger.verbose('ddd', AppController.name);
    this.logger.warn('eee', AppController.name);
    
    return this.appService.getHello();
  }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

浏览器访问下:

会打印这样的日志:

这里的 verbose、debug、log、warn、error 就是日志级别,而 [] 中的是 context,也就是当前所在的上下文,最后是日志的内容。

# 控制日志

# 控制是否开启

这个日志是受 Nest 控制的,可以在创建应用的时候指定是否开启:

设置 logger 为 false 之后就没有日志了。

# 控制可输出的日志类型

你也可以自己决定输出什么级别的日志:

# 自定义日志输出方式

此外,你还可以自定义日志打印的方式,定义一个实现 LoggerService 接口的类:

只要实现 log、warn、error 3 个方法就好了:

import { LoggerService, LogLevel } from '@nestjs/common';

export class MyLogger implements LoggerService {
    log(message: string, context: string) {
        console.log(`---log---[${context}]---`, message)
    }

    error(message: string, context: string) {
        console.log(`---error---[${context}]---`, message)
    }

    warn(message: string, context: string) {
        console.log(`---warn---[${context}]---`, message)
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

在创建应用时指定这个 logger:

然后现在项目启动就是这样了:

刷新页面打印的日志是这样的:

确实还挺丑的。。

我们只是测试下自定义 Logger。

你也可以不自己实现 LoggerService 的全部方法,而是继承 ConsoleLogger,重写一些方法:

import { ConsoleLogger } from '@nestjs/common';

export class MyLogger2 extends ConsoleLogger{
    log(message: string, context: string) {
        console.log(`[${context}]`,message)
    }
}
1
2
3
4
5
6
7

因为 ConsoleLogger 实现了 LoggerService 接口:

这样你没重写的方法就是原来的:

这就是创建应用时 logger 的 3 种取值:

# 自定义日志注入依赖

但这样有个问题,没法注入依赖,因为 Logger 是在容器外面,手动 new 的对象。

怎么办呢?

这时候可以这样:

bufferLogs 就是先不打印日志,把它放到 buffer 缓冲区,直到用 useLogger 指定了 Logger 并且应用初始化完毕。

app.get 就是从容器中取这个类的实例的,我们写一个 Logger 类放到容器里:

import { Inject } from '@nestjs/common';
import { ConsoleLogger, Injectable } from '@nestjs/common';
import { AppService } from './app.service';

@Injectable()
export class MyLogger3 extends ConsoleLogger{
    @Inject(AppService)
    private appService: AppService;

    log(message, context) {
        console.log(this.appService.getHello());
        console.log(`[${context}]`, message);
        console.log('--------------')
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

添加 @Injectable() 装饰器,代表这是一个 provider,并且要在 Module 里引入:

通过 @Inject 注入 AppService,并在 log 的时候调用。

现在的日志是这样的:

很明显,logger 里成功注入了 appService 的依赖。

我们可以单独搞一个模块来放 Logger。

nest g module logger

# 设置全局模块实现任意注入

把这个 Module 设置为全局模块:

这样在任何地方都可以注入这个 logger 对象了。

我们创建个新模块:

nest g resource aaa 
1

在这个模块里可以直接注入 MyLogger,不用 imports 那个 Module。

测试下:

可以看到,成功注入了 MyLogger。

# 动态模块注入实现不同配置

或者你也可以声明一个动态模块,每次 imports 的时候配置下:

import { DynamicModule, Global, Module } from '@nestjs/common';
import { MyLogger } from './MyLogger';

@Module({})
export class Logger2Module{

    static register(options): DynamicModule {
        return {
            module: Logger2Module,
            providers: [
                MyLogger, 
                {
                    provide: 'LOG_OPTIONS',
                    useValue: options
                }
            ],
            exports: [MyLogger, 'LOG_OPTIONS']
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

把传入的 options 作为 provider,在 Logger 里注入:

每次 imports 的时候传入不同的配置:

在 AppService 里注入下:

import { Inject, Injectable } from '@nestjs/common';
import { MyLogger } from './logger2/MyLogger';

@Injectable()
export class AppService {

  @Inject(MyLogger)
  private logger: MyLogger;

  getHello(): string {
    this.logger.log('yyy', AppService.name);
    
    return 'Hello World!';
  }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

浏览器访问 http://localhost:3000 就可以看到 MyLogger 打印的传入的 option:

具体是用全局模块还是动态模块,可以根据情况来选择。

案例代码在小册仓库 (opens new window)。

# 总结

日志打印可以用 Nest 的 Logger,它支持在创建应用的时候指定 logger 是否开启,打印的日志级别,还可以自定义 logger。

自定义 Logger 需要实现 LoggerService 接口,或者继承 ConsoleLogger 然后重写部分方法。

可以在 main.ts 中替换全局 Logger 或通过依赖注入实现指定部分输出自定义 Logger。

如果想在 Logger 注入一些 provider,就需要创建应用时设置 bufferLogs 为 true,然后用 app.useLogger(app.get(xxxLogger)) 来指定 Logger。

你可以把这个自定义 Logger 封装到全局模块,或者动态模块里。

当然,一般情况下,直接使用 Logger 就可以了。

编辑 (opens new window)
上次更新: 2025/5/14 16:47:16
最完美的 OSS 上传方案
为什么Node里要用Winston打印日志

← 最完美的 OSS 上传方案 为什么Node里要用Winston打印日志→

最近更新
01
IoC 解决了什么痛点问题?
03-10
02
如何调试 Nest 项目
03-10
03
Provider注入对象
03-10
更多文章>
Copyright © 2019-2025 Study | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式