baqend
Version:
Baqend JavaScript SDK
349 lines (307 loc) • 12.2 kB
text/typescript
import * as msg from '../message';
import type { EntityManager } from '../EntityManager';
import { JsonMap } from '../util';
export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error';
/**
* A Logger to store log notes when running the app.
*/
export class Logger {
static readonly LEVELS: LogLevel[] = ['trace', 'debug', 'info', 'warn', 'error'];
static readonly FORMAT_REGEXP = /%[sdj%]/g;
public entityManager: EntityManager = null as any;
public levelIndex: number = 2;
/**
* Creates a Logger instance for the given EntityManager
* @param entityManager - Theo owning entityManager
* @return The created logger instance
*/
static create(entityManager: EntityManager): Logger {
const proto = this.prototype;
const logger = (() => {
function LoggerFunction(...args: any[]) {
proto.log.apply(LoggerFunction, args as any);
}
Object.getOwnPropertyNames(proto).forEach((key) => {
Object.defineProperty(LoggerFunction, key, Object.getOwnPropertyDescriptor(proto, key)!);
});
return LoggerFunction as any as Logger;
})();
logger.init(entityManager);
return logger;
}
/**
* The log level which will be logged
*
* The log level can be one of 'trace', 'debug', 'info', 'warn', 'error'
* @type string
*/
get level(): LogLevel {
return Logger.LEVELS[this.levelIndex];
}
/**
* Sets the log level which will be logged
* @param value
*/
set level(value: LogLevel) {
const index = Logger.LEVELS.indexOf(value);
if (index === -1) {
throw new Error(`Unknown logging level ${value}`);
}
this.levelIndex = index;
}
/**
* Logs a message in the default level 'info'
* @param message The message to log, the message string can be interpolated like the node util.format method
* @param args The arguments used to interpolated the message string. The last param can be object which will
* be included in the log entry
*
* @see https://nodejs.org/api/util.html#util_util_format_format
*
* @return A promise which resolves when the log messages was logged, or null if the log level has
* skipped the message
*/
log(message: string, ...args: any[]): Promise<any>;
/**
* Logs a message in the default level 'info'
* @param message The message to log, the message string can be interpolated like the node util.format method
* @param [data=null] An optional object which will be included in the log entry
*
* @see https://nodejs.org/api/util.html#util_util_format_format
*
* @return A promise which resolves when the log messages was logged, or null if the log level has
* skipped the message
*/
log(message: string, data: any): Promise<any>;
/**
* Logs a message with the given log level
* @param level The level used to log the message
* @param message The message to log, the message string can be interpolated like the node util.format method
* @param args The arguments used to interpolated the message string. The last param can be object which will
* be included in the log entry
*
* @see https://nodejs.org/api/util.html#util_util_format_format
*
* @return A promise which resolves when the log messages was logged, or null if the log level has
* skipped the message
*/
log(level: string, message: string, ...args: any[]): Promise<any>;
/**
* Logs a message with the given log level
* @param level The level used to log the message
* @param message The message to log, the message string can be interpolated like the node util.format method
* @param [data=null] An optional object which will be included in the log entry
*
* @see https://nodejs.org/api/util.html#util_util_format_format
*
* @return A promise which resolves when the log messages was logged, or null if the log level has
* skipped the message
*/
log(level: string, message: string, data: any): Promise<any>;
log(...args: any[]): Promise<any> {
const level: LogLevel = Logger.LEVELS.indexOf(args[0]) === -1 ? 'info' : args.shift();
if (this.levelIndex > Logger.LEVELS.indexOf(level)) {
return Promise.resolve(null);
}
let message: string = typeof args[0] === 'string' ? this.format(args.shift(), args) : '[no message]';
let data: { data: any } | { name: string, message: string, stack: string, data: {}, status: number } | null = null;
if (args.length) {
const arg = args.pop();
data = arg;
if (typeof arg !== 'object' || Array.isArray(arg)) {
data = { data: arg };
}
if (arg instanceof Error) {
// errors aren't loggable by default, since they do not have any visible property
const {
// @ts-ignore
stack, data: data1, message: message1, name, status,
} = arg;
data = {
name,
message: message1,
stack,
status,
data: data1,
};
}
}
if (args.length) {
message += `, ${args.join(', ')}`;
}
return this.logJSON({
date: new Date().toISOString(),
message,
level,
data,
...(this.entityManager.me && { user: this.entityManager.me.id }),
});
}
format(message: string, args: any) {
if (args.length === 0) {
return message;
}
const str = String(message).replace(Logger.FORMAT_REGEXP, (x: string) => {
if (x === '%%') {
return '%';
}
if (!args.length) {
return x;
}
switch (x) {
case '%s':
return String(args.shift());
case '%d':
return String(Number(args.shift()));
case '%j':
try {
return JSON.stringify(args.shift());
} catch (_) {
return '[Circular]';
}
default:
return x;
}
});
return str;
}
init(entityManager: EntityManager) {
this.entityManager = entityManager;
this.levelIndex = 2;
Logger.LEVELS.forEach((level) => {
this[level] = this.log.bind(this, level);
});
}
logJSON(json: JsonMap): Promise<any> {
if (!this.entityManager.isReady) {
return this.entityManager.ready(this.logJSON.bind(this, json));
}
return this.entityManager.send(new msg.CreateObject('logs.AppLog', json));
}
}
export interface Logger {
/**
* Log message at trace level
* @param message The message to log, the message string can be interpolated like the node util.format method
* @param args The arguments used to interpolated the message string. The last param can be object which will
* be included in the log entry
* @return A promise which resolves when the log messages was logged, or null if the log level has
* skipped the message
* @function trace
* @memberOf util.Logger.prototype
*
* @see https://nodejs.org/api/util.html#util_util_format_format
*/
trace(message: string, ...args: any[]): Promise<any>;
/**
* Log message at trace level
* @param message The message to log, the message string can be interpolated like the node util.format method
* @param [data=null] An optional object which will be included in the log entry
* @return A promise which resolves when the log messages was logged, or null if the log level has
* skipped the message
* @function trace
* @memberOf util.Logger.prototype
*
* @see https://nodejs.org/api/util.html#util_util_format_format
*/
trace(message: string, data: any): Promise<any>;
/**
* Log message at debug level
* @param message The message to log, the message string can be interpolated like the node util.format method
* @param args The arguments used to interpolated the message string. The last param can be object which will
* be included in the log entry
* @return A promise which resolves when the log messages was logged, or null if the log level has
* skipped the message
* @function debug
* @memberOf util.Logger.prototype
*
* @see https://nodejs.org/api/util.html#util_util_format_format
*/
debug(message: string, ...args: any[]): Promise<any>;
/**
* Log message at debug level
* @param message The message to log, the message string can be interpolated like the node util.format method
* @param [data=null] An optional object which will be included in the log entry
* @return A promise which resolves when the log messages was logged, or null if the log level has
* skipped the message
* @function debug
* @memberOf util.Logger.prototype
*
* @see https://nodejs.org/api/util.html#util_util_format_format
*/
debug(message: string, data: any): Promise<any>;
/**
* Log message at info level
* @param message The message to log, the message string can be interpolated like the node util.format method
* @param args The arguments used to interpolated the message string. The last param can be object which will
* be included in the log entry
* @return A promise which resolves when the log messages was logged, or null if the log level has
* skipped the message
* @function info
* @memberOf util.Logger.prototype
*
* @see https://nodejs.org/api/util.html#util_util_format_format
*/
info(message: string, ...args: any[]): Promise<any>;
/**
* Log message at info level
* @param message The message to log, the message string can be interpolated like the node util.format method
* @param [data=null] An optional object which will be included in the log entry
* @return A promise which resolves when the log messages was logged, or null if the log level has
* skipped the message
* @function info
* @memberOf util.Logger.prototype
*
* @see https://nodejs.org/api/util.html#util_util_format_format
*/
info(message: string, data: any): Promise<any>;
/**
* Log message at warn level
* @param message The message to log, the message string can be interpolated like the node util.format method
* @param args The arguments used to interpolated the message string. The last param can be object which will
* be included in the log entry
* @return A promise which resolves when the log messages was logged, or null if the log level has
* skipped the message
* @function warn
* @memberOf util.Logger.prototype
*
* @see https://nodejs.org/api/util.html#util_util_format_format
*/
warn(message: string, ...args: any[]): Promise<any>;
/**
* Log message at warn level
* @param message The message to log, the message string can be interpolated like the node util.format method
* @param [data=null] An optional object which will be included in the log entry
* @return A promise which resolves when the log messages was logged, or null if the log level has
* skipped the message
* @function warn
* @memberOf util.Logger.prototype
*
* @see https://nodejs.org/api/util.html#util_util_format_format
*/
warn(message: string, data: any): Promise<any>;
/**
* Log message at error level
* @param message The message to log, the message string can be interpolated like the node util.format method
* @param args The arguments used to interpolated the message string. The last param can be object which will
* be included in the log entry
* @return A promise which resolves when the log messages was logged, or null if the log level has
* skipped the message
* @function error
* @memberOf util.Logger.prototype
*
* @see https://nodejs.org/api/util.html#util_util_format_format
*/
error(message: string, ...args: any[]): Promise<any>;
/**
* Log message at error level
* @param message The message to log, the message string can be interpolated like the node util.format method
* @param [data=null] An optional object which will be included in the log entry
* @return A promise which resolves when the log messages was logged, or null if the log level has
* skipped the message
* @function error
* @memberOf util.Logger.prototype
*
* @see https://nodejs.org/api/util.html#util_util_format_format
*/
error(message: string, data: any): Promise<any>;
}