mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
94 lines
3.3 KiB
TypeScript
94 lines
3.3 KiB
TypeScript
import cluster from 'cluster';
|
|
import { WrappingLogger } from './Logger';
|
|
import type { Logger } from './Logger';
|
|
import type { LoggerFactory } from './LoggerFactory';
|
|
import type { LogLevel } from './LogLevel';
|
|
|
|
/**
|
|
* Temporary {@link LoggerFactory} that buffers log messages in memory
|
|
* until the {@link TemporaryLoggerFactory#switch} method is called.
|
|
*/
|
|
class TemporaryLoggerFactory implements LoggerFactory {
|
|
private bufferSpaces: number;
|
|
private readonly wrappers: { wrapper: WrappingLogger; label: string }[] = [];
|
|
private readonly buffer: { logger: Logger; level: LogLevel; message: string }[] = [];
|
|
|
|
public constructor(bufferSize = 1024) {
|
|
this.bufferSpaces = bufferSize;
|
|
}
|
|
|
|
public createLogger(label: string): WrappingLogger {
|
|
const wrapper = new WrappingLogger({
|
|
log: (level: LogLevel, message: string): Logger =>
|
|
this.bufferLogEntry(wrapper, level, message),
|
|
});
|
|
this.wrappers.push({ wrapper, label });
|
|
return wrapper;
|
|
}
|
|
|
|
private bufferLogEntry(logger: WrappingLogger, level: LogLevel, message: string): Logger {
|
|
// Buffer the message if spaces are still available
|
|
if (this.bufferSpaces > 0) {
|
|
this.bufferSpaces -= 1;
|
|
// If this is the last space, instead generate a warning through a new logger
|
|
if (this.bufferSpaces === 0) {
|
|
logger = this.createLogger('LazyLoggerFactory');
|
|
level = 'warn';
|
|
message = `Memory-buffered logging limit of ${this.buffer.length + 1} reached`;
|
|
}
|
|
this.buffer.push({ logger, level, message });
|
|
}
|
|
return logger;
|
|
}
|
|
|
|
/**
|
|
* Swaps all lazy loggers to new loggers from the given factory,
|
|
* and emits any buffered messages through those actual loggers.
|
|
*/
|
|
public switch(loggerFactory: LoggerFactory): void {
|
|
// Instantiate an actual logger within every lazy logger
|
|
for (const { wrapper, label } of this.wrappers.splice(0, this.wrappers.length)) {
|
|
wrapper.logger = loggerFactory.createLogger(label);
|
|
}
|
|
// Emit all buffered log messages
|
|
for (const { logger, level, message } of this.buffer.splice(0, this.buffer.length)) {
|
|
logger.log(level, message, { isPrimary: cluster.isMaster, pid: process.pid });
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Wraps around another {@link LoggerFactory} that can be set lazily.
|
|
* This is useful when objects are instantiated (and when they create loggers)
|
|
* before the logging system has been fully instantiated,
|
|
* as is the case when using a dependency injection framework such as Components.js.
|
|
*
|
|
* Loggers can be created even before a {@link LoggerFactory} is set;
|
|
* any log messages will be buffered and re-emitted.
|
|
*/
|
|
export class LazyLoggerFactory implements LoggerFactory {
|
|
private factory: LoggerFactory;
|
|
|
|
public constructor(options: { bufferSize?: number } = {}) {
|
|
this.factory = new TemporaryLoggerFactory(options.bufferSize);
|
|
}
|
|
|
|
public get loggerFactory(): LoggerFactory {
|
|
if (this.factory instanceof TemporaryLoggerFactory) {
|
|
throw new Error('Logger factory not yet set.');
|
|
}
|
|
return this.factory;
|
|
}
|
|
|
|
public set loggerFactory(loggerFactory: LoggerFactory) {
|
|
if (this.factory instanceof TemporaryLoggerFactory) {
|
|
this.factory.switch(loggerFactory);
|
|
}
|
|
this.factory = loggerFactory;
|
|
}
|
|
|
|
public createLogger(label: string): Logger {
|
|
return this.factory.createLogger(label);
|
|
}
|
|
}
|