npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@lucassith/nest-winston

v2.0.0

Published

A Nest module wrapper for winston

Downloads

155

Readme

Table of Contents

Installation

npm install --save @lucassith/@lucassith/nest-winston winston

Having troubles configuring @lucassith/@lucassith/nest-winston? Clone this repository and cd in a sample:

cd sample/quick-start
npm install
npm run start:dev

If you want to upgrade to a major or minor version, have a look at the upgrade section.

Quick start

Import WinstonModule into the root AppModule and use the forRoot() method to configure it. This method accepts the same options object as createLogger() function from the winston package:

import { Module } from '@nestjs/common';
import { WinstonModule } from '@lucassith/@lucassith/nest-winston';
import * as winston from 'winston';

@Module({
  imports: [
    WinstonModule.forRoot({
      // options
    }),
  ],
})
export class AppModule {}

Afterward, the winston instance will be available to inject across entire project (and in your feature modules, being WinstonModule a global one) using the WINSTON_MODULE_PROVIDER injection token:

import { Controller, Inject } from '@nestjs/common';
import { WINSTON_MODULE_PROVIDER } from '@lucassith/nest-winston';
import { Logger } from 'winston';

@Controller('cats')
export class CatsController {
  constructor(@Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger) { }
}

Async configuration

Caveats: because the way Nest works, you can't inject dependencies exported from the root module itself (using exports). If you use forRootAsync() and need to inject a service, that service must be either imported using the imports options or exported from a global module.

Maybe you need to asynchronously pass your module options, for example when you need a configuration service. In such case, use the forRootAsync() method, returning an options object from the useFactory method:

import { Module } from '@nestjs/common';
import { WinstonModule } from '@lucassith/nest-winston';
import * as winston from 'winston';

@Module({
  imports: [
    WinstonModule.forRootAsync({
      useFactory: () => ({
        // options
      }),
      inject: [],
    }),
  ],
})
export class AppModule {}

The factory might be async, can inject dependencies with inject option and import other modules using the imports option.

Alternatively, you can use the useClass syntax:

WinstonModule.forRootAsync({
  useClass: WinstonConfigService,
})

With the above code, Nest will create a new instance of WinstonConfigService and its method createWinstonModuleOptions will be called in order to provide the module options.

Replacing the Nest logger

This module also provides the WinstonLogger class (custom implementation of the LoggerService interface) to be used by Nest for system logging. This will ensure consistent behavior and formatting across both Nest system logging and your application event/message logging.

Change your main.ts as shown below:

import { WINSTON_MODULE_NEST_PROVIDER } from '@lucassith/nest-winston';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useLogger(app.get(WINSTON_MODULE_NEST_PROVIDER));
  await app.listen(3000);
}
bootstrap();

Then inject the logger using the WINSTON_MODULE_NEST_PROVIDER token and the LoggerService typing:

import { Controller, Inject, LoggerService } from '@nestjs/common';
import { WINSTON_MODULE_NEST_PROVIDER } from '@lucassith/nest-winston';

@Controller('cats')
export class CatsController {
  constructor(@Inject(WINSTON_MODULE_NEST_PROVIDER) private readonly logger: LoggerService) { }
}

Under the hood, the WinstonLogger class uses the configured winston logger instance (through forRoot or forRootAsync), forwarding all calls to it.

Replacing the Nest logger (also for bootstrapping)

Important: by doing this, you give up the dependency injection, meaning that forRoot and forRootAsync are not needed and shouldn't be used. Remove them from your main module.

Using the dependency injection has one minor drawback. Nest has to bootstrap the application first (instantiating modules and providers, injecting dependencies, etc.) and during this process the instance of WinstonLogger is not yet available, which means that Nest falls back to the internal logger.

One solution is to create the logger outside of the application lifecycle, using the createLogger function, and pass it to NestFactory.create. Nest will then wrap our winston logger (the same instance returned by the createLogger method) into the Logger class, forwarding all calls to it:

import { WinstonModule } from '@lucassith/nest-winston';

async function bootstrap() {
  const app = await NestFactory.create(AppModule, {
    logger: WinstonModule.createLogger({
      // options (same as WinstonModule.forRoot() options)
    })
  });
  await app.listen(3000);
}
bootstrap();

An alternative is to provide directly an instance of Winston in the options. This allows you to keep a reference to the instance and interact with it.

import { createLogger } from 'winston';
import { WinstonModule } from '@lucassith/nest-winston';

async function bootstrap() {
  // createLogger of Winston
  const instance = createLogger({
    // options of Winston
  });
  const app = await NestFactory.create(AppModule, {
    logger: WinstonModule.createLogger({
      instance,
    }),
  });
  await app.listen(3000);
}
bootstrap();

The usage afterwards for both solutions is the same. First, change your main module to provide the Logger service:

import { Logger, Module } from '@nestjs/common';

@Module({
  providers: [Logger],
})
export class AppModule {}

Then inject the logger simply by type hinting it with Logger from @nestjs/common:

import { Controller, Logger } from '@nestjs/common';

@Controller('cats')
export class CatsController {
  constructor(private readonly logger: Logger) {}
}

Alternative syntax using the LoggerService typing and the @Inject decorator:

import { Controller, Inject, Logger, LoggerService } from '@nestjs/common';

@Controller('cats')
export class CatsController {
  constructor(@Inject(Logger) private readonly logger: LoggerService) {}
}

Injection and usage summary

Here is a summary of the three techniques explained above:

| Injection token | Typing | Module config | Usage | | :----------------------------- | :------------------------------------ | :------------ | :--------------------------------------------------------------------- | | WINSTON_MODULE_PROVIDER | Logger from winston | Yes | + Your application/message logging | WINSTON_MODULE_NEST_PROVIDER | LoggerService from @nestjs/common | Yes | + Your application/message logging + Nest logger | | none | Logger from @nestjs/common | No | + Your application/message logging + Nest logger + Application bootstrapping |

Utilities

The module also provides a custom Nest-like special formatter for console transports named nestLike. Supported options:

  • colors: enable console colors, defaults to true, unless process.env.NO_COLOR is set (same behaviour of Nest > 7.x)
  • prettyPrint: pretty format log metadata, defaults to true
  • processId: includes the Node Process ID (process.pid) in the output, defaults to true
import { Module } from '@nestjs/common';
import { utilities as nestWinstonModuleUtilities, WinstonModule } from '@lucassith/nest-winston';
import * as winston from 'winston';

@Module({
  imports: [
    WinstonModule.forRoot({
      transports: [
        new winston.transports.Console({
          format: winston.format.combine(
            winston.format.timestamp(),
            winston.format.ms(),
            nestWinstonModuleUtilities.format.nestLike('MyApp', {
              colors: true,
              prettyPrint: true,
              processId: true
            }),
          ),
        }),
        // other transports...
      ],
      // other options
    }),
  ],
})
export class AppModule {}

Logger methods

Note: the logger instance has different logger methods, and each takes different arguments. To make sure the logger is being formatted the same way across the board take note of the following:

debug(message: any, context?: string)
log(message: any, context?: string)
error(message: any, stack?: string, context?: string)
fatal(message: any, stack?: string, context?: string)
verbose(message: any, context?: string)
warn(message: any, context?: string)

Example:

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

@Controller()
export class AppController {
  constructor(
    private readonly appService: AppService,
    private readonly logger: Logger,
  ) {}

  @Get()
  getHello(): string {
    this.logger.log('Calling getHello()', AppController.name);
    this.logger.debug('Calling getHello()', AppController.name);
    this.logger.verbose('Calling getHello()', AppController.name);
    this.logger.warn('Calling getHello()', AppController.name);

    try {
      throw new Error()
    } catch (e) {
      this.logger.error('Calling getHello()', e.stack, AppController.name);
    }

    return this.appService.getHello();
  }
}

Upgrade

Some notes about upgrading to a major or minor version.

1.6.x to 1.7

  • The exported type NestLikeConsoleFormatOptions has slightly changed: prettyPrint is now optional and colors has been added.
  • The nestLike formatter has the new colors option: if not provided, colors will be used according to Nest "approach" (disabled if env variable process.env.NO_COLOR is defined). Before output was always colorized.

Contributing

All types of contributions are encouraged and valued. See the Contributing guidelines, the community looks forward to your contributions!

Contributors list

License

This project is released under the under terms of the ISC License.