garrettmills
1d5056b753
All checks were successful
continuous-integration/drone/push Build is passing
166 lines
4.9 KiB
TypeScript
166 lines
4.9 KiB
TypeScript
import {Logger, LoggingLevel, LogMessage} from '../util'
|
|
import {Singleton} from '../di'
|
|
|
|
/**
|
|
* A singleton service that manages loggers registered in the application, and
|
|
* can be used to log output to all of them based on the configured logging level.
|
|
*
|
|
* This should be used in place of `console.log` as it also supports logging to
|
|
* external locations.
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* logging.info('Info level!')
|
|
* logging.debug('Some debugging information...')
|
|
* logging.warn('A warning!', true) // true, to force it to show, regardless of logging level.
|
|
* ```
|
|
*/
|
|
@Singleton()
|
|
export class Logging {
|
|
/** Array of Logger implementations that should be logged to. */
|
|
protected registeredLoggers: Logger[] = []
|
|
|
|
/** The currently configured logging level. */
|
|
protected currentLevel: LoggingLevel = LoggingLevel.Warning
|
|
|
|
/** Register a Logger implementation with this service. */
|
|
public registerLogger(logger: Logger): this {
|
|
if ( !this.registeredLoggers.includes(logger) ) {
|
|
this.registeredLoggers.push(logger)
|
|
}
|
|
return this
|
|
}
|
|
|
|
/**
|
|
* Remove a Logger implementation from this service, if it is registered.
|
|
* @param logger
|
|
*/
|
|
public unregisterLogger(logger: Logger): this {
|
|
this.registeredLoggers = this.registeredLoggers.filter(x => x !== logger)
|
|
return this
|
|
}
|
|
|
|
/**
|
|
* Get the current logging level.
|
|
*/
|
|
public get level(): LoggingLevel {
|
|
return this.currentLevel
|
|
}
|
|
|
|
/**
|
|
* Set the current logging level.
|
|
* @param level
|
|
*/
|
|
public set level(level: LoggingLevel) {
|
|
this.currentLevel = level
|
|
}
|
|
|
|
/**
|
|
* Write a success-level output to the logs.
|
|
* @param output
|
|
* @param force - if true, output even if outside the current logging level
|
|
*/
|
|
public success(output: unknown, force = false): void {
|
|
this.writeLog(LoggingLevel.Success, output, force)
|
|
}
|
|
|
|
/**
|
|
* Write an error-level output to the logs.
|
|
* @param output
|
|
* @param force - if true, output even if outside the current logging level
|
|
*/
|
|
public error(output: unknown, force = false): void {
|
|
this.writeLog(LoggingLevel.Error, output, force)
|
|
}
|
|
|
|
/**
|
|
* Write a warning-level output to the logs.
|
|
* @param output
|
|
* @param force - if true, output even if outside the current logging level
|
|
*/
|
|
public warn(output: unknown, force = false): void {
|
|
this.writeLog(LoggingLevel.Warning, output, force)
|
|
}
|
|
|
|
/**
|
|
* Write an info-level output to the logs.
|
|
* @param output
|
|
* @param force - if true, output even if outside the current logging level
|
|
*/
|
|
public info(output: unknown, force = false): void {
|
|
this.writeLog(LoggingLevel.Info, output, force)
|
|
}
|
|
|
|
/**
|
|
* Write a debugging-level output to the logs.
|
|
* @param output
|
|
* @param force - if true, output even if outside the current logging level
|
|
*/
|
|
public debug(output: unknown, force = false): void {
|
|
this.writeLog(LoggingLevel.Debug, output, force)
|
|
}
|
|
|
|
/**
|
|
* Write a verbose-level output to the logs.
|
|
* @param output
|
|
* @param force - if true, output even if outside the current logging level
|
|
*/
|
|
public verbose(output: unknown, force = false): void {
|
|
this.writeLog(LoggingLevel.Verbose, output, force)
|
|
}
|
|
|
|
/**
|
|
* Helper function to write the given output, at the given logging level, to
|
|
* all of the registered loggers.
|
|
* @param level
|
|
* @param output
|
|
* @param force - if true, output even if outside the current logging level
|
|
* @protected
|
|
*/
|
|
protected writeLog(level: LoggingLevel, output: unknown, force = false): void {
|
|
const message = this.buildMessage(level, output)
|
|
if ( this.currentLevel >= level || force ) {
|
|
for ( const logger of this.registeredLoggers ) {
|
|
try {
|
|
logger.write(message)
|
|
} catch (e) {
|
|
console.error('logging error', e) // eslint-disable-line no-console
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Given a level and output item, build a formatted LogMessage with date and caller.
|
|
* @param level
|
|
* @param output
|
|
* @protected
|
|
*/
|
|
protected buildMessage(level: LoggingLevel, output: unknown): LogMessage {
|
|
return {
|
|
level,
|
|
output,
|
|
date: new Date(),
|
|
callerName: this.getCallerInfo(),
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the name of the object that called the log method using error traces.
|
|
* @param level
|
|
* @protected
|
|
*/
|
|
protected getCallerInfo(level = 5): string {
|
|
const e = new Error()
|
|
if ( !e.stack ) {
|
|
return 'Unknown'
|
|
}
|
|
|
|
return e.stack.split(/\s+at\s+/)
|
|
.slice(level)
|
|
.map((x: string): string => x.trim().split(' (')[0].split('.')[0].split(':')[0])[0]
|
|
.split('/')
|
|
.reverse()[0]
|
|
}
|
|
}
|