lin-mizar
Version:
The core library of Lin CMS
198 lines (197 loc) • 6.21 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", { value: true });
exports.FileTransport = void 0;
const tslib_1 = require("tslib");
const fs_1 = tslib_1.__importDefault(require("fs"));
const path_1 = tslib_1.__importDefault(require("path"));
const assert_1 = tslib_1.__importDefault(require("assert"));
const mkdirp_1 = tslib_1.__importDefault(require("mkdirp"));
const utility_1 = tslib_1.__importDefault(require("utility"));
const dayjs_1 = tslib_1.__importDefault(require("dayjs"));
const depd = require('depd')('egg-logger');
const utils = require('egg-logger/lib/utils');
const egg_logger_1 = require("egg-logger");
const format_1 = require("./format");
const config_1 = require("../config");
const baseDir = config_1.config.getItem('baseDir', process.cwd());
/**
* output log into file {@link Transport}。
*/
class FileTransport extends egg_logger_1.Transport {
/**
* @constructor
* @param {Object} options
* - {String} file - file path
* - {String} [level = INFO] - log level
*/
constructor(options) {
super(options);
assert_1.default(this.options.dir, 'should pass options.dir');
assert_1.default(this.options.sizeLimit, 'should pass options.sizeLimit');
this._stream = null;
this.reload();
}
get defaults() {
// @ts-ignore
return utils.assign(super.defaults, {
file: null,
level: 'INFO'
});
}
/**
* reload file stream
*/
reload() {
this._closeStream();
this._stream = this._createStream();
}
/**
* output log, see {@link Transport#log}
* @param {String} level - log level
* @param {Array} args - all arguments
* @param {Object} meta - meta information
*/
log(level, args, meta) {
// 根据日期
// 每一天
const filename = this.checkIsPresent();
// 为false,则文件名需要更新
// 存在,则判断是否溢出
if (filename) {
const overflow = this.checkSizeOverflow(filename);
// 如果溢出,reload
if (overflow) {
// filename重命名
this.renameLogFile(filename);
this.reload();
}
}
else {
this.reload();
}
if (!this.writable) {
const err = new Error(`${this.options.file} log stream had been closed`);
console.error(err.stack);
return;
}
meta = meta || {};
meta.formatter = format_1.consoleFormatter;
const buf = super.log(level, args, meta);
// @ts-ignore
if (buf.length) {
this._write(buf);
}
}
renameLogFile(filename) {
const today = dayjs_1.default();
const dir = path_1.default.dirname(filename);
const mill = today.format('HH:mm:ss');
const refilename = path_1.default.join(dir, `${today.format('YYYY-MM-DD')}-${mill}.log`);
fs_1.default.renameSync(filename, refilename);
}
/**
* 检查当前的日志文件是否为当天
*/
checkIsPresent() {
// 检查前面的日志
// 2019-06-01-21:29:01.log
// 而且检查当前文件夹
const filename = this.getPresentFilename();
const exist = fs_1.default.existsSync(filename);
if (exist) {
return filename;
}
else {
return false;
}
}
getPresentFilename() {
const dir = path_1.default.isAbsolute(this.options.dir)
? this.options.dir
: path_1.default.join(baseDir, this.options.dir);
const today = dayjs_1.default();
const ddir = path_1.default.join(dir, today.format('YYYY-MM'));
const dfilename = today.format('YYYY-MM-DD');
const filename = path_1.default.join(ddir, `${dfilename}.log`);
return filename;
}
checkSizeOverflow(filename) {
// sizeLimit 一定得传进来
const limit = this.options.sizeLimit;
const status = fs_1.default.statSync(filename);
// 是否溢出
return status.size > limit;
}
/**
* close stream
*/
close() {
this._closeStream();
}
/**
* @deprecated
*/
end() {
depd('transport.end() is deprecated, use transport.close()');
this.close();
}
/**
* write stream directly
* @param {Buffer|String} buf - log content
* @private
*/
_write(buf) {
this._stream.write(buf);
}
/**
* transport is writable
* @return {Boolean} writable
*/
get writable() {
return (this._stream &&
// @ts-ignore
!this._stream.closed &&
this._stream.writable &&
// @ts-ignore
!this._stream.destroyed);
}
/**
* create stream
* @return {Stream} return writeStream
* @private
*/
_createStream() {
// 获得文件名
const filename = this.getPresentFilename();
// 获得文件夹名
const dirp = path_1.default.dirname(filename);
// 创建文件夹
if (!fs_1.default.existsSync(dirp)) {
mkdirp_1.default.sync(dirp);
}
const stream = fs_1.default.createWriteStream(filename, { flags: 'a' });
const onError = err => {
console.error('%s ERROR %s [logger] [%s] %s', utility_1.default.logDate(','), process.pid, filename, err.stack);
this.reload();
console.warn('%s WARN %s [logger] [%s] reloaded', utility_1.default.logDate(','), process.pid, filename);
};
// only listen error once because stream will reload after error
stream.once('error', onError);
// @ts-ignore
stream._onError = onError;
return stream;
}
/**
* close stream
* @private
*/
_closeStream() {
if (this._stream) {
this._stream.end();
// @ts-ignore
this._stream.removeListener('error', this._stream._onError);
this._stream = null;
}
}
}
exports.FileTransport = FileTransport;