add new Console global DI to abstract the node.js console

This commit is contained in:
Hazelnoot 2025-10-08 17:01:11 -04:00
parent 8059515db4
commit 9b99e8eba8
4 changed files with 24 additions and 19 deletions

View file

@ -14,6 +14,7 @@ import { TimeService, NativeTimeService } from '@/global/TimeService.js';
import { EnvService } from '@/global/EnvService.js';
import { CacheManagementService } from '@/global/CacheManagementService.js';
import { InternalEventService } from '@/global/InternalEventService.js';
import { DependencyService } from '@/global/DependencyService.js';
import { LoggerService } from '@/core/LoggerService.js';
import { DI } from './di-symbols.js';
import { Config, loadConfig } from './config.js';
@ -179,12 +180,14 @@ const $TimeService: Provider[] = [
];
const $EnvService: Provider[] = [EnvService, { provide: 'EnvService', useExisting: EnvService }];
const $LoggerService: Provider[] = [LoggerService, { provide: 'LoggerService', useExisting: LoggerService }];
const $Console: Provider[] = [{ provide: DI.console, useValue: global.console }];
const $DependencyService: Provider[] = [DependencyService, { provide: 'DependencyService', useExisting: DependencyService }];
@Global()
@Module({
imports: [RepositoryModule],
providers: [$config, $db, $meta, $meilisearch, $redis, $redisForPub, $redisForSub, $redisForTimelines, $redisForReactions, $redisForRateLimit, $CacheManagementService, $InternalEventService, $TimeService, $EnvService, $LoggerService].flat(),
exports: [$config, $db, $meta, $meilisearch, $redis, $redisForPub, $redisForSub, $redisForTimelines, $redisForReactions, $redisForRateLimit, $CacheManagementService, $InternalEventService, $TimeService, $EnvService, $LoggerService, RepositoryModule].flat(),
providers: [$config, $db, $meta, $meilisearch, $redis, $redisForPub, $redisForSub, $redisForTimelines, $redisForReactions, $redisForRateLimit, $CacheManagementService, $InternalEventService, $TimeService, $EnvService, $LoggerService, $Console, $DependencyService].flat(),
exports: [$config, $db, $meta, $meilisearch, $redis, $redisForPub, $redisForSub, $redisForTimelines, $redisForReactions, $redisForRateLimit, $CacheManagementService, $InternalEventService, $TimeService, $EnvService, $LoggerService, RepositoryModule, $Console, $DependencyService].flat(),
})
export class GlobalModule implements OnApplicationShutdown {
private readonly logger = new Logger('global');

View file

@ -6,24 +6,24 @@
import { Inject, Injectable } from '@nestjs/common';
import Logger from '@/logger.js';
import { TimeService } from '@/global/TimeService.js';
import { EnvService } from '@/global/EnvService.js';
import { bindThis } from '@/decorators.js';
import type { KEYWORD } from 'color-convert/conversions.js';
import { envOption } from '@/env.js'; // TODO move to envService
import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
import type { KEYWORD } from 'color-convert/conversions.js';
@Injectable()
export class LoggerService {
constructor(
@Inject(DI.config)
private config: Config,
private readonly timeService: TimeService,
@Inject(DI.console)
protected readonly console: Console,
protected readonly timeService: TimeService,
protected readonly envService: EnvService,
) {
}
@bindThis
public getLogger(domain: string, color?: KEYWORD | undefined) {
const verbose = this.config.logging?.verbose || envOption.verbose;
return new Logger(domain, color, verbose, undefined, this.timeService);
return new Logger(domain, color, this.envService, this.timeService, this.console);
}
}

View file

@ -14,6 +14,7 @@ export const DI = {
redisForTimelines: Symbol('redisForTimelines'),
redisForReactions: Symbol('redisForReactions'),
redisForRateLimit: Symbol('redisForRateLimit'),
console: Symbol('console'),
//#region Repositories
usersRepository: Symbol('usersRepository'),

View file

@ -9,7 +9,7 @@ import { default as convertColor } from 'color-convert';
import { format as dateFormat } from 'date-fns';
import { bindThis } from '@/decorators.js';
import { TimeService, NativeTimeService } from '@/global/TimeService.js';
import { envOption } from './env.js';
import { EnvService } from '@/global/EnvService.js';
import type { KEYWORD } from 'color-convert/conversions.js';
type Context = {
@ -28,6 +28,7 @@ export type Console = Pick<typeof global.console, 'error' | 'warn' | 'info' | 'l
export const nativeConsole: Console = global.console;
const fallbackTimeService = new NativeTimeService();
const fallbackEnvService = new EnvService();
const levelFuncs = {
error: 'error',
@ -41,8 +42,8 @@ const levelFuncs = {
export default class Logger {
private context: Context;
private parentLogger: Logger | null = null;
public readonly verbose: boolean;
private readonly timeService: TimeService;
private readonly envService: EnvService;
/**
* Where to send the actual log strings.
@ -50,26 +51,26 @@ export default class Logger {
*/
private readonly console: Console;
constructor(context: string, color?: KEYWORD, verbose?: boolean, console?: Console, timeService?: TimeService) {
constructor(context: string, color?: KEYWORD, envService?: EnvService, timeService?: TimeService, console?: Console) {
this.context = {
name: context,
color: color,
};
this.verbose = verbose ?? envOption.verbose;
this.envService = envService ?? fallbackEnvService;
this.console = console ?? nativeConsole;
this.timeService = timeService ?? fallbackTimeService;
}
@bindThis
public createSubLogger(context: string, color?: KEYWORD): Logger {
const logger = new Logger(context, color, this.verbose, this.console, this.timeService);
const logger = new Logger(context, color, this.envService, this.timeService, this.console);
logger.parentLogger = this;
return logger;
}
@bindThis
private log(level: Level, message: string, data?: Data, important = false, subContexts: Context[] = []): void {
if (envOption.quiet) return;
if (this.envService.options.quiet) return;
if (this.parentLogger) {
this.parentLogger.log(level, message, data, important, [this.context].concat(subContexts));
@ -94,10 +95,10 @@ export default class Logger {
level === 'info' ? message :
null;
let log = envOption.hideWorkerId
let log = this.envService.options.hideWorkerId
? `${l}\t[${contexts.join(' ')}]\t\t${m}`
: `${l} ${worker}\t[${contexts.join(' ')}]\t\t${m}`;
if (envOption.withLogTime) log = chalk.gray(time) + ' ' + log;
if (this.envService.options.withLogTime) log = chalk.gray(time) + ' ' + log;
const args: unknown[] = [important ? chalk.bold(log) : log];
if (Array.isArray(data)) {
@ -137,7 +138,7 @@ export default class Logger {
@bindThis
public debug(message: string, data?: Data, important = false): void { // デバッグ用に使う(開発者に必要だが利用者に不要な情報)
if (process.env.NODE_ENV !== 'production' || this.verbose) {
if (process.env.NODE_ENV !== 'production' || this.envService.options.verbose) {
this.log('debug', message, data, important);
}
}