Node.js 로그파일 기록하기 - Winston
어플리케이션을 실행할 때 로그를 기록하는 것은 실사용에서 꼭 필요한 작업이다. Node에서 일반적으로 사용하는 로그 모듈인 Winston을 이용하여 Console과 File에 로그를 만드는 방법에 대해 인터넷을 찾아보고 내가 원하는 방식으로 로그파일을 만들어 본다.내가 원하는 방식:
- 로그파일은 \logs 디렉토리 밑에 날짜별로 생성
- 로그는 express의 미들웨어를 통해 client call을 로깅
- 호출파일에 대한 기록 // 향후 어떤 파일을 호출했는지 찾아보기 위해 적용
단순해 보이지만 이를 모두 구현한 예제를 찾기 힘들었고 여러가지 예제를 조합하여 다음과 같이 예제 프로그램을 구현해 보았다.
디렉토리는 다음과 같이 구성된다.
-- test.js (테스트 파일)
+ configs\winston.js (Winston 설정파일)
+ logs\yyyy-mm-dd-cmpapi.log (로그 파일)
configs\winston.js 파일은 다음과 같다.
- // Log file lotation - 날짜에 따라 새로운 로그를 생성
- const { createLogger, format, transports, handleExceptions } = require('winston');
- const path = require('path');
- // 시스템의 환경 변수를 확인해서 NODE_ENV값을 확인
- // 사용은 PM2 의 ecosystem.yaml의 env항목 혹은 docker의 environment 항목에 설정
- // 이런 설정이 없으면 'development' 로 지정
- const env = process.env.NODE_ENV || 'development';
- // logs 디렉토리를 생성하기 위해서 사용
- const fs = require('fs');
- // 현재 위치에 log 디렉토리를 지정 : const logDir = __dirname + '/logs';
- const logDir = 'logs';
- // Create the log directory if it does not exist
- if (!fs.existsSync(logDir)) {
- fs.mkdirSync(logDir);
- };
- // File 모드 옵션 설정 - 날짜별로 로그파일의 이름을 변경
- require('winston-daily-rotate-file');
- const dailyRotateFileTransport = new transports.DailyRotateFile({
- // level: env === 'development' ? 'verbose' : 'info',
- handleExceptions: true, // Exception 발생 시 로그에 기록
- filename: `${logDir}/%DATE%-cmpapi.log`, // 로그파일명
- datePattern: 'YYYY-MM-DD', // 로그에 사용되는 날짜 포멧
- json: false,
- colorize: false,
- zippedArchive: true, // 오래된 로그파일 압축
- maxSize: 5242880, // 5MB
- maxFiles: 5, // 5MB - 5개 파일까지 생성 후 이후부터는 오래된 파일 삭제
- format: format.combine(
- format.printf(
- info =>
- `${info.timestamp} ${info.level} [${info.label}]: ${info.message}`
- )
- ) // 로그의 포멧 정의
- });
- // Console 모드 옵션 설정 - 로그의 패턴별로 색상을 다르게 지정함
- const consoleTransport = new transports.Console({
- level: env === 'development' ? 'verbose' : 'info',
- handleExceptions: true, // Exception 발생 시 로그에 기록
- json: false,
- colorize: true,
- format: format.combine(
- format.printf(
- info =>
- `${info.timestamp} ${info.level} [${info.label}]: ${info.message}`
- )
- ) // 로그의 포멧 정의
- });
- // logger를 호출할 때 callback으로 filename을 추가하기 위해 구조를 변경
- const logger = caller => {
- return createLogger({
- level: env === 'development' ? 'verbose' : 'info',
- format: format.combine(
- format.label({ label: path.basename(caller) }), //로그에 호출된 파일이름 기록
- // format.colorize(),
- format.timestamp({
- format: 'YYYY-MM-DD HH:mm:ss' // 로그의 Timestamp 포멧을 지정
- }),
- ),
- transports: [
- consoleTransport, // Console에 표시하는 형태
- dailyRotateFileTransport // File에 표시하는 형태
- ],
- exitOnError: true // handleExceptions 실행
- });
- };
- //handleExceptions(new transports.Console({ colorize: true, json: true }));
- module.exports = logger;
test.js파일은 다음과 같다.
- // 테스트를 위하여 express 모듈을 사용
- const express = require('express')
- const app = express()
- const port = 3000
- let queryString = '';
- // Winston Setup - Winston은 로그를 기록할 때 일반적으로 사용하는 모듈
- // configs 디렉토리의 wiston.js에 winston설정을 지정하여 import하여 사용
- let logger = require('./configs/winston')(__filename);
- //express에서 logger.steam 호출 시 표시하는 형태
- logger.stream = {
- write: (message, encoding) => {
- logger.info(message);
- }
- };
- // Morgan Setup - Morgan은 Rest API의 로그(req,res)를 보기 좋게 구성
- let morgan = require('morgan');
- // Morgan Setup - dev는 날짜 표시를 제외한 Standard Apache common log output
- app.use(morgan('dev', { "stream": logger.stream }));
- // Level 별로 다른 로그 지정
- logger.debug('Debugging info');
- logger.verbose('Verbose info');
- logger.info('Hello world');
- logger.warn('Warning message');
- logger.error('Error info');
- // 아래는 테스트를 위한 express route call 수행
- app.get('/', (req, res) => res.send('Hello World!'))
- app.get('/pathCall', (req, res) => {
- console.log(req.query.queryStr);
- switch (req.query.queryStr) {
- case 'Location':
- queryString = ' - Location Call';
- break;
- case 'Country' :
- queryString = ' - Country Call';
- break;
- case 'SubDiv' :
- queryString = ' - Subdivision Call';
- break;
- default:
- break;
- };
- res.send(req.path + queryString);
- });
- app.listen(port, () => console.log(`Example app listening on port ${port}!`))
winston 공식 메뉴얼을 이용해서 가능한 deprecated 된 기능이 없도록 구성하였다.
[참고 사이트]
콘솔, 파일 혹은 데이터베이스로 로그를 남기는 방법에 대해 설명한다.
리모트 프로세스의 로그를 통합하는데 필요한 기능을 설명한다.
https://mcpaint.tistory.com/198
주로 참고한 사이트로 날짜표시, 파일이름 표시방법을 설명한다.
https://www.digitalocean.com/community/tutorials/how-to-use-winston-to-log-node-js-applications
깔끔한 로그 만들기, 화면과 파일에 2중으로 로그남기기, 날짜별로 다른 이름 지정을 한다.
https://thisdavej.com/using-winston-a-versatile-logging-library-for-node-js/
Rest API를 위한 Log 관리를 설명한다.
https://medium.com/aha-official/%EC%95%84%ED%95%98-rest-api-%EC%84%9C%EB%B2%84-%EA%B0%9C%EB%B0%9C-13-b90f6007a8f9
morgan의 Stream을 winston의 log파일에 사용한다.
https://stackoverflow.com/questions/27906551/node-js-logging-use-morgan-and-winston
process.env 사용에 대해 설명한다.
https://codeburst.io/process-env-what-it-is-and-why-when-how-to-use-it-effectively-505d0b2831e7
댓글 없음:
댓글 쓰기