
Security News
Oracle Drags Its Feet in the JavaScript Trademark Dispute
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
nest-winston
Advanced tools
The nest-winston package is a logging module for NestJS applications that integrates the popular Winston logger. It allows developers to leverage Winston's powerful logging capabilities within the NestJS framework, providing a flexible and configurable logging solution.
Basic Logging
This feature allows you to set up basic logging in a NestJS application using Winston. The example shows how to create a logger with a console transport.
const { WinstonModule } = require('nest-winston');
const winston = require('winston');
const app = await NestFactory.create(AppModule, {
logger: WinstonModule.createLogger({
transports: [
new winston.transports.Console(),
],
}),
});
Custom Transports
This feature allows you to configure custom transports for logging. The example demonstrates how to add file and HTTP transports to the logger.
const { WinstonModule } = require('nest-winston');
const winston = require('winston');
const app = await NestFactory.create(AppModule, {
logger: WinstonModule.createLogger({
transports: [
new winston.transports.File({ filename: 'combined.log' }),
new winston.transports.Http({ host: 'localhost', port: 3000 }),
],
}),
});
Log Formatting
This feature allows you to customize the format of the log messages. The example shows how to combine timestamp and JSON formatting for the logs.
const { WinstonModule } = require('nest-winston');
const winston = require('winston');
const app = await NestFactory.create(AppModule, {
logger: WinstonModule.createLogger({
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.Console(),
],
}),
});
nestjs-pino is a logging module for NestJS that integrates the Pino logger. Pino is known for its performance and low overhead. Compared to nest-winston, nestjs-pino focuses on speed and efficiency, making it suitable for high-performance applications.
nestjs-bunyan is a logging module for NestJS that integrates the Bunyan logger. Bunyan provides a simple and fast JSON logging solution. It is similar to nest-winston in terms of functionality but uses Bunyan's JSON-based logging approach.
nestjs-log4js is a logging module for NestJS that integrates the Log4js logger. Log4js is a versatile logging library that supports various appenders and configurations. Compared to nest-winston, nestjs-log4js offers more flexibility in terms of log output destinations and configurations.
A Nest module wrapper for winston logger.
Table of Contents
npm install --save nest-winston winston
Having troubles configuring 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.
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 '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 'nest-winston';
import { Logger } from 'winston';
@Controller('cats')
export class CatsController {
constructor(@Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger) { }
}
Caveats: because the way Nest works, you can't inject dependencies exported from the root module itself (using
exports
). If you useforRootAsync()
and need to inject a service, that service must be either imported using theimports
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 '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.
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 '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 '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.
Important: by doing this, you give up the dependency injection, meaning that
forRoot
andforRootAsync
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 '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 '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) {}
}
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 |
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
appName
: includes the provided application name in the output, defaults to true
Note: When providing partial options, unspecified options will retain their default values.
import { Module } from '@nestjs/common';
import { utilities as nestWinstonModuleUtilities, WinstonModule } from '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,
appName: true,
}),
),
}),
// other transports...
],
// other options
}),
],
})
export class AppModule {}
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();
}
}
Some notes about upgrading to a major or minor version.
NestLikeConsoleFormatOptions
has slightly changed: prettyPrint
is now optional and colors
has been added.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.All types of contributions are encouraged and valued. See the Contributing guidelines, the community looks forward to your contributions!
This project is released under the under terms of the ISC License.
FAQs
A Nest module wrapper for winston
The npm package nest-winston receives a total of 85,385 weekly downloads. As such, nest-winston popularity was classified as popular.
We found that nest-winston demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Security News
The Linux Foundation is warning open source developers that compliance with global sanctions is mandatory, highlighting legal risks and restrictions on contributions.
Security News
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.