UNPKG

simple-fs-rotator

Version:
267 lines (266 loc) 11.6 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _FileStreamRotator_instances, _FileStreamRotator_write; Object.defineProperty(exports, "__esModule", { value: true }); const fs = require("fs"); const path = require("path"); const enums_1 = require("./enums"); const DefaultOptions_1 = require("./DefaultOptions"); const Rotator_1 = require("./Rotator"); const AuditManager_1 = require("./AuditManager"); const helper_1 = require("./helper"); const EventEmitter = require("events"); class FileStreamRotator extends EventEmitter { // private logWatcher?: FSWatcher constructor(options, debug = false) { var _a, _b; super(); _FileStreamRotator_instances.add(this); this.writeBuffer = []; this.writing = false; this.config = {}; this.config = this.parseOptions(options); helper_1.Logger.getInstance(options.verbose, debug); this.auditManager = new AuditManager_1.default((_a = this.config.auditSettings) !== null && _a !== void 0 ? _a : DefaultOptions_1.default.auditSettings({}), this); let lastEntry = this.auditManager.config.files.slice(-1).shift(); this.rotator = new Rotator_1.default(((_b = this.config.rotationSettings) !== null && _b !== void 0 ? _b : DefaultOptions_1.default.rotationSettings({})), lastEntry); this.currentFile = this.rotator.getNewFilename(); this.createNewLog(this.currentFile); this.emit('new', this.currentFile); } static getStream(options) { return new FileStreamRotator(options); } parseOptions(options) { var _a, _b, _c, _d; let config = {}; config.options = DefaultOptions_1.default.fileStreamRotatorOptions(options); config.fileOptions = DefaultOptions_1.default.fileOptions((_a = options.file_options) !== null && _a !== void 0 ? _a : {}); let auditSettings = DefaultOptions_1.default.auditSettings({}); if (options.audit_file) { auditSettings.auditFilename = options.audit_file; } if (options.audit_hash_type) { auditSettings.hashType = options.audit_hash_type; } if (options.extension) { auditSettings.extension = options.extension; } if (options.max_logs) { let params = DefaultOptions_1.default.extractParam(options.max_logs); auditSettings.keepSettings = { type: ((_b = params.letter) === null || _b === void 0 ? void 0 : _b.toLowerCase()) == "d" ? enums_1.KeepLogFiles.days : enums_1.KeepLogFiles.fileCount, amount: params.number }; } config.auditSettings = auditSettings; config.rotationSettings = DefaultOptions_1.default.rotationSettings({ filename: options.filename, extension: options.extension }); if (options.date_format && !options.frequency) { config.rotationSettings.frequency = enums_1.Frequency.date; } else { config.rotationSettings.frequency = enums_1.Frequency.none; } if (options.date_format) { config.rotationSettings.format = options.date_format; } config.rotationSettings.utc = (_c = options.utc) !== null && _c !== void 0 ? _c : false; switch (options.frequency) { case "daily": config.rotationSettings.frequency = enums_1.Frequency.daily; break; case "custom": case "date": config.rotationSettings.frequency = enums_1.Frequency.date; break; case "test": config.rotationSettings.frequency = enums_1.Frequency.minutes; config.rotationSettings.amount = 1; break; default: if (options.frequency) { let params = DefaultOptions_1.default.extractParam(options.frequency); if ((_d = params.letter) === null || _d === void 0 ? void 0 : _d.match(/^([mh])$/)) { config.rotationSettings.frequency = params.letter == "h" ? enums_1.Frequency.hours : enums_1.Frequency.minutes; config.rotationSettings.amount = params.number; } } } if (options.size) { let params = DefaultOptions_1.default.extractParam(options.size); switch (params.letter) { case 'k': config.rotationSettings.maxSize = params.number * 1024; break; case 'm': config.rotationSettings.maxSize = params.number * 1024 * 1024; break; case 'g': config.rotationSettings.maxSize = params.number * 1024 * 1024 * 1024; break; } } config.rotationSettings.keepSettings = auditSettings.keepSettings; this.rotator = new Rotator_1.default(config.rotationSettings); return config; } rotate(force = false) { var _a, _b; let oldFile = this.currentFile; this.rotator.rotate(force); this.currentFile = this.rotator.getNewFilename(); // oldfile same as new file. do nothing if (this.currentFile == oldFile) { return; } // close old file and watcher if exists. if (this.fs) { // if (this.logWatcher) { // this.logWatcher.close() // } if (((_a = this.config.options) === null || _a === void 0 ? void 0 : _a.end_stream) === true) { this.fs.end(); } else { this.fs.destroy(); } } // add old file to audit if (oldFile) { this.auditManager.addLog(oldFile); } this.createNewLog(this.currentFile); this.emit('new', this.currentFile); if (((_b = this.config.options) === null || _b === void 0 ? void 0 : _b.rotate) && oldFile) { this.rotatePromise = this.config.options.rotate(oldFile) .catch(() => { }) .then(() => { this.rotatePromise = undefined; }); } this.emit('rotate', oldFile, this.currentFile, force); } createNewLog(filename) { var _a; // create new directory if required (0, helper_1.makeDirectory)(filename); // add mew file tp audit this.auditManager.addLog(filename); // create new file let streamOptions = {}; if (this.config.fileOptions) { streamOptions = this.config.fileOptions; } this.fs = fs.createWriteStream(filename, streamOptions); // setup dependencies: proxy events, emit events this.bubbleEvents(this.fs, filename); // setup symlink if ((_a = this.config.options) === null || _a === void 0 ? void 0 : _a.create_symlink) { this.createCurrentSymLink(filename); } } write(str, encoding) { this.writeBuffer.push({ str, encoding }); if (this.writing) { return; } this.writing = true; __classPrivateFieldGet(this, _FileStreamRotator_instances, "m", _FileStreamRotator_write).call(this); } flush(cb) { __classPrivateFieldGet(this, _FileStreamRotator_instances, "m", _FileStreamRotator_write).call(this) .then(() => { if (cb) cb(); }); } end(str) { if (this.fs) { this.fs.end(str); this.fs = undefined; } } bubbleEvents(emitter, filename) { emitter.on('close', () => { this.emit('close'); }); emitter.on('finish', () => { this.emit('finish'); }); emitter.on('error', (err) => { this.emit('error', err); }); emitter.on('open', (fd) => { this.emit('open', filename); }); } createCurrentSymLink(logfile) { var _a, _b; if (!logfile) { return; } let symLinkName = (_b = (_a = this.config.options) === null || _a === void 0 ? void 0 : _a.symlink_name) !== null && _b !== void 0 ? _b : "current.log"; let logPath = path.dirname(logfile); let logfileName = path.basename(logfile); let current = logPath + path.sep + symLinkName; try { if (fs.existsSync(current)) { let stats = fs.lstatSync(current); if (stats.isSymbolicLink()) { fs.unlinkSync(current); fs.symlinkSync(logfileName, current); return; } helper_1.Logger.verbose("Could not create symlink file as file with the same name exists: ", current); } else { fs.symlinkSync(logfileName, current); } } catch (err) { helper_1.Logger.verbose("[Could not create symlink file: ", current, ' -> ', logfileName); helper_1.Logger.debug("error creating sym link", current, err); } } test() { return { config: this.config, rotator: this.rotator }; } } exports.default = FileStreamRotator; _FileStreamRotator_instances = new WeakSet(), _FileStreamRotator_write = function _FileStreamRotator_write() { return __awaiter(this, void 0, void 0, function* () { const buffers = this.writeBuffer.splice(0); for (const buffer of buffers) { if (this.rotatePromise != null) { try { yield this.rotatePromise; } catch (_a) { } } yield new Promise(resolve => { if (this.fs) { this.fs.write(buffer.str, buffer.encoding || "utf8", err => { if (err == null) { this.rotator.addBytes(Buffer.byteLength(buffer.str, buffer.encoding)); } resolve(); }); } }); if (this.rotatePromise == null && this.rotator.hasMaxSizeReached()) { this.rotate(); } } if (this.writeBuffer.length > 0) { yield __classPrivateFieldGet(this, _FileStreamRotator_instances, "m", _FileStreamRotator_write).call(this); } else { this.writing = false; } }); };