Skip to content

Commit

Permalink
perf(common): faster logs by caching intl.datetimeformat
Browse files Browse the repository at this point in the history
  • Loading branch information
H4ad committed Jan 7, 2023
1 parent 95e096f commit b029328
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 95 deletions.
22 changes: 10 additions & 12 deletions packages/common/services/console-logger.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ const DEFAULT_LOG_LEVELS: LogLevel[] = [
'verbose',
];

const dateTimeFormatter = Intl.DateTimeFormat(undefined, {
year: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
day: '2-digit',
month: '2-digit',
});

@Injectable()
export class ConsoleLogger implements LoggerService {
private static lastTimestampAt?: number;
Expand Down Expand Up @@ -162,18 +171,7 @@ export class ConsoleLogger implements LoggerService {
}

protected getTimestamp(): string {
const localeStringOptions = {
year: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
day: '2-digit',
month: '2-digit',
};
return new Date(Date.now()).toLocaleString(
undefined,
localeStringOptions as Intl.DateTimeFormatOptions,
);
return dateTimeFormatter.format(Date.now());
}

protected printMessages(
Expand Down
153 changes: 70 additions & 83 deletions packages/common/services/logger.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,47 +39,26 @@ export interface LoggerService {
setLogLevels?(levels: LogLevel[]): any;
}

interface LogBufferRecord {
/**
* Method to execute.
*/
methodRef: Function;

/**
* Arguments to pass to the method.
*/
arguments: unknown[];
}

const DEFAULT_LOGGER = new ConsoleLogger();

const dateTimeFormatter = Intl.DateTimeFormat(undefined, {
year: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
day: '2-digit',
month: '2-digit',
});

@Injectable()
export class Logger implements LoggerService {
protected static logBuffer = new Array<LogBufferRecord>();
protected static logBuffer = new Array<Function>();
protected static staticInstanceRef?: LoggerService = DEFAULT_LOGGER;
protected static logLevels?: LogLevel[];
private static isBufferAttached: boolean;

protected localInstanceRef?: LoggerService;

private static WrapBuffer: MethodDecorator = (
target: object,
propertyKey: string | symbol,
descriptor: TypedPropertyDescriptor<any>,
) => {
const originalFn = descriptor.value;
descriptor.value = function (...args: unknown[]) {
if (Logger.isBufferAttached) {
Logger.logBuffer.push({
methodRef: originalFn.bind(this),
arguments: args,
});
return;
}
return originalFn.call(this, ...args);
};
};

constructor();
constructor(context: string);
constructor(context: string, options?: { timestamp?: boolean });
Expand All @@ -97,73 +76,89 @@ export class Logger implements LoggerService {
return this.registerLocalInstanceRef();
}
}

return Logger.staticInstanceRef;
}

private static wrapBuffer(logMethod: Function): void {
if (!Logger.isBufferAttached) return logMethod();

Logger.logBuffer.push(logMethod);
}

/**
* Write an 'error' level log.
*/
error(message: any, stack?: string, context?: string): void;
error(message: any, ...optionalParams: [...any, string?, string?]): void;
@Logger.WrapBuffer
error(message: any, ...optionalParams: any[]) {
optionalParams = this.context
? optionalParams.concat(this.context)
: optionalParams;
Logger.wrapBuffer(() => {
optionalParams = this.context
? optionalParams.concat(this.context)
: optionalParams;

this.localInstance?.error(message, ...optionalParams);
this.localInstance?.error(message, ...optionalParams);
});
}

/**
* Write a 'log' level log.
*/
log(message: any, context?: string): void;
log(message: any, ...optionalParams: [...any, string?]): void;
@Logger.WrapBuffer
log(message: any, ...optionalParams: any[]) {
optionalParams = this.context
? optionalParams.concat(this.context)
: optionalParams;
this.localInstance?.log(message, ...optionalParams);
Logger.wrapBuffer(() => {
optionalParams = this.context
? optionalParams.concat(this.context)
: optionalParams;

this.localInstance?.log(message, ...optionalParams);
});
}

/**
* Write a 'warn' level log.
*/
warn(message: any, context?: string): void;
warn(message: any, ...optionalParams: [...any, string?]): void;
@Logger.WrapBuffer
warn(message: any, ...optionalParams: any[]) {
optionalParams = this.context
? optionalParams.concat(this.context)
: optionalParams;
this.localInstance?.warn(message, ...optionalParams);
Logger.wrapBuffer(() => {
optionalParams = this.context
? optionalParams.concat(this.context)
: optionalParams;

this.localInstance?.warn(message, ...optionalParams);
});
}

/**
* Write a 'debug' level log.
*/
debug(message: any, context?: string): void;
debug(message: any, ...optionalParams: [...any, string?]): void;
@Logger.WrapBuffer
debug(message: any, ...optionalParams: any[]) {
optionalParams = this.context
? optionalParams.concat(this.context)
: optionalParams;
this.localInstance?.debug?.(message, ...optionalParams);
Logger.wrapBuffer(() => {
optionalParams = this.context
? optionalParams.concat(this.context)
: optionalParams;

this.localInstance?.debug(message, ...optionalParams);
});
}

/**
* Write a 'verbose' level log.
*/
verbose(message: any, context?: string): void;
verbose(message: any, ...optionalParams: [...any, string?]): void;
@Logger.WrapBuffer
verbose(message: any, ...optionalParams: any[]) {
optionalParams = this.context
? optionalParams.concat(this.context)
: optionalParams;
this.localInstance?.verbose?.(message, ...optionalParams);
Logger.wrapBuffer(() => {
optionalParams = this.context
? optionalParams.concat(this.context)
: optionalParams;

this.localInstance?.verbose?.(message, ...optionalParams);
});
}

/**
Expand All @@ -175,29 +170,32 @@ export class Logger implements LoggerService {
message: any,
...optionalParams: [...any, string?, string?]
): void;
@Logger.WrapBuffer
static error(message: any, ...optionalParams: any[]) {
this.staticInstanceRef?.error(message, ...optionalParams);
Logger.wrapBuffer(() => {
this.staticInstanceRef?.error(message, ...optionalParams);
});
}

/**
* Write a 'log' level log.
*/
static log(message: any, context?: string): void;
static log(message: any, ...optionalParams: [...any, string?]): void;
@Logger.WrapBuffer
static log(message: any, ...optionalParams: any[]) {
this.staticInstanceRef?.log(message, ...optionalParams);
Logger.wrapBuffer(() => {
this.staticInstanceRef?.log(message, ...optionalParams);
});
}

/**
* Write a 'warn' level log.
*/
static warn(message: any, context?: string): void;
static warn(message: any, ...optionalParams: [...any, string?]): void;
@Logger.WrapBuffer
static warn(message: any, ...optionalParams: any[]) {
this.staticInstanceRef?.warn(message, ...optionalParams);
Logger.wrapBuffer(() => {
this.staticInstanceRef?.warn(message, ...optionalParams);
});
}

/**
Expand All @@ -206,61 +204,50 @@ export class Logger implements LoggerService {
*/
static debug(message: any, context?: string): void;
static debug(message: any, ...optionalParams: [...any, string?]): void;
@Logger.WrapBuffer
static debug(message: any, ...optionalParams: any[]) {
this.staticInstanceRef?.debug?.(message, ...optionalParams);
Logger.wrapBuffer(() => {
this.staticInstanceRef?.debug(message, ...optionalParams);
});
}

/**
* Write a 'verbose' level log.
*/
static verbose(message: any, context?: string): void;
static verbose(message: any, ...optionalParams: [...any, string?]): void;
@Logger.WrapBuffer
static verbose(message: any, ...optionalParams: any[]) {
this.staticInstanceRef?.verbose?.(message, ...optionalParams);
Logger.wrapBuffer(() => {
this.staticInstanceRef?.verbose(message, ...optionalParams);
});
}

/**
* Print buffered logs and detach buffer.
*/
static flush() {
this.isBufferAttached = false;
this.logBuffer.forEach(item =>
item.methodRef(...(item.arguments as [string])),
);
this.logBuffer.forEach(logMethod => logMethod());
this.logBuffer = [];
}

/**
* Attach buffer.
* Turns on initialisation logs buffering.
* Turns on initialization logs buffering.
*/
static attachBuffer() {
this.isBufferAttached = true;
}

/**
* Detach buffer.
* Turns off initialisation logs buffering.
* Turns off initialization logs buffering.
*/
static detachBuffer() {
this.isBufferAttached = false;
}

static getTimestamp() {
const localeStringOptions = {
year: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
day: '2-digit',
month: '2-digit',
};
return new Date(Date.now()).toLocaleString(
undefined,
localeStringOptions as Intl.DateTimeFormatOptions,
);
return dateTimeFormatter.format(Date.now());
}

static overrideLogger(logger: LoggerService | LogLevel[] | boolean) {
Expand Down

0 comments on commit b029328

Please sign in to comment.