@absolunet/ioc2.1.0

View on GitHub

log/services/Logger/drivers/DatabaseDriver.js

//--------------------------------------------------------
//-- Node IoC - Log - Services - Logger - Drivers - File Driver
//--------------------------------------------------------

import Driver from './Driver';


/**
 * Driver that logs into a database table.
 *
 * @memberof log.services.Logger.drivers
 * @augments log.services.Logger.drivers.Driver
 * @hideconstructor
 */
class DatabaseDriver extends Driver {

	/**
	 * Class dependencies: <code>['app', 'db', 'log.level', 'terminal']</code>.
	 *
	 * @type {Array<string>}
	 */
	static get dependencies() {
		return (super.dependencies || []).concat(['app', 'db', 'terminal']);
	}

	/**
	 * @inheritdoc
	 * @private
	 */
	init() {
		this.setConfig({
			connection: 'default',
			table: 'logs'
		});
	}

	/**
	 * @inheritdoc
	 */
	async log(level, message, context) {
		await this.storeLog(level, message, context);
		await this.cleanPastLogs();
	}

	/**
	 * Store log in database.
	 *
	 * @param {number} level - The log level.
	 * @param {string} message - The message.
	 * @param {*} [context] - The context.
	 * @returns {Promise} The async process promise.
	 */
	async storeLog(level, message, context) {
		const { connection, config: { table } } = this;

		await connection(table).insert({
			level:      this.getFormattedLevel(level),
			version:    this.getFormattedVersion(),
			message:    this.getFormattedMessage(message),
			command:    this.getFormattedCommand(),
			context:    this.getFormattedContext(context),
			created_at: connection.fn.now(), // eslint-disable-line camelcase
			updated_at: connection.fn.now()  // eslint-disable-line camelcase
		});
	}

	/**
	 * Clear past logs in the database, starting by the least recent ones.
	 *
	 * @returns {Promise} The async process promise.
	 */
	async cleanPastLogs() {
		const { connection, config: { table, limit } } = this;
		const [{ count }] = await connection.select().from(table).count('id as count');

		if (count > limit) {
			const results = await connection.select('id').from(table).orderBy('id').limit(count - limit);
			const [{ id }] = results.reverse();
			await connection(table).delete().where('id', '<', id);
		}
	}

	/**
	 * Get formatted level value.
	 *
	 * @param {number|string} level - The level value.
	 * @returns {number} The formatted level value.
	 */
	getFormattedLevel(level) {
		return typeof level === 'number' ? level : this.LEVEL[level.toUpperCase()];
	}

	/**
	 * Get formatted version value.
	 *
	 * @returns {string} The application version.
	 */
	getFormattedVersion() {
		return this.app.version;
	}

	/**
	 * Get formatted message value.
	 *
	 * @param {string} message - The original message.
	 * @returns {string} The formatted message.
	 */
	getFormattedMessage(message) {
		return message.toString();
	}

	/**
	 * Get formatted current command.
	 *
	 * @returns {string} The command.
	 */
	getFormattedCommand() {
		return this.terminal.command || '';
	}

	/**
	 * Get formatted context by converting it into JSON.
	 *
	 * @param {*} context - The context.
	 * @returns {string} The formatted context.
	 */
	getFormattedContext(context) {
		return JSON.stringify(typeof context === 'undefined' ? null : context);
	}

	/**
	 * The connection to use based on driver configuration.
	 *
	 * @type {Knex}
	 */
	get connection() {
		return this.db.getConnection(this.config.connection);
	}

}


export default DatabaseDriver;