You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

162 lines
4.7 KiB

import {LoggingLevel, LogMessage} from './types.ts'
import Logger from './Logger.ts'
import {Service} from '../../../../di/src/decorator/Service.ts'
import {make} from '../../../../di/src/global.ts'
import {isInstantiable} from '../../../../di/src/type/Instantiable.ts'
/**
* Service for managing application logging.
*/
@Service()
class Logging {
/**
* The current logging level.
* @type LoggingLevel
*/
private _level = LoggingLevel.Warning
/**
* Loggers registered with this service.
* @type Array<Logger>
*/
private _loggers: Logger[] = []
/**
* Get the current logging level.
* @type LoggingLevel
*/
public get level() {
return this._level
}
/**
* Set the new logging level.
* @param {LoggingLevel} level
*/
public set level(level) {
this._level = level
}
/**
* Write an output with the success level.
* @param output
* @param {boolean} [force = false] - if true, the output will be written, regardless of the output level
*/
public success(output: any, force = false) {
this.write_log(LoggingLevel.Success, output, force)
}
/**
* Write an output with the error level.
* @param output
* @param {boolean} [force = false] - if true, the output will be written, regardless of the output level
*/
public error(output: any, force = false) {
this.write_log(LoggingLevel.Error, output, force)
}
/**
* Write an output with the warning level.
* @param output
* @param {boolean} [force = false] - if true, the output will be written, regardless of the output level
*/
public warn(output: any, force = false) {
this.write_log(LoggingLevel.Warning, output, force)
}
/**
* Write an output with the info level.
* @param output
* @param {boolean} [force = false] - if true, the output will be written, regardless of the output level
*/
public info(output: any, force = false) {
this.write_log(LoggingLevel.Info, output, force)
}
/**
* Write an output with the debug level.
* @param output
* @param {boolean} [force = false] - if true, the output will be written, regardless of the output level
*/
public debug(output: any, force = false) {
this.write_log(LoggingLevel.Debug, output, force)
}
/**
* Write an output with the verbose level.
* @param output
* @param {boolean} [force = false] - if true, the output will be written, regardless of the output level
*/
public verbose(output: any, force = false) {
this.write_log(LoggingLevel.Verbose, output, force)
}
/**
* Writes the output at the given logging level.
* @param {LoggingLevel} level
* @param output
* @param {boolean} [force = false]
*/
protected write_log(level: LoggingLevel, output: any, force = false) {
const message = this.build_message(level, output)
if ( this._level >= level || force ) {
for ( const logger of this._loggers ) {
try {
logger.write(message)
} catch (e) {
console.error('logging error', e)
}
}
}
}
/**
* Given an output and level, build a log message object.
* @param {LoggingLevel} level
* @param output
* @return LogMessage
*/
protected build_message(level: LoggingLevel, output: any): LogMessage {
return {
level,
output,
date: new Date,
caller_name: this.get_caller_info(),
}
}
/**
* Register a logger with this class.
* @param {typeof Logger} logger_class
*/
public register_logger(logger_class: typeof Logger) {
if ( isInstantiable(logger_class) ) {
const logger = make(logger_class)
if ( !this._loggers.includes(logger) )
this._loggers.push(logger)
}
}
/**
* Remove a logger from this class.
* @param {typeof Logger} logger_class
*/
public remove_logger(logger_class: typeof Logger) {
this._loggers = this._loggers.filter(x => !(x instanceof logger_class))
}
/**
* Get the information about the caller of a given context.
* @param {number} [level = 5] - how far up in the stacktrace to go
*/
protected get_caller_info(level = 5): string {
let e = new Error
if ( !e.stack ) return 'Unknown'
return e.stack.split(' at ')
.slice(level)
.map((x: string): string => x.trim().split(' (')[0].split('.')[0].split(':')[0])[0]
}
}
export { Logging }