obcon-scada / app /include /logger.js
chanmin0723's picture
Initial obcon SCADA deploy
e4bf523
Raw
History Blame Contribute Delete
6.38 kB
'use strict'
/**
* 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;