/* jshint -W097 */ /* jshint strict: false */ /*jslint node: true */ 'use strict'; var winston = require('winston'); var DailyRotateFile = require('winston-daily-rotate-file'); var fs = require('fs'); var path = require('path'); var os = require('os'); var tools = require(__dirname + '/tools.js'); var SysLog; var hostname = tools.getHostName(); try { SysLog = require('winston-syslog').Syslog; } catch (ex) { //console.log('No syslog support'); } var logger = function (level, files, noStdout, prefix) { var userOptions = {}; var options = { transports: [] }; //var defaultMaxSize;// = 10 * 1024 * 1024; if (typeof files === 'string') { files = [files]; } files = files || []; var isNpm = (__dirname.replace(/\\/g, '/').toLowerCase().indexOf('node_modules/' + tools.appName.toLowerCase() + '.js-controller') !== -1); if (typeof level === 'object') { userOptions = Object.assign({}, level); level = userOptions.level; prefix = userOptions.prefix; noStdout = userOptions.noStdout; if (userOptions.prefix !== undefined) delete userOptions.prefix; if (userOptions.transport) { var fName = 0; for (var f in userOptions.transport) { if (!userOptions.transport.hasOwnProperty(f)) continue; if (userOptions.transport[f].type === 'file' && userOptions.transport[f].enabled !== false) { userOptions.transport[f].filename = userOptions.transport[f].filename || 'log/' + tools.appName; if (!userOptions.transport[f].fileext && userOptions.transport[f].filename.indexOf('.log') === -1) { userOptions.transport[f].fileext = '.log'; } if (!fName) userOptions.transport[f].systemLog = true; userOptions.transport[f].handleExceptions = false; userOptions.transport[f].name = !fName ? tools.appName : 'dailyRotateFile' + fName; fName++; userOptions.transport[f].filename = userOptions.transport[f].filename.replace(/\\/g, '/'); if (userOptions.transport[f].filename.match(/^\w:\/|^\//)) { userOptions.transport[f].filename = path.normalize(userOptions.transport[f].filename); } else { userOptions.transport[f].filename = path.normalize(__dirname + (isNpm ? '/../../../' : '/../') + userOptions.transport[f].filename); } userOptions.transport[f].label = prefix || ''; userOptions.transport[f].level = userOptions.transport[f].level || level; userOptions.transport[f].json = (userOptions.transport[f].json !== undefined) ? userOptions.transport[f].json : false; userOptions.transport[f].silent = (userOptions.transport[f].silent !== undefined) ? userOptions.transport[f].silent : false; userOptions.transport[f].colorize = (userOptions.transport[f].colorize !== undefined) ? userOptions.transport[f].colorize : ((userOptions.colorize === undefined) ? true : userOptions.colorize); userOptions.transport[f].localTime = (userOptions.transport[f].localTime !== undefined) ? userOptions.transport[f].localTime : ((userOptions.localTime === undefined) ? true : userOptions.localTime); // userOptions.transport[f].maxsize = (userOptions.transport[f].maxsize !== undefined) ? userOptions.transport[f].maxsize : defaultMaxSize; userOptions.transport[f].timestamp = timestamp; userOptions.transport[f].datePattern = '.yyyy-MM-dd' + (userOptions.transport[f].fileext || ''); /*userOptions.transport[f].logException = function (message, info, next, err) { console.error(message); };*/ var _log = new DailyRotateFile(userOptions.transport[f]); options.transports.push(_log); } else if (userOptions.transport[f].type === 'syslog' && userOptions.transport[f].enabled !== false) { if (!SysLog) { console.error('Syslog configured, but not installed!'); continue; } // host: The host running syslogd, defaults to localhost. // port: The port on the host that syslog is running on, defaults to syslogd's default port. // protocol: The network protocol to log over (e.g. tcp4, udp4, unix, unix-connect, etc). // path: The path to the syslog dgram socket (i.e. /dev/log or /var/run/syslog for OS X). // pid: PID of the process that log messages are coming from (Default process.pid). // facility: Syslog facility to use (Default: local0). // localhost: Host to indicate that log messages are coming from (Default: localhost). // sysLogType: The type of the syslog protocol to use (Default: BSD). // app_name: The name of the application (Default: process.title). // eol: The end of line character to be added to the end of the message (Default: Message without modifications). // replace the used by syslog attribute "type" with own "sysLogType" // If no name defined, use hostname as name userOptions.transport[f].localhost = userOptions.transport[f].localhost || hostname; if (userOptions.transport[f].sysLogType) { userOptions.transport[f].type = userOptions.transport[f].sysLogType; delete userOptions.transport[f].sysLogType; } else { delete userOptions.transport[f].type; } try { options.transports.push(new SysLog(userOptions.transport[f])); } catch (err) { console.log('Cannot activate syslog: ' + err); } } } } } else { for (var i = 0; i < files.length; i++) { var opt = { name: !i ? tools.appName : 'dailyRotateFile' + i, filename: path.normalize(isNpm ? __dirname + '/../../../log/' + files[i] : __dirname + '/../log/' + files[i]), datePattern: '.yyyy-MM-dd.log', json: false, // If true, messages will be logged as JSON (default true). level: level, silent: false, localTime: true, colorize: (userOptions.colorize === undefined) ? true : userOptions.colorize, timestamp: timestamp, label: prefix || '', handleExceptions: false //maxsize: defaultMaxSize }; options.transports.push(new DailyRotateFile(opt)); } } if (!noStdout) { options.transports.push(new winston.transports.Console({ level: level, silent: false, colorize: (userOptions.colorize === undefined) ? true : userOptions.colorize, timestamp: timestamp, label: prefix || '' })); } var log = new winston.Logger(options); log.getFileName = function () { if (this.transports && this.transports[tools.appName]) { if (this.transports[tools.appName].filename) { return this.transports[tools.appName].dirname + '/' + this.transports[tools.appName].filename; } else if (this.transports[tools.appName]._getFilename) { return this.transports[tools.appName].dirname + '/' + this.transports[tools.appName]._getFilename(); } else { return ''; } } else { return ''; } }; log.activateDateChecker = function (isEnabled, daysCount) { if (!isEnabled && this._fileChecker) { clearInterval(this._fileChecker); } else if (isEnabled && !this._fileChecker) { if (!daysCount) daysCount = 3; // Check every hour this._fileChecker = setInterval(function () { if (this.transports[tools.appName] && fs.existsSync(this.transports[tools.appName].dirname)) { var files = fs.readdirSync(this.transports[tools.appName].dirname); var for3days = new Date(); for3days.setDate(for3days.getDate() - daysCount); for (var i = 0; i < files.length; i++) { var match = files[i].match(/.+\.(\d+-\d+-\d+)/); if (match) { var date = new Date(match[1]); if (date < for3days) { // delete file try { this.transports[tools.appName].log('info', 'host.' + hostname + ' Delete log file ' + files[i]); fs.unlinkSync(this.transports[tools.appName].dirname + '/' + files[i]); } catch (e) { // there is a bug under windows, that file stays opened and cannot be deleted this.log(os.platform().match(/^win/) ? 'info' : 'error', 'host.' + hostname + ' Cannot delete file "' + path.normalize(this.transports[tools.appName].dirname + '/' + files[i]) + '": ' + e); } } } } } }.bind(this), 3600000); // every hour } }; winston.unhandleExceptions(); return log; }; function timestamp() { var ts = new Date(); var result = ts.getFullYear() + '-'; /** @type {number | string} */ var value = ts.getMonth() + 1; if (value < 10) value = '0' + value; result += value + '-'; value = ts.getDate(); if (value < 10) value = '0' + value; result += value + ' '; value = ts.getHours(); if (value < 10) value = '0' + value; result += value + ':'; value = ts.getMinutes(); if (value < 10) value = '0' + value; result += value + ':'; value = ts.getSeconds(); if (value < 10) value = '0' + value; result += value + '.'; value = ts.getMilliseconds(); if (value < 10) { value = '00' + value; } else if (value < 100) { value = '0' + value; } result += value + ' '; return result; } module.exports = logger;