/** @module log */ import { ContextResolver, IContext } from 'pip-services4-components-node'; import { ConfigParams } from 'pip-services4-components-node'; import { ErrorDescription } from 'pip-services4-commons-node'; import { ErrorDescriptionFactory } from 'pip-services4-commons-node'; import { LogLevel } from './LogLevel'; import { Logger } from './Logger'; import { LogMessage } from './LogMessage'; import { LogLevelConverter } from './LogLevelConverter'; /** * Abstract logger that caches captured log messages in memory and periodically dumps them. * Child classes implement saving cached messages to their specified destinations. * * ### Configuration parameters ### * * - level: maximum log level to capture * - source: source (context) name * - options: * - interval: interval in milliseconds to save log messages (default: 10 seconds) * - max_cache_size: maximum number of messages stored in this cache (default: 100) * * ### References ### * * - \*:context-info:\*:\*:1.0 (optional) [[ContextInfo]] to detect the context id and specify counters source * * @see [[ILogger]] * @see [[Logger]] * @see [[LogMessage]] */ export abstract class CachedLogger extends Logger { protected _cache: LogMessage[] = []; protected _updated = false; protected _lastDumpTime: number = new Date().getTime(); protected _maxCacheSize = 100; protected _interval = 10000; /** * Creates a new instance of the logger. */ public constructor() { super(); } /** * Writes a log message to the logger destination. * * @param level a log level. * @param context (optional) a context to trace execution through call chain. * @param error an error object associated with this message. * @param message a human-readable message to log. */ protected write(level: LogLevel, context: IContext, error: Error, message: string): void { const errorDesc: ErrorDescription = error != null ? ErrorDescriptionFactory.create(error) : null; const logMessage: LogMessage = { time: new Date(), level: LogLevelConverter.toString(level), source: this._source, trace_id: context != null ? ContextResolver.getTraceId(context) : null, error: errorDesc, message: message }; this._cache.push(logMessage); this.update(); } /** * Saves log messages from the cache. * * @param messages a list with log messages * @param callback callback function that receives error or null for success. */ protected abstract save(messages: LogMessage[]): Promise; /** * Configures component by passing configuration parameters. * * @param config configuration parameters to be set. */ public configure(config: ConfigParams): void { super.configure(config); this._interval = config.getAsLongWithDefault("options.interval", this._interval); this._maxCacheSize = config.getAsIntegerWithDefault("options.max_cache_size", this._maxCacheSize); } /** * Clears (removes) all cached log messages. */ public clear(): void { this._cache = []; this._updated = false; } /** * Dumps (writes) the currently cached log messages. * * @see [[write]] */ public dump(): void { if (this._updated) { if (!this._updated) return; const messages = this._cache; this._cache = []; this.save(messages) .catch((err) => { // Adds messages back to the cache messages.push(...this._cache); this._cache = messages; // Truncate cache const deleteCount = this._cache.length - this._maxCacheSize; if (deleteCount > 0) { this._cache.splice(0, deleteCount); } console.error(err); }); this._updated = false; this._lastDumpTime = new Date().getTime(); } } /** * Makes message cache as updated * and dumps it when timeout expires. * * @see [[dump]] */ protected update(): void { this._updated = true; const now = new Date().getTime(); if (now > this._lastDumpTime + this._interval) { this.dump(); } } }