-
[Nest.js] 16 - Log with Winston and WebHookNest.js 2021. 9. 25. 18:36
- last time in #14, we used built-in Logger in nestjs/common.
However, we will use the external logger, which is Winston.- Nest's built-in logger is used for monitoring Nest system behavior, and can also be useful for basic formatted text logging in your feature modules while in development
Constent
1. Winston?
2. Module Installation
3. Winston Logging Level
4. Winston Transports
5. Implementation and test
1. Winston?
- Production applications often have specific logging requirements, including advanced filtering, formatting and centralized logging. Also, production applications often take advantage of dedicated logging modules like Winston As with any standard Node.js application, you can take full advantage of such modules in Nest.
- Winston is designed to be a simple and universal logging library with support for multiple transports.
A transport is essentially a storage device for our logs.
Therefore, Each winston logger can have multiple transports configured at different levels .- For example, one may want error logs to be stored in a persistent remote location (like a database),
but all logs, excepting error logs, output to the console or a local file.- In short,
we can use Winston to store logs for Production application in a customized way,
saving in multiple files, alerting with different levels, showing various formats , and so on.
2. Module Installation
- install modules : nest-winston, winston, winston-slack-webhook-transport
$ npm install --save nest-winston winston winston-slack-webhook-transport
3. Logging Level
- Each level is given a specific integer priority. The higher the priority the more important the message is considered to be, and the lower the corresponding integer priority. For example, as specified exactly in RFC5424 the syslog levels are prioritized from 0 to 7 (highest to lowest).
- syslog Levels
{ emerg: 0, alert: 1, crit: 2, error: 3, warning: 4, notice: 5, info: 6, debug: 7 }
- npm Levels
{ error: 0, warn: 1, info: 2, http: 3, verbose: 4, debug: 5, silly: 6 }
// npm levels will be used on my project
4. Wiinston Transports
- In winston a transport is essentially a storage device for our logs.
Each instance of a winston logger can have multiple transports configured at different levels.- here is a transport list to see more details, reference from https://github.com/winstonjs/winston/blob/master/docs/transports.md#winston-core
GitHub - winstonjs/winston: A logger for just about everything.
A logger for just about everything. Contribute to winstonjs/winston development by creating an account on GitHub.
github.com
// We use File, and Slack transports at this time.
- File transport oprions
- level: Level of messages that this transport should log (default: level set on parent logger).
- silent: Boolean flag indicating whether to suppress output (default false).
- eol: Line-ending character to use. (default: os.EOL).
- filename: The filename of the logfile to write output to.
- maxsize: Max size in bytes of the logfile, if the size is exceeded then a new file is created, a counter will become a suffix of the log file.
- maxFiles: Limit the number of files created when the size of the logfile is exceeded.
- tailable: If true, log files will be rolled based on maxsize and maxfiles, but in ascending order. The filename will always have the most recent log lines. The larger the appended number, the older the log file. This option requires maxFiles to be set, or it will be ignored.
- maxRetries: The number of stream creation retry attempts before entering a failed state. In a failed state the transport stays active but performs a NOOP on it's log function. (default 2)
- zippedArchive: If true, all log files but the current one will be zipped.
- options: options passed to fs.createWriteStream (default {flags: 'a'}).
- stream: DEPRECATED The WriteableStream to write output to.
- Slack webhook options
- webhookUrl - Slack incoming webhook URL. This can be from a basic integration or a bot. REQUIRED
- channel - Slack channel to post message to.
- username - Username to post message with.
- iconEmoji - Status icon to post message with. (interchangeable with iconUrl)
- iconUrl - Status icon to post message with. (interchangeable with iconEmoji)
- formatter - Custom function to format messages with. This function accepts the info object (see Winston documentation) and must return an object with at least one of the following three keys: text (string), attachments (array of attachment objects), blocks (array of layout block objects). These will be used to structure the format of the logged Slack message. By default, messages will use the format of [level]: [message] with no attachments or layout blocks.
- level - Level to log. Global settings will apply if this is blank.
- unfurlLinks - Enables or disables link unfurling. (Default: false)
- unfurlMedia - Enables or disables media unfurling. (Default: false)
- mrkdwn - Enables or disables mrkdwn formatting within attachments or layout blocks (Default: false)
5. Implementation & Test
- src/logger
// create a logger folder to manage loggers in folder
- src/logger/winston.logger.ts
import * as winston from 'winston'; const { combine, timestamp, printf } = winston.format; // 1 const logFormat = printf(({ level, message, timestamp }) => { // 2 return `${timestamp} ${level}: ${message}`; }); export const winstonLogger = winston.createLogger({ // 3 level: 'info', // 4 format: combine( // 5 timestamp({ format: 'YYYY-MM-DD HH:mm:ss', }), logFormat, ), transports: [ // 6 new winston.transports.File({ // 6 level: 'info', handleExceptions: true, maxsize: 5242880, maxFiles: 7, filename: './logs/combined.log', }), new winston.transports.File({ // 6 level: 'warn', handleExceptions: true, maxsize: 5242880, maxFiles: 7, filename: './logs/warning.log', }), ], }); export const hookLogger = winston.createLogger({ // 7 level: 'info', format: combine( timestamp({ format: 'YYYY-MM-DD HH:mm:ss', }), logFormat, ), transports: [ new SlackHooks({ // 8 webhookUrl: // 9 'https://hooks.slack.com/services/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', }), ], });
// 1. take 'combine, timestamp, printf' functions, which are used for my customization, from winston.format
// 2. define how our log shows up.
// 3. create a winston logger and export it, named as winstonLogger
// 4. set level "info" as maximum level of the logger, so it could apply on info, warn, error levels only.
// 5. use a combine function for timestamp formatting and timestamp property
to customize timestamp property formatted in 'YYYY-MM-DD HH:mm:ss'// 6. transports: [] - it has mutiple transport options. I seperated them by its level.
Therefore, there are info, warning, error logs in combined.log,
and warning, error logs in warning.log.// 7. created another winston logger and exported it, name as hookLogger
// 8. it is a transport that sends all log messages to the Slack chat service.
// 9. Slack webhook url looks like: 'https://hooks.slack.com/services/xxx/xxx/xxx'
- Test File transports loggers
.. import { hookLogger, winstonLogger } from './logger/winston.logger'; async function bootstrap() { const logger = new Logger(); const app = await NestFactory.create(AppModule); ... winstonLogger.log('warn', `Application running on port ${port}`); winstonLogger.error(`Application running on port ${port}`); winstonLogger.info(`Application running on port ${port}`); winstonLogger.silly(`Application running on port ${port}`); } bootstrap();
- ./logs/combined.log
- ./logs/warning.log
- Test Slack webhook logger, src/boards/boards.controller.ts
... import { hookLogger } from 'src/logger/winston.logger'; @Controller('boards') @UseGuards(AuthGuard()) export class BoardsController { private logger = new Logger('JamesBoardsController'); constructor(private boardsService: BoardsService) {} ... @Get() getAllBoards(@GetUser() user: User): Promise<Board[]> { hookLogger.info( `In ${BoardsController.name} User ${user.username} trying to get all boards`, ); return this.boardsService.getAllBoards(user); } ... }
- Slack channel
### Will update logging with winston-daily-rotate-file ###
reference by
https://github.com/winstonjs/winston-daily-rotate-fileGitHub - winstonjs/winston-daily-rotate-file: A transport for winston which logs to a rotating file each day.
A transport for winston which logs to a rotating file each day. - GitHub - winstonjs/winston-daily-rotate-file: A transport for winston which logs to a rotating file each day.
github.com
https://github.com/winstonjs/winston/blob/master/docs/transports.md#winston-transports
GitHub - winstonjs/winston: A logger for just about everything.
A logger for just about everything. Contribute to winstonjs/winston development by creating an account on GitHub.
github.com
'Nest.js' 카테고리의 다른 글
[Nest.js] Life Cycle - advanced approach (0) 2021.09.29 [Nest.js] simple project (0) 2021.09.27 [Nest.js] 15 - Configuration (0) 2021.09.22 [Nest.js] 14 - Log basic (0) 2021.09.17 [Nest.js] 13 - Relations - One To One, Many To One (0) 2021.09.15