Spaces:
Running
Running
| /** | |
| * Copyright (c) 2017~2024, OBCon Inc. | |
| * All rights reserved. | |
| */ | |
| /** | |
| * @file | |
| * @copyright 2017~2024, OBCon Inc. | |
| * @author gye hyun james kim [pnuskgh@gmail.com] | |
| */ | |
| //--- https://github.com/winstonjs/winston | |
| //--- Logging Level : error: 0, warn: 1, info: 2, verbose: 3, debug: 4, silly: 5 | |
| // logger.error('~'); | |
| // logger.warn('~'); | |
| // logger.info('~'); | |
| // logger.debug('~'); | |
| //--- 로그 폴더 생성 | |
| const fs = require('fs'); | |
| const path = require('path'); | |
| //--- https://www.npmjs.com/package/winston | |
| const winston = require('winston'); //--- 로거 모듈 | |
| const winstonDaily = require('winston-daily-rotate-file'); //--- 날자별로 로거 파일 생성 | |
| //--- To-Do : 어떤 프로그램의 몇번째 라인에서 메시지를 표시하였는지를 로그에 표시 한다. | |
| //--- To-Do : log > Elastic Search > Kibana | |
| //--- 로그 포맷 | |
| //--- {level}: {timestamp} : {message} | |
| //--- {level}: {timestamp} : {filename} : {message} //--- 일반 로그 포맷 | |
| //--- {level}: {timestamp} : {filename} : {deviceIdx} : {message} //--- 특정 Device의 로그 포맷 | |
| class Logger { | |
| constructor() { | |
| this.logFolder = utils.getPath(config.logger.folder); | |
| this._initFolder(); | |
| this.useJson = config.logger.useJson; | |
| this.useConsole = config.logger.useConsole | |
| this.level = config.logger.level; | |
| //--- cluster와 pm2 환경에서 실행되는 instance의 수만큼 1씩 증가하며 로그 파일이 생성 된다. (0: Master in cluster, 1, 2, ...) | |
| this.filename = config.logger.filename.replace('%worker%', appl.worker.id); | |
| if (appl.type.endsWith('_batch')) { | |
| this.filename = this.filename.replace('\.log', '_batch.log'); | |
| } | |
| this.maxSize = config.logger.maxSize; | |
| this.maxFiles = config.logger.maxFiles; | |
| } | |
| _initFolder() { | |
| //--- 로그 폴더가 없는 경우 로그 폴더를 생성 한다. | |
| if (!fs.existsSync(this.logFolder)) { | |
| fs.mkdirSync(this.logFolder); | |
| } | |
| } | |
| getFormat() { | |
| const format = `YYYY-MM-DD HH:mm:ss.SSS : ${appl.worker.id}`; | |
| const formats = [ winston.format.timestamp({ format: format }) ]; | |
| if (this.useJson) { | |
| formats.push(winston.format.json()); | |
| } else { | |
| if (config.logger.showFileinfo == false) { | |
| formats.push(winston.format(function(info, opts) { | |
| info.message = info.timestamp + ' : ' + info.message; | |
| delete info.timestamp; | |
| return info; | |
| })({})); | |
| } else { | |
| formats.push(winston.format(function(info, opts) { | |
| let fileName = null; | |
| let lineNumber = null; | |
| let columnNumber = null; | |
| let tmpStackArray = new Error().stack.split('\n'); | |
| if (10 < tmpStackArray.length) { | |
| let tmpStr = tmpStackArray[10]; | |
| if ((-1 < tmpStr.indexOf('(')) && (-1 < tmpStr.indexOf(')'))) { | |
| //--- " at Object.<anonymous> (/work/appl/obcon/modules/modules.js:62:8)" | |
| tmpStr = tmpStr.substring(tmpStr.indexOf('(') + 1, tmpStr.indexOf(')')); | |
| } else { | |
| //--- " at /work/appl/obcon/modules/http_app.js:244:20" | |
| tmpStr = tmpStr.replace(/ at /, ''); | |
| } | |
| tmpStr = tmpStr.replace('file:///', ''); | |
| const tmpArray = tmpStr.split(':'); | |
| if (tmpArray.length == 3) { | |
| fileName = tmpArray[0]; | |
| lineNumber = tmpArray[1]; | |
| columnNumber = tmpArray[2]; | |
| } else if (tmpArray.length == 4) { | |
| fileName = tmpArray[0] + ':' + tmpArray[1]; | |
| lineNumber = tmpArray[2]; | |
| columnNumber = tmpArray[3]; | |
| } | |
| fileName = fileName.replace(/\\/g, '/').replace(appl.root, ''); | |
| } | |
| if (fileName == null) { | |
| info.message = info.timestamp + ' : : ' + info.message; | |
| } else { | |
| info.message = info.timestamp + ` : ${fileName} (${lineNumber}, ${columnNumber}) : ` + info.message; | |
| } | |
| delete info.timestamp; | |
| return info; | |
| })({})); | |
| } | |
| formats.push(winston.format.simple()); | |
| } | |
| return winston.format.combine(...formats); | |
| } | |
| getTransports() { | |
| const transports = [ | |
| new winstonDaily({ | |
| level: this.level, | |
| filename: path.join(this.logFolder, this.filename), | |
| datePattern: "YYYYMMDD", | |
| zippedArchive: false, | |
| maxSize: this.maxSize, | |
| maxFiles: this.maxFiles, | |
| handleExceptions: true | |
| }) | |
| ]; | |
| if (this.useConsole) { | |
| transports.push( | |
| new winston.transports.Console({ | |
| level: this.level, | |
| // colorize: true, | |
| handleExceptions: true | |
| }) | |
| ); | |
| } | |
| return transports; | |
| } | |
| createLogger() { | |
| const log = winston.createLogger({ | |
| format: this.getFormat(), | |
| transports: this.getTransports() | |
| }); | |
| log.setLoggerLevel = function(level) { | |
| log._readableState.pipes.forEach(pipe => { pipe.level = level; }); | |
| }; | |
| log.setLevel = async function(level, workerId = -1) { | |
| try { | |
| log.setLoggerLevel(level); | |
| // await ipc.requestOnly('services', 'setLoggerLevel', workerId, {}, { level: level }); | |
| } catch(ex) { | |
| console.error(ex); | |
| } | |
| }; | |
| return log; | |
| } | |
| } | |
| module.exports = Logger; | |