From 6e6deec40c223b987eab8b82265516933dae95fb Mon Sep 17 00:00:00 2001 From: AmAn Sharma Date: Wed, 17 Apr 2024 03:00:31 +0530 Subject: [PATCH] feat: use ILoggerRepository (#8855) * Migrate ImmichLogger over to injected ILoggerRepository * chore: cleanup and tests --------- Co-authored-by: Jason Rasmussen --- .../commands/reset-admin-password.command.ts | 2 +- .../src/controllers/shared-link.controller.ts | 2 +- .../controllers/system-config.controller.ts | 2 +- server/src/cores/storage.core.ts | 48 +++++++++-------- server/src/cores/system-config.core.ts | 12 +++-- server/src/main.ts | 4 +- .../src/middleware/file-upload.interceptor.ts | 9 ++-- server/src/repositories/access.repository.ts | 2 + server/src/repositories/audit.repository.ts | 2 + .../src/repositories/database.repository.ts | 12 +++-- server/src/repositories/event.repository.ts | 11 ++-- server/src/repositories/job.repository.ts | 10 ++-- server/src/repositories/logger.repository.ts | 4 +- server/src/repositories/media.repository.ts | 9 ++-- .../src/repositories/metadata.repository.ts | 16 +++--- server/src/repositories/metric.repository.ts | 2 +- server/src/repositories/partner.repository.ts | 2 +- server/src/repositories/person.repository.ts | 2 + server/src/repositories/search.repository.ts | 9 ++-- .../repositories/storage.repository.spec.ts | 6 ++- server/src/repositories/storage.repository.ts | 8 ++- .../repositories/system-config.repository.ts | 2 + .../system-metadata.repository.ts | 2 + server/src/services/api.service.ts | 11 ++-- server/src/services/asset-v1.service.spec.ts | 15 +++++- server/src/services/asset-v1.service.ts | 5 +- server/src/services/asset.service.spec.ts | 5 ++ server/src/services/asset.service.ts | 7 +-- server/src/services/audit.service.spec.ts | 6 ++- server/src/services/audit.service.ts | 5 +- server/src/services/auth.service.ts | 6 +-- server/src/services/database.service.spec.ts | 52 ++++++++----------- server/src/services/database.service.ts | 9 ++-- server/src/services/job.service.spec.ts | 8 ++- server/src/services/job.service.ts | 7 +-- server/src/services/library.service.spec.ts | 17 +++++- server/src/services/library.service.ts | 7 +-- server/src/services/media.service.spec.ts | 16 +++++- server/src/services/media.service.ts | 12 +++-- server/src/services/metadata.service.spec.ts | 5 ++ server/src/services/metadata.service.ts | 12 +++-- server/src/services/person.service.spec.ts | 5 ++ server/src/services/person.service.ts | 12 +++-- server/src/services/search.service.spec.ts | 15 +++++- server/src/services/search.service.ts | 5 +- .../src/services/server-info.service.spec.ts | 14 ++++- server/src/services/server-info.service.ts | 9 ++-- .../src/services/smart-info.service.spec.ts | 6 ++- server/src/services/smart-info.service.ts | 7 +-- .../services/storage-template.service.spec.ts | 7 ++- .../src/services/storage-template.service.ts | 12 +++-- server/src/services/storage.service.spec.ts | 6 ++- server/src/services/storage.service.ts | 11 ++-- .../services/system-config.service.spec.ts | 17 ++---- server/src/services/system-config.service.ts | 4 +- server/src/services/user.service.spec.ts | 15 +++++- server/src/services/user.service.ts | 7 +-- server/src/utils/misc.ts | 4 +- server/src/utils/sql.ts | 4 ++ 59 files changed, 352 insertions(+), 191 deletions(-) diff --git a/server/src/commands/reset-admin-password.command.ts b/server/src/commands/reset-admin-password.command.ts index a186603a3f..f7c0775c8b 100644 --- a/server/src/commands/reset-admin-password.command.ts +++ b/server/src/commands/reset-admin-password.command.ts @@ -9,7 +9,7 @@ import { UserService } from 'src/services/user.service'; export class ResetAdminPasswordCommand extends CommandRunner { constructor( private userService: UserService, - private readonly inquirer: InquirerService, + private inquirer: InquirerService, ) { super(); } diff --git a/server/src/controllers/shared-link.controller.ts b/server/src/controllers/shared-link.controller.ts index 990f4e3225..a7a8e3a1c6 100644 --- a/server/src/controllers/shared-link.controller.ts +++ b/server/src/controllers/shared-link.controller.ts @@ -19,7 +19,7 @@ import { UUIDParamDto } from 'src/validation'; @Controller('shared-link') @Authenticated() export class SharedLinkController { - constructor(private readonly service: SharedLinkService) {} + constructor(private service: SharedLinkService) {} @Get() getAllSharedLinks(@Auth() auth: AuthDto): Promise { diff --git a/server/src/controllers/system-config.controller.ts b/server/src/controllers/system-config.controller.ts index 0b46b82a51..08da743191 100644 --- a/server/src/controllers/system-config.controller.ts +++ b/server/src/controllers/system-config.controller.ts @@ -8,7 +8,7 @@ import { SystemConfigService } from 'src/services/system-config.service'; @Controller('system-config') @Authenticated({ admin: true }) export class SystemConfigController { - constructor(private readonly service: SystemConfigService) {} + constructor(private service: SystemConfigService) {} @Get() getConfig(): Promise { diff --git a/server/src/cores/storage.core.ts b/server/src/cores/storage.core.ts index 035f90c911..f1c16e5698 100644 --- a/server/src/cores/storage.core.ts +++ b/server/src/cores/storage.core.ts @@ -7,11 +7,11 @@ import { PersonEntity } from 'src/entities/person.entity'; import { ImageFormat } from 'src/entities/system-config.entity'; import { IAssetRepository } from 'src/interfaces/asset.interface'; import { ICryptoRepository } from 'src/interfaces/crypto.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IMoveRepository } from 'src/interfaces/move.interface'; import { IPersonRepository } from 'src/interfaces/person.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; -import { ImmichLogger } from 'src/utils/logger'; export enum StorageFolder { ENCODED_VIDEO = 'encoded-video', @@ -41,35 +41,37 @@ export type GeneratedAssetType = GeneratedImageType | AssetPathType.ENCODED_VIDE let instance: StorageCore | null; export class StorageCore { - private logger = new ImmichLogger(StorageCore.name); private configCore; private constructor( private assetRepository: IAssetRepository, + private cryptoRepository: ICryptoRepository, private moveRepository: IMoveRepository, private personRepository: IPersonRepository, - private cryptoRepository: ICryptoRepository, - private repository: IStorageRepository, + private storageRepository: IStorageRepository, systemConfigRepository: ISystemConfigRepository, + private logger: ILoggerRepository, ) { - this.configCore = SystemConfigCore.create(systemConfigRepository); + this.configCore = SystemConfigCore.create(systemConfigRepository, this.logger); } static create( assetRepository: IAssetRepository, + cryptoRepository: ICryptoRepository, moveRepository: IMoveRepository, personRepository: IPersonRepository, - cryptoRepository: ICryptoRepository, - configRepository: ISystemConfigRepository, - repository: IStorageRepository, + storageRepository: IStorageRepository, + systemConfigRepository: ISystemConfigRepository, + logger: ILoggerRepository, ) { if (!instance) { instance = new StorageCore( assetRepository, + cryptoRepository, moveRepository, personRepository, - cryptoRepository, - repository, - configRepository, + storageRepository, + systemConfigRepository, + logger, ); } @@ -170,8 +172,8 @@ export class StorageCore { let move = await this.moveRepository.getByEntity(entityId, pathType); if (move) { this.logger.log(`Attempting to finish incomplete move: ${move.oldPath} => ${move.newPath}`); - const oldPathExists = await this.repository.checkFileExists(move.oldPath); - const newPathExists = await this.repository.checkFileExists(move.newPath); + const oldPathExists = await this.storageRepository.checkFileExists(move.oldPath); + const newPathExists = await this.storageRepository.checkFileExists(move.newPath); const newPathCheck = newPathExists ? move.newPath : null; const actualPath = oldPathExists ? move.oldPath : newPathCheck; if (!actualPath) { @@ -205,7 +207,7 @@ export class StorageCore { if (move.oldPath !== newPath) { try { this.logger.debug(`Attempting to rename file: ${move.oldPath} => ${newPath}`); - await this.repository.rename(move.oldPath, newPath); + await this.storageRepository.rename(move.oldPath, newPath); } catch (error: any) { if (error.code !== 'EXDEV') { this.logger.warn( @@ -214,19 +216,19 @@ export class StorageCore { return; } this.logger.debug(`Unable to rename file. Falling back to copy, verify and delete`); - await this.repository.copyFile(move.oldPath, newPath); + await this.storageRepository.copyFile(move.oldPath, newPath); if (!(await this.verifyNewPathContentsMatchesExpected(move.oldPath, newPath, assetInfo))) { this.logger.warn(`Skipping move due to file size mismatch`); - await this.repository.unlink(newPath); + await this.storageRepository.unlink(newPath); return; } - const { atime, mtime } = await this.repository.stat(move.oldPath); - await this.repository.utimes(newPath, atime, mtime); + const { atime, mtime } = await this.storageRepository.stat(move.oldPath); + await this.storageRepository.utimes(newPath, atime, mtime); try { - await this.repository.unlink(move.oldPath); + await this.storageRepository.unlink(move.oldPath); } catch (error: any) { this.logger.warn(`Unable to delete old file, it will now no longer be tracked by Immich: ${error.message}`); } @@ -242,8 +244,8 @@ export class StorageCore { newPath: string, assetInfo?: { sizeInBytes: number; checksum: Buffer }, ) { - const oldStat = await this.repository.stat(oldPath); - const newStat = await this.repository.stat(newPath); + const oldStat = await this.storageRepository.stat(oldPath); + const newStat = await this.storageRepository.stat(newPath); const oldPathSize = assetInfo ? assetInfo.sizeInBytes : oldStat.size; const newPathSize = newStat.size; this.logger.debug(`File size check: ${newPathSize} === ${oldPathSize}`); @@ -269,11 +271,11 @@ export class StorageCore { } ensureFolders(input: string) { - this.repository.mkdirSync(dirname(input)); + this.storageRepository.mkdirSync(dirname(input)); } removeEmptyDirs(folder: StorageFolder) { - return this.repository.removeEmptyDirs(StorageCore.getBaseFolder(folder)); + return this.storageRepository.removeEmptyDirs(StorageCore.getBaseFolder(folder)); } private savePath(pathType: PathType, id: string, newPath: string) { diff --git a/server/src/cores/system-config.core.ts b/server/src/cores/system-config.core.ts index 3a1ea47bbe..9cbe3b8414 100644 --- a/server/src/cores/system-config.core.ts +++ b/server/src/cores/system-config.core.ts @@ -22,8 +22,8 @@ import { VideoCodec, } from 'src/entities/system-config.entity'; import { QueueName } from 'src/interfaces/job.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; -import { ImmichLogger } from 'src/utils/logger'; export type SystemConfigValidator = (config: SystemConfig, newConfig: SystemConfig) => void | Promise; @@ -169,16 +169,18 @@ let instance: SystemConfigCore | null; @Injectable() export class SystemConfigCore { - private logger = new ImmichLogger(SystemConfigCore.name); private configCache: SystemConfigEntity[] | null = null; public config$ = new Subject(); - private constructor(private repository: ISystemConfigRepository) {} + private constructor( + private repository: ISystemConfigRepository, + private logger: ILoggerRepository, + ) {} - static create(repository: ISystemConfigRepository) { + static create(repository: ISystemConfigRepository, logger: ILoggerRepository) { if (!instance) { - instance = new SystemConfigCore(repository); + instance = new SystemConfigCore(repository, logger); } return instance; } diff --git a/server/src/main.ts b/server/src/main.ts index 30b1b8fc01..54e6a97acc 100644 --- a/server/src/main.ts +++ b/server/src/main.ts @@ -20,7 +20,7 @@ async function bootstrapMicroservices() { const host = String(process.env.HOST || '0.0.0.0'); const port = Number(process.env.MICROSERVICES_PORT) || 3002; const app = await NestFactory.create(MicroservicesModule, { bufferLogs: true }); - const logger = app.get(ILoggerRepository); + const logger = await app.resolve(ILoggerRepository); logger.setContext('ImmichMicroservice'); app.useLogger(logger); app.useWebSocketAdapter(new WebSocketAdapter(app)); @@ -36,7 +36,7 @@ async function bootstrapApi() { const host = String(process.env.HOST || '0.0.0.0'); const port = Number(process.env.SERVER_PORT) || 3001; const app = await NestFactory.create(ApiModule, { bufferLogs: true }); - const logger = app.get(ILoggerRepository); + const logger = await app.resolve(ILoggerRepository); logger.setContext('ImmichServer'); app.useLogger(logger); diff --git a/server/src/middleware/file-upload.interceptor.ts b/server/src/middleware/file-upload.interceptor.ts index 53acbefa88..1b8405fe6e 100644 --- a/server/src/middleware/file-upload.interceptor.ts +++ b/server/src/middleware/file-upload.interceptor.ts @@ -1,4 +1,4 @@ -import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common'; +import { CallHandler, ExecutionContext, Inject, Injectable, NestInterceptor } from '@nestjs/common'; import { PATH_METADATA } from '@nestjs/common/constants'; import { Reflector } from '@nestjs/core'; import { transformException } from '@nestjs/platform-express/multer/multer/multer.utils'; @@ -7,9 +7,9 @@ import multer, { StorageEngine, diskStorage } from 'multer'; import { createHash, randomUUID } from 'node:crypto'; import { Observable } from 'rxjs'; import { UploadFieldName } from 'src/dtos/asset.dto'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { AuthRequest } from 'src/middleware/auth.guard'; import { AssetService, UploadFile } from 'src/services/asset.service'; -import { ImmichLogger } from 'src/utils/logger'; export enum Route { ASSET = 'asset', @@ -59,8 +59,6 @@ const asRequest = (request: AuthRequest, file: Express.Multer.File) => { @Injectable() export class FileUploadInterceptor implements NestInterceptor { - private logger = new ImmichLogger(FileUploadInterceptor.name); - private handlers: { userProfile: RequestHandler; assetUpload: RequestHandler; @@ -70,7 +68,10 @@ export class FileUploadInterceptor implements NestInterceptor { constructor( private reflect: Reflector, private assetService: AssetService, + @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { + this.logger.setContext(FileUploadInterceptor.name); + this.defaultStorage = diskStorage({ filename: this.filename.bind(this), destination: this.destination.bind(this), diff --git a/server/src/repositories/access.repository.ts b/server/src/repositories/access.repository.ts index fd74eb2ec9..469de11be6 100644 --- a/server/src/repositories/access.repository.ts +++ b/server/src/repositories/access.repository.ts @@ -1,3 +1,4 @@ +import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { ChunkedSet, DummyValue, GenerateSql } from 'src/decorators'; import { ActivityEntity } from 'src/entities/activity.entity'; @@ -25,6 +26,7 @@ type IPersonAccess = IAccessRepository['person']; type IPartnerAccess = IAccessRepository['partner']; @Instrumentation() +@Injectable() class ActivityAccess implements IActivityAccess { constructor( private activityRepository: Repository, diff --git a/server/src/repositories/audit.repository.ts b/server/src/repositories/audit.repository.ts index 3332b06fe1..6cf5b76e6e 100644 --- a/server/src/repositories/audit.repository.ts +++ b/server/src/repositories/audit.repository.ts @@ -1,3 +1,4 @@ +import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { AuditEntity } from 'src/entities/audit.entity'; import { AuditSearch, IAuditRepository } from 'src/interfaces/audit.interface'; @@ -5,6 +6,7 @@ import { Instrumentation } from 'src/utils/instrumentation'; import { In, LessThan, MoreThan, Repository } from 'typeorm'; @Instrumentation() +@Injectable() export class AuditRepository implements IAuditRepository { constructor(@InjectRepository(AuditEntity) private repository: Repository) {} diff --git a/server/src/repositories/database.repository.ts b/server/src/repositories/database.repository.ts index 4ff24eeaa4..b9a04bffc8 100644 --- a/server/src/repositories/database.repository.ts +++ b/server/src/repositories/database.repository.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import { InjectDataSource } from '@nestjs/typeorm'; import AsyncLock from 'async-lock'; import { vectorExt } from 'src/database.config'; @@ -11,8 +11,8 @@ import { VectorUpdateResult, extName, } from 'src/interfaces/database.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { Instrumentation } from 'src/utils/instrumentation'; -import { ImmichLogger } from 'src/utils/logger'; import { Version, VersionType } from 'src/utils/version'; import { isValidInteger } from 'src/validation'; import { DataSource, EntityManager, QueryRunner } from 'typeorm'; @@ -20,10 +20,14 @@ import { DataSource, EntityManager, QueryRunner } from 'typeorm'; @Instrumentation() @Injectable() export class DatabaseRepository implements IDatabaseRepository { - private logger = new ImmichLogger(DatabaseRepository.name); readonly asyncLock = new AsyncLock(); - constructor(@InjectDataSource() private dataSource: DataSource) {} + constructor( + @InjectDataSource() private dataSource: DataSource, + @Inject(ILoggerRepository) private logger: ILoggerRepository, + ) { + this.logger.setContext(DatabaseRepository.name); + } async getExtensionVersion(extension: DatabaseExtension): Promise { const res = await this.dataSource.query(`SELECT extversion FROM pg_extension WHERE extname = $1`, [extension]); diff --git a/server/src/repositories/event.repository.ts b/server/src/repositories/event.repository.ts index be1de76c2d..33dfbfadc5 100644 --- a/server/src/repositories/event.repository.ts +++ b/server/src/repositories/event.repository.ts @@ -1,3 +1,4 @@ +import { Inject, Injectable } from '@nestjs/common'; import { EventEmitter2 } from '@nestjs/event-emitter'; import { OnGatewayConnection, @@ -14,9 +15,9 @@ import { ServerEvent, ServerEventMap, } from 'src/interfaces/event.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { AuthService } from 'src/services/auth.service'; import { Instrumentation } from 'src/utils/instrumentation'; -import { ImmichLogger } from 'src/utils/logger'; @Instrumentation() @WebSocketGateway({ @@ -24,16 +25,18 @@ import { ImmichLogger } from 'src/utils/logger'; path: '/api/socket.io', transports: ['websocket'], }) +@Injectable() export class EventRepository implements OnGatewayConnection, OnGatewayDisconnect, OnGatewayInit, IEventRepository { - private logger = new ImmichLogger(EventRepository.name); - @WebSocketServer() private server?: Server; constructor( private authService: AuthService, private eventEmitter: EventEmitter2, - ) {} + @Inject(ILoggerRepository) private logger: ILoggerRepository, + ) { + this.logger.setContext(EventRepository.name); + } afterInit(server: Server) { this.logger.log('Initialized websocket server'); diff --git a/server/src/repositories/job.repository.ts b/server/src/repositories/job.repository.ts index a7c99f93cb..858798b88d 100644 --- a/server/src/repositories/job.repository.ts +++ b/server/src/repositories/job.repository.ts @@ -1,5 +1,5 @@ import { getQueueToken } from '@nestjs/bullmq'; -import { Injectable } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import { ModuleRef } from '@nestjs/core'; import { SchedulerRegistry } from '@nestjs/schedule'; import { Job, JobsOptions, Processor, Queue, Worker, WorkerOptions } from 'bullmq'; @@ -15,8 +15,8 @@ import { QueueName, QueueStatus, } from 'src/interfaces/job.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { Instrumentation } from 'src/utils/instrumentation'; -import { ImmichLogger } from 'src/utils/logger'; export const JOBS_TO_QUEUE: Record = { // misc @@ -83,12 +83,14 @@ export const JOBS_TO_QUEUE: Record = { @Injectable() export class JobRepository implements IJobRepository { private workers: Partial> = {}; - private logger = new ImmichLogger(JobRepository.name); constructor( private moduleReference: ModuleRef, private schedulerReqistry: SchedulerRegistry, - ) {} + @Inject(ILoggerRepository) private logger: ILoggerRepository, + ) { + this.logger.setContext(JobRepository.name); + } addHandler(queueName: QueueName, concurrency: number, handler: (item: JobItem) => Promise) { const workerHandler: Processor = async (job: Job) => handler(job as JobItem); diff --git a/server/src/repositories/logger.repository.ts b/server/src/repositories/logger.repository.ts index beedf96513..65ccd8ea47 100644 --- a/server/src/repositories/logger.repository.ts +++ b/server/src/repositories/logger.repository.ts @@ -1,10 +1,10 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, Scope } from '@nestjs/common'; import { ClsService } from 'nestjs-cls'; import { LogLevel } from 'src/entities/system-config.entity'; import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { ImmichLogger } from 'src/utils/logger'; -@Injectable() +@Injectable({ scope: Scope.TRANSIENT }) export class LoggerRepository extends ImmichLogger implements ILoggerRepository { constructor(private cls: ClsService) { super(LoggerRepository.name); diff --git a/server/src/repositories/media.repository.ts b/server/src/repositories/media.repository.ts index 52a538909f..3936ad7e42 100644 --- a/server/src/repositories/media.repository.ts +++ b/server/src/repositories/media.repository.ts @@ -1,9 +1,11 @@ +import { Inject, Injectable } from '@nestjs/common'; import ffmpeg, { FfprobeData } from 'fluent-ffmpeg'; import fs from 'node:fs/promises'; import { Writable } from 'node:stream'; import { promisify } from 'node:util'; import sharp from 'sharp'; import { Colorspace } from 'src/entities/system-config.entity'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { CropOptions, IMediaRepository, @@ -12,7 +14,6 @@ import { VideoInfo, } from 'src/interfaces/media.interface'; import { Instrumentation } from 'src/utils/instrumentation'; -import { ImmichLogger } from 'src/utils/logger'; import { handlePromiseError } from 'src/utils/misc'; const probe = promisify(ffmpeg.ffprobe); @@ -20,9 +21,11 @@ sharp.concurrency(0); sharp.cache({ files: 0 }); @Instrumentation() +@Injectable() export class MediaRepository implements IMediaRepository { - private logger = new ImmichLogger(MediaRepository.name); - + constructor(@Inject(ILoggerRepository) private logger: ILoggerRepository) { + this.logger.setContext(MediaRepository.name); + } crop(input: string | Buffer, options: CropOptions): Promise { return sharp(input, { failOn: 'none' }) .pipelineColorspace('rgb16') diff --git a/server/src/repositories/metadata.repository.ts b/server/src/repositories/metadata.repository.ts index 511023a8ea..8eeb0064ac 100644 --- a/server/src/repositories/metadata.repository.ts +++ b/server/src/repositories/metadata.repository.ts @@ -1,4 +1,4 @@ -import { Inject } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; import { DefaultReadTaskOptions, Tags, exiftool } from 'exiftool-vendored'; import geotz from 'geo-tz'; @@ -11,24 +11,26 @@ import { DummyValue, GenerateSql } from 'src/decorators'; import { ExifEntity } from 'src/entities/exif.entity'; import { GeodataPlacesEntity } from 'src/entities/geodata-places.entity'; import { SystemMetadataKey } from 'src/entities/system-metadata.entity'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { GeoPoint, IMetadataRepository, ImmichTags, ReverseGeocodeResult } from 'src/interfaces/metadata.interface'; import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { Instrumentation } from 'src/utils/instrumentation'; -import { ImmichLogger } from 'src/utils/logger'; import { DataSource, QueryRunner, Repository } from 'typeorm'; import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity.js'; @Instrumentation() +@Injectable() export class MetadataRepository implements IMetadataRepository { constructor( @InjectRepository(ExifEntity) private exifRepository: Repository, - @InjectRepository(GeodataPlacesEntity) private readonly geodataPlacesRepository: Repository, + @InjectRepository(GeodataPlacesEntity) private geodataPlacesRepository: Repository, @Inject(ISystemMetadataRepository) - private readonly systemMetadataRepository: ISystemMetadataRepository, + private systemMetadataRepository: ISystemMetadataRepository, @InjectDataSource() private dataSource: DataSource, - ) {} - - private logger = new ImmichLogger(MetadataRepository.name); + @Inject(ILoggerRepository) private logger: ILoggerRepository, + ) { + this.logger.setContext(MetadataRepository.name); + } async init(): Promise { this.logger.log('Initializing metadata repository'); diff --git a/server/src/repositories/metric.repository.ts b/server/src/repositories/metric.repository.ts index c6eb953acf..5948e92fa6 100644 --- a/server/src/repositories/metric.repository.ts +++ b/server/src/repositories/metric.repository.ts @@ -6,7 +6,7 @@ import { apiMetrics, hostMetrics, jobMetrics, repoMetrics } from 'src/utils/inst class MetricGroupRepository implements IMetricGroupRepository { private enabled = false; - constructor(private readonly metricService: MetricService) {} + constructor(private metricService: MetricService) {} addToCounter(name: string, value: number, options?: MetricOptions): void { if (this.enabled) { diff --git a/server/src/repositories/partner.repository.ts b/server/src/repositories/partner.repository.ts index 8465493b54..e0c8998dbf 100644 --- a/server/src/repositories/partner.repository.ts +++ b/server/src/repositories/partner.repository.ts @@ -8,7 +8,7 @@ import { DeepPartial, Repository } from 'typeorm'; @Instrumentation() @Injectable() export class PartnerRepository implements IPartnerRepository { - constructor(@InjectRepository(PartnerEntity) private readonly repository: Repository) {} + constructor(@InjectRepository(PartnerEntity) private repository: Repository) {} getAll(userId: string): Promise { return this.repository.find({ where: [{ sharedWithId: userId }, { sharedById: userId }] }); diff --git a/server/src/repositories/person.repository.ts b/server/src/repositories/person.repository.ts index 0acbafe699..7ffc6bf2b7 100644 --- a/server/src/repositories/person.repository.ts +++ b/server/src/repositories/person.repository.ts @@ -1,3 +1,4 @@ +import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import _ from 'lodash'; import { ChunkedArray, DummyValue, GenerateSql } from 'src/decorators'; @@ -19,6 +20,7 @@ import { Paginated, PaginationOptions, paginate } from 'src/utils/pagination'; import { FindManyOptions, FindOptionsRelations, FindOptionsSelect, In, Repository } from 'typeorm'; @Instrumentation() +@Injectable() export class PersonRepository implements IPersonRepository { constructor( @InjectRepository(AssetEntity) private assetRepository: Repository, diff --git a/server/src/repositories/search.repository.ts b/server/src/repositories/search.repository.ts index 4530d2295f..6ac49a3190 100644 --- a/server/src/repositories/search.repository.ts +++ b/server/src/repositories/search.repository.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { vectorExt } from 'src/database.config'; import { DummyValue, GenerateSql } from 'src/decorators'; @@ -8,6 +8,7 @@ import { GeodataPlacesEntity } from 'src/entities/geodata-places.entity'; import { SmartInfoEntity } from 'src/entities/smart-info.entity'; import { SmartSearchEntity } from 'src/entities/smart-search.entity'; import { DatabaseExtension } from 'src/interfaces/database.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { AssetSearchOptions, FaceEmbeddingSearch, @@ -18,7 +19,6 @@ import { } from 'src/interfaces/search.interface'; import { asVector, searchAssetBuilder } from 'src/utils/database'; import { Instrumentation } from 'src/utils/instrumentation'; -import { ImmichLogger } from 'src/utils/logger'; import { getCLIPModelInfo } from 'src/utils/misc'; import { Paginated, PaginationMode, PaginationResult, paginatedBuilder } from 'src/utils/pagination'; import { isValidInteger } from 'src/validation'; @@ -27,7 +27,6 @@ import { Repository, SelectQueryBuilder } from 'typeorm'; @Instrumentation() @Injectable() export class SearchRepository implements ISearchRepository { - private logger = new ImmichLogger(SearchRepository.name); private faceColumns: string[]; private assetsByCityQuery: string; @@ -36,8 +35,10 @@ export class SearchRepository implements ISearchRepository { @InjectRepository(AssetEntity) private assetRepository: Repository, @InjectRepository(AssetFaceEntity) private assetFaceRepository: Repository, @InjectRepository(SmartSearchEntity) private smartSearchRepository: Repository, - @InjectRepository(GeodataPlacesEntity) private readonly geodataPlacesRepository: Repository, + @InjectRepository(GeodataPlacesEntity) private geodataPlacesRepository: Repository, + @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { + this.logger.setContext(SearchRepository.name); this.faceColumns = this.assetFaceRepository.manager.connection .getMetadata(AssetFaceEntity) .ownColumns.map((column) => column.propertyName) diff --git a/server/src/repositories/storage.repository.spec.ts b/server/src/repositories/storage.repository.spec.ts index b92a26904f..44c81d76a6 100644 --- a/server/src/repositories/storage.repository.spec.ts +++ b/server/src/repositories/storage.repository.spec.ts @@ -1,6 +1,8 @@ import mockfs from 'mock-fs'; import { CrawlOptionsDto } from 'src/dtos/library.dto'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { StorageRepository } from 'src/repositories/storage.repository'; +import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; interface Test { test: string; @@ -181,9 +183,11 @@ const tests: Test[] = [ describe(StorageRepository.name, () => { let sut: StorageRepository; + let logger: ILoggerRepository; beforeEach(() => { - sut = new StorageRepository(); + logger = newLoggerRepositoryMock(); + sut = new StorageRepository(logger); }); afterEach(() => { diff --git a/server/src/repositories/storage.repository.ts b/server/src/repositories/storage.repository.ts index 8f0dfd3ff9..ae374ac812 100644 --- a/server/src/repositories/storage.repository.ts +++ b/server/src/repositories/storage.repository.ts @@ -1,3 +1,4 @@ +import { Inject, Injectable } from '@nestjs/common'; import archiver from 'archiver'; import chokidar, { WatchOptions } from 'chokidar'; import { glob, globStream } from 'fast-glob'; @@ -5,6 +6,7 @@ import { constants, createReadStream, existsSync, mkdirSync } from 'node:fs'; import fs from 'node:fs/promises'; import path from 'node:path'; import { CrawlOptionsDto } from 'src/dtos/library.dto'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { DiskUsage, IStorageRepository, @@ -13,12 +15,14 @@ import { WatchEvents, } from 'src/interfaces/storage.interface'; import { Instrumentation } from 'src/utils/instrumentation'; -import { ImmichLogger } from 'src/utils/logger'; import { mimeTypes } from 'src/utils/mime-types'; @Instrumentation() +@Injectable() export class StorageRepository implements IStorageRepository { - private logger = new ImmichLogger(StorageRepository.name); + constructor(@Inject(ILoggerRepository) private logger: ILoggerRepository) { + this.logger.setContext(StorageRepository.name); + } readdir(folder: string): Promise { return fs.readdir(folder); diff --git a/server/src/repositories/system-config.repository.ts b/server/src/repositories/system-config.repository.ts index baa3218b00..3d2dbecbc8 100644 --- a/server/src/repositories/system-config.repository.ts +++ b/server/src/repositories/system-config.repository.ts @@ -1,3 +1,4 @@ +import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { readFile } from 'node:fs/promises'; import { Chunked, DummyValue, GenerateSql } from 'src/decorators'; @@ -7,6 +8,7 @@ import { Instrumentation } from 'src/utils/instrumentation'; import { In, Repository } from 'typeorm'; @Instrumentation() +@Injectable() export class SystemConfigRepository implements ISystemConfigRepository { constructor( @InjectRepository(SystemConfigEntity) diff --git a/server/src/repositories/system-metadata.repository.ts b/server/src/repositories/system-metadata.repository.ts index 80936e46f6..91b887a176 100644 --- a/server/src/repositories/system-metadata.repository.ts +++ b/server/src/repositories/system-metadata.repository.ts @@ -1,3 +1,4 @@ +import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { SystemMetadata, SystemMetadataEntity } from 'src/entities/system-metadata.entity'; import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; @@ -5,6 +6,7 @@ import { Instrumentation } from 'src/utils/instrumentation'; import { Repository } from 'typeorm'; @Instrumentation() +@Injectable() export class SystemMetadataRepository implements ISystemMetadataRepository { constructor( @InjectRepository(SystemMetadataEntity) diff --git a/server/src/services/api.service.ts b/server/src/services/api.service.ts index 87107b23f4..fb9912da95 100644 --- a/server/src/services/api.service.ts +++ b/server/src/services/api.service.ts @@ -1,9 +1,10 @@ -import { Injectable } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import { Cron, CronExpression, Interval } from '@nestjs/schedule'; import { NextFunction, Request, Response } from 'express'; import { readFileSync } from 'node:fs'; import { join } from 'node:path'; import { ONE_HOUR, WEB_ROOT } from 'src/constants'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { AuthService } from 'src/services/auth.service'; import { DatabaseService } from 'src/services/database.service'; import { JobService } from 'src/services/job.service'; @@ -11,7 +12,6 @@ import { ServerInfoService } from 'src/services/server-info.service'; import { SharedLinkService } from 'src/services/shared-link.service'; import { StorageService } from 'src/services/storage.service'; import { SystemConfigService } from 'src/services/system-config.service'; -import { ImmichLogger } from 'src/utils/logger'; import { OpenGraphTags } from 'src/utils/misc'; const render = (index: string, meta: OpenGraphTags) => { @@ -36,8 +36,6 @@ const render = (index: string, meta: OpenGraphTags) => { @Injectable() export class ApiService { - private logger = new ImmichLogger(ApiService.name); - constructor( private authService: AuthService, private configService: SystemConfigService, @@ -46,7 +44,10 @@ export class ApiService { private sharedLinkService: SharedLinkService, private storageService: StorageService, private databaseService: DatabaseService, - ) {} + @Inject(ILoggerRepository) private logger: ILoggerRepository, + ) { + this.logger.setContext(ApiService.name); + } @Interval(ONE_HOUR.as('milliseconds')) async onVersionCheck() { diff --git a/server/src/services/asset-v1.service.spec.ts b/server/src/services/asset-v1.service.spec.ts index 991d5c03aa..bc088cb30b 100644 --- a/server/src/services/asset-v1.service.spec.ts +++ b/server/src/services/asset-v1.service.spec.ts @@ -6,6 +6,7 @@ import { IAssetRepositoryV1 } from 'src/interfaces/asset-v1.interface'; import { IAssetRepository } from 'src/interfaces/asset.interface'; import { IJobRepository, JobName } from 'src/interfaces/job.interface'; import { ILibraryRepository } from 'src/interfaces/library.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; import { IUserRepository } from 'src/interfaces/user.interface'; import { AssetServiceV1 } from 'src/services/asset-v1.service'; @@ -16,6 +17,7 @@ import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositorie import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock'; import { newJobRepositoryMock } from 'test/repositories/job.repository.mock'; import { newLibraryRepositoryMock } from 'test/repositories/library.repository.mock'; +import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock'; import { newUserRepositoryMock } from 'test/repositories/user.repository.mock'; import { QueryFailedError } from 'typeorm'; @@ -66,6 +68,7 @@ describe('AssetService', () => { let assetMock: Mocked; let jobMock: Mocked; let libraryMock: Mocked; + let loggerMock: Mocked; let storageMock: Mocked; let userMock: Mocked; @@ -85,10 +88,20 @@ describe('AssetService', () => { assetMock = newAssetRepositoryMock(); jobMock = newJobRepositoryMock(); libraryMock = newLibraryRepositoryMock(); + loggerMock = newLoggerRepositoryMock(); storageMock = newStorageRepositoryMock(); userMock = newUserRepositoryMock(); - sut = new AssetServiceV1(accessMock, assetRepositoryMockV1, assetMock, jobMock, libraryMock, storageMock, userMock); + sut = new AssetServiceV1( + accessMock, + assetRepositoryMockV1, + assetMock, + jobMock, + libraryMock, + storageMock, + userMock, + loggerMock, + ); assetRepositoryMockV1.get.mockImplementation((assetId) => Promise.resolve( diff --git a/server/src/services/asset-v1.service.ts b/server/src/services/asset-v1.service.ts index 97aa99d91d..61fe5bd80b 100644 --- a/server/src/services/asset-v1.service.ts +++ b/server/src/services/asset-v1.service.ts @@ -33,18 +33,17 @@ import { IAssetRepositoryV1 } from 'src/interfaces/asset-v1.interface'; import { IAssetRepository } from 'src/interfaces/asset.interface'; import { IJobRepository, JobName } from 'src/interfaces/job.interface'; import { ILibraryRepository } from 'src/interfaces/library.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; import { IUserRepository } from 'src/interfaces/user.interface'; import { UploadFile } from 'src/services/asset.service'; import { CacheControl, ImmichFileResponse, getLivePhotoMotionFilename } from 'src/utils/file'; -import { ImmichLogger } from 'src/utils/logger'; import { mimeTypes } from 'src/utils/mime-types'; import { QueryFailedError } from 'typeorm'; @Injectable() /** @deprecated */ export class AssetServiceV1 { - readonly logger = new ImmichLogger(AssetServiceV1.name); private access: AccessCore; constructor( @@ -55,8 +54,10 @@ export class AssetServiceV1 { @Inject(ILibraryRepository) private libraryRepository: ILibraryRepository, @Inject(IStorageRepository) private storageRepository: IStorageRepository, @Inject(IUserRepository) private userRepository: IUserRepository, + @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { this.access = AccessCore.create(accessRepository); + this.logger.setContext(AssetServiceV1.name); } public async uploadFile( diff --git a/server/src/services/asset.service.spec.ts b/server/src/services/asset.service.spec.ts index 74ab87414d..1516ef8961 100755 --- a/server/src/services/asset.service.spec.ts +++ b/server/src/services/asset.service.spec.ts @@ -6,6 +6,7 @@ import { IAssetStackRepository } from 'src/interfaces/asset-stack.interface'; import { AssetStats, IAssetRepository } from 'src/interfaces/asset.interface'; import { ClientEvent, IEventRepository } from 'src/interfaces/event.interface'; import { IJobRepository, JobName } from 'src/interfaces/job.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IPartnerRepository } from 'src/interfaces/partner.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; @@ -21,6 +22,7 @@ import { newAssetStackRepositoryMock } from 'test/repositories/asset-stack.repos import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock'; import { newEventRepositoryMock } from 'test/repositories/event.repository.mock'; import { newJobRepositoryMock } from 'test/repositories/job.repository.mock'; +import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; import { newPartnerRepositoryMock } from 'test/repositories/partner.repository.mock'; import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock'; import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock'; @@ -156,6 +158,7 @@ describe(AssetService.name, () => { let configMock: Mocked; let partnerMock: Mocked; let assetStackMock: Mocked; + let loggerMock: Mocked; it('should work', () => { expect(sut).toBeDefined(); @@ -177,6 +180,7 @@ describe(AssetService.name, () => { configMock = newSystemConfigRepositoryMock(); partnerMock = newPartnerRepositoryMock(); assetStackMock = newAssetStackRepositoryMock(); + loggerMock = newLoggerRepositoryMock(); sut = new AssetService( accessMock, @@ -188,6 +192,7 @@ describe(AssetService.name, () => { eventMock, partnerMock, assetStackMock, + loggerMock, ); mockGetById([assetStub.livePhotoStillAsset, assetStub.livePhotoMotionAsset]); diff --git a/server/src/services/asset.service.ts b/server/src/services/asset.service.ts index f2a67775f8..3dc1290623 100644 --- a/server/src/services/asset.service.ts +++ b/server/src/services/asset.service.ts @@ -40,11 +40,11 @@ import { JobName, JobStatus, } from 'src/interfaces/job.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IPartnerRepository } from 'src/interfaces/partner.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; import { IUserRepository } from 'src/interfaces/user.interface'; -import { ImmichLogger } from 'src/utils/logger'; import { mimeTypes } from 'src/utils/mime-types'; import { usePagination } from 'src/utils/pagination'; @@ -63,7 +63,6 @@ export interface UploadFile { } export class AssetService { - private logger = new ImmichLogger(AssetService.name); private access: AccessCore; private configCore: SystemConfigCore; @@ -77,9 +76,11 @@ export class AssetService { @Inject(IEventRepository) private eventRepository: IEventRepository, @Inject(IPartnerRepository) private partnerRepository: IPartnerRepository, @Inject(IAssetStackRepository) private assetStackRepository: IAssetStackRepository, + @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { + this.logger.setContext(AssetService.name); this.access = AccessCore.create(accessRepository); - this.configCore = SystemConfigCore.create(configRepository); + this.configCore = SystemConfigCore.create(configRepository, this.logger); } canUploadFile({ auth, fieldName, file }: UploadRequest): true { diff --git a/server/src/services/audit.service.spec.ts b/server/src/services/audit.service.spec.ts index e3110eeb8a..8557677f92 100644 --- a/server/src/services/audit.service.spec.ts +++ b/server/src/services/audit.service.spec.ts @@ -3,6 +3,7 @@ import { IAssetRepository } from 'src/interfaces/asset.interface'; import { IAuditRepository } from 'src/interfaces/audit.interface'; import { ICryptoRepository } from 'src/interfaces/crypto.interface'; import { JobStatus } from 'src/interfaces/job.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IPersonRepository } from 'src/interfaces/person.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; import { IUserRepository } from 'src/interfaces/user.interface'; @@ -13,6 +14,7 @@ import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositorie import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock'; import { newAuditRepositoryMock } from 'test/repositories/audit.repository.mock'; import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.mock'; +import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; import { newPersonRepositoryMock } from 'test/repositories/person.repository.mock'; import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock'; import { newUserRepositoryMock } from 'test/repositories/user.repository.mock'; @@ -27,6 +29,7 @@ describe(AuditService.name, () => { let personMock: Mocked; let storageMock: Mocked; let userMock: Mocked; + let loggerMock: Mocked; beforeEach(() => { accessMock = newAccessRepositoryMock(); @@ -36,7 +39,8 @@ describe(AuditService.name, () => { personMock = newPersonRepositoryMock(); storageMock = newStorageRepositoryMock(); userMock = newUserRepositoryMock(); - sut = new AuditService(accessMock, assetMock, cryptoMock, personMock, auditMock, storageMock, userMock); + loggerMock = newLoggerRepositoryMock(); + sut = new AuditService(accessMock, assetMock, cryptoMock, personMock, auditMock, storageMock, userMock, loggerMock); }); it('should work', () => { diff --git a/server/src/services/audit.service.ts b/server/src/services/audit.service.ts index b15ee9240a..bfff09c0bc 100644 --- a/server/src/services/audit.service.ts +++ b/server/src/services/audit.service.ts @@ -20,16 +20,15 @@ import { IAssetRepository } from 'src/interfaces/asset.interface'; import { IAuditRepository } from 'src/interfaces/audit.interface'; import { ICryptoRepository } from 'src/interfaces/crypto.interface'; import { JOBS_ASSET_PAGINATION_SIZE, JobStatus } from 'src/interfaces/job.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IPersonRepository } from 'src/interfaces/person.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; import { IUserRepository } from 'src/interfaces/user.interface'; -import { ImmichLogger } from 'src/utils/logger'; import { usePagination } from 'src/utils/pagination'; @Injectable() export class AuditService { private access: AccessCore; - private logger = new ImmichLogger(AuditService.name); constructor( @Inject(IAccessRepository) accessRepository: IAccessRepository, @@ -39,8 +38,10 @@ export class AuditService { @Inject(IAuditRepository) private repository: IAuditRepository, @Inject(IStorageRepository) private storageRepository: IStorageRepository, @Inject(IUserRepository) private userRepository: IUserRepository, + @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { this.access = AccessCore.create(accessRepository); + this.logger.setContext(AuditService.name); } async handleCleanup(): Promise { diff --git a/server/src/services/auth.service.ts b/server/src/services/auth.service.ts index 41b827b1ce..7bebca5989 100644 --- a/server/src/services/auth.service.ts +++ b/server/src/services/auth.service.ts @@ -89,10 +89,10 @@ export class AuthService { @Inject(ISharedLinkRepository) private sharedLinkRepository: ISharedLinkRepository, @Inject(IKeyRepository) private keyRepository: IKeyRepository, ) { - this.access = AccessCore.create(accessRepository); - this.configCore = SystemConfigCore.create(configRepository); - this.userCore = UserCore.create(cryptoRepository, libraryRepository, userRepository); this.logger.setContext(AuthService.name); + this.access = AccessCore.create(accessRepository); + this.configCore = SystemConfigCore.create(configRepository, logger); + this.userCore = UserCore.create(cryptoRepository, libraryRepository, userRepository); custom.setHttpOptionsDefaults({ timeout: 30_000 }); } diff --git a/server/src/services/database.service.spec.ts b/server/src/services/database.service.spec.ts index 482535ae6c..28ed7d7df2 100644 --- a/server/src/services/database.service.spec.ts +++ b/server/src/services/database.service.spec.ts @@ -1,18 +1,20 @@ import { DatabaseExtension, IDatabaseRepository, VectorIndex } from 'src/interfaces/database.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { DatabaseService } from 'src/services/database.service'; -import { ImmichLogger } from 'src/utils/logger'; import { Version, VersionType } from 'src/utils/version'; import { newDatabaseRepositoryMock } from 'test/repositories/database.repository.mock'; -import { MockInstance, Mocked, vitest } from 'vitest'; +import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; +import { Mocked } from 'vitest'; describe(DatabaseService.name, () => { let sut: DatabaseService; let databaseMock: Mocked; + let loggerMock: Mocked; beforeEach(() => { databaseMock = newDatabaseRepositoryMock(); - - sut = new DatabaseService(databaseMock); + loggerMock = newLoggerRepositoryMock(); + sut = new DatabaseService(databaseMock, loggerMock); }); it('should work', () => { @@ -23,18 +25,11 @@ describe(DatabaseService.name, () => { [{ vectorExt: DatabaseExtension.VECTORS, extName: 'pgvecto.rs', minVersion: new Version(0, 1, 1) }], [{ vectorExt: DatabaseExtension.VECTOR, extName: 'pgvector', minVersion: new Version(0, 5, 0) }], ] as const)('init', ({ vectorExt, extName, minVersion }) => { - let fatalLog: MockInstance; - let errorLog: MockInstance; - let warnLog: MockInstance; - beforeEach(() => { - fatalLog = vitest.spyOn(ImmichLogger.prototype, 'fatal'); - errorLog = vitest.spyOn(ImmichLogger.prototype, 'error'); - warnLog = vitest.spyOn(ImmichLogger.prototype, 'warn'); databaseMock.getPreferredVectorExtension.mockReturnValue(vectorExt); databaseMock.getExtensionVersion.mockResolvedValue(minVersion); - sut = new DatabaseService(databaseMock); + sut = new DatabaseService(databaseMock, loggerMock); sut.minVectorVersion = minVersion; sut.minVectorsVersion = minVersion; @@ -42,11 +37,6 @@ describe(DatabaseService.name, () => { sut.vectorsVersionPin = VersionType.MINOR; }); - afterEach(() => { - fatalLog.mockRestore(); - warnLog.mockRestore(); - }); - it(`should resolve successfully if minimum supported PostgreSQL and ${extName} version are installed`, async () => { databaseMock.getPostgresVersion.mockResolvedValueOnce(new Version(14, 0, 0)); @@ -57,7 +47,7 @@ describe(DatabaseService.name, () => { expect(databaseMock.createExtension).toHaveBeenCalledTimes(1); expect(databaseMock.getExtensionVersion).toHaveBeenCalled(); expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1); - expect(fatalLog).not.toHaveBeenCalled(); + expect(loggerMock.fatal).not.toHaveBeenCalled(); }); it('should throw an error if PostgreSQL version is below minimum supported version', async () => { @@ -74,7 +64,7 @@ describe(DatabaseService.name, () => { expect(databaseMock.createExtension).toHaveBeenCalledWith(vectorExt); expect(databaseMock.createExtension).toHaveBeenCalledTimes(1); expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1); - expect(fatalLog).not.toHaveBeenCalled(); + expect(loggerMock.fatal).not.toHaveBeenCalled(); }); it(`should throw an error if ${extName} version is not installed even after createVectorExtension`, async () => { @@ -134,7 +124,7 @@ describe(DatabaseService.name, () => { await expect(sut.init()).rejects.toThrow('Failed to create extension'); - expect(fatalLog).toHaveBeenCalledTimes(1); + expect(loggerMock.fatal).toHaveBeenCalledTimes(1); expect(databaseMock.createExtension).toHaveBeenCalledTimes(1); expect(databaseMock.runMigrations).not.toHaveBeenCalled(); }); @@ -148,7 +138,7 @@ describe(DatabaseService.name, () => { expect(databaseMock.updateVectorExtension).toHaveBeenCalledWith(vectorExt, version); expect(databaseMock.updateVectorExtension).toHaveBeenCalledTimes(1); expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1); - expect(fatalLog).not.toHaveBeenCalled(); + expect(loggerMock.fatal).not.toHaveBeenCalled(); }); it(`should not update ${extName} if a newer version is higher than the maximum`, async () => { @@ -159,7 +149,7 @@ describe(DatabaseService.name, () => { expect(databaseMock.updateVectorExtension).not.toHaveBeenCalled(); expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1); - expect(fatalLog).not.toHaveBeenCalled(); + expect(loggerMock.fatal).not.toHaveBeenCalled(); }); it(`should warn if attempted to update ${extName} and failed`, async () => { @@ -169,10 +159,10 @@ describe(DatabaseService.name, () => { await expect(sut.init()).resolves.toBeUndefined(); - expect(warnLog).toHaveBeenCalledTimes(1); - expect(warnLog.mock.calls[0][0]).toContain(extName); - expect(errorLog).toHaveBeenCalledTimes(1); - expect(fatalLog).not.toHaveBeenCalled(); + expect(loggerMock.warn).toHaveBeenCalledTimes(1); + expect(loggerMock.warn.mock.calls[0][0]).toContain(extName); + expect(loggerMock.error).toHaveBeenCalledTimes(1); + expect(loggerMock.fatal).not.toHaveBeenCalled(); expect(databaseMock.updateVectorExtension).toHaveBeenCalledWith(vectorExt, version); expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1); }); @@ -184,11 +174,11 @@ describe(DatabaseService.name, () => { await expect(sut.init()).resolves.toBeUndefined(); - expect(warnLog).toHaveBeenCalledTimes(1); - expect(warnLog.mock.calls[0][0]).toContain(extName); + expect(loggerMock.warn).toHaveBeenCalledTimes(1); + expect(loggerMock.warn.mock.calls[0][0]).toContain(extName); expect(databaseMock.updateVectorExtension).toHaveBeenCalledWith(vectorExt, version); expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1); - expect(fatalLog).not.toHaveBeenCalled(); + expect(loggerMock.fatal).not.toHaveBeenCalled(); }); it.each([{ index: VectorIndex.CLIP }, { index: VectorIndex.FACE }])( @@ -203,7 +193,7 @@ describe(DatabaseService.name, () => { expect(databaseMock.reindex).toHaveBeenCalledWith(index); expect(databaseMock.reindex).toHaveBeenCalledTimes(1); expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1); - expect(fatalLog).not.toHaveBeenCalled(); + expect(loggerMock.fatal).not.toHaveBeenCalled(); }, ); @@ -217,7 +207,7 @@ describe(DatabaseService.name, () => { expect(databaseMock.shouldReindex).toHaveBeenCalledTimes(2); expect(databaseMock.reindex).not.toHaveBeenCalled(); expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1); - expect(fatalLog).not.toHaveBeenCalled(); + expect(loggerMock.fatal).not.toHaveBeenCalled(); }, ); }); diff --git a/server/src/services/database.service.ts b/server/src/services/database.service.ts index a333c0053a..8da48eb152 100644 --- a/server/src/services/database.service.ts +++ b/server/src/services/database.service.ts @@ -7,12 +7,11 @@ import { VectorIndex, extName, } from 'src/interfaces/database.interface'; -import { ImmichLogger } from 'src/utils/logger'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { Version, VersionType } from 'src/utils/version'; @Injectable() export class DatabaseService { - private logger = new ImmichLogger(DatabaseService.name); private vectorExt: VectorExtension; minPostgresVersion = 14; minVectorsVersion = new Version(0, 2, 0); @@ -20,7 +19,11 @@ export class DatabaseService { minVectorVersion = new Version(0, 5, 0); vectorVersionPin = VersionType.MAJOR; - constructor(@Inject(IDatabaseRepository) private databaseRepository: IDatabaseRepository) { + constructor( + @Inject(IDatabaseRepository) private databaseRepository: IDatabaseRepository, + @Inject(ILoggerRepository) private logger: ILoggerRepository, + ) { + this.logger.setContext(DatabaseService.name); this.vectorExt = this.databaseRepository.getPreferredVectorExtension(); } diff --git a/server/src/services/job.service.spec.ts b/server/src/services/job.service.spec.ts index 5f5c02e65d..ce7d2c00e4 100644 --- a/server/src/services/job.service.spec.ts +++ b/server/src/services/job.service.spec.ts @@ -12,6 +12,7 @@ import { JobStatus, QueueName, } from 'src/interfaces/job.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IMetricRepository } from 'src/interfaces/metric.interface'; import { IPersonRepository } from 'src/interfaces/person.interface'; import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; @@ -20,6 +21,7 @@ import { assetStub } from 'test/fixtures/asset.stub'; import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock'; import { newEventRepositoryMock } from 'test/repositories/event.repository.mock'; import { newJobRepositoryMock } from 'test/repositories/job.repository.mock'; +import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; import { newMetricRepositoryMock } from 'test/repositories/metric.repository.mock'; import { newPersonRepositoryMock } from 'test/repositories/person.repository.mock'; import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock'; @@ -41,6 +43,7 @@ describe(JobService.name, () => { let jobMock: Mocked; let personMock: Mocked; let metricMock: Mocked; + let loggerMock: Mocked; beforeEach(() => { assetMock = newAssetRepositoryMock(); @@ -49,7 +52,8 @@ describe(JobService.name, () => { jobMock = newJobRepositoryMock(); personMock = newPersonRepositoryMock(); metricMock = newMetricRepositoryMock(); - sut = new JobService(assetMock, eventMock, jobMock, configMock, personMock, metricMock); + loggerMock = newLoggerRepositoryMock(); + sut = new JobService(assetMock, eventMock, jobMock, configMock, personMock, metricMock, loggerMock); }); it('should work', () => { @@ -235,7 +239,7 @@ describe(JobService.name, () => { it('should subscribe to config changes', async () => { await sut.init(makeMockHandlers(JobStatus.FAILED)); - SystemConfigCore.create(newSystemConfigRepositoryMock(false)).config$.next({ + SystemConfigCore.create(newSystemConfigRepositoryMock(false), newLoggerRepositoryMock()).config$.next({ job: { [QueueName.BACKGROUND_TASK]: { concurrency: 10 }, [QueueName.SMART_SEARCH]: { concurrency: 10 }, diff --git a/server/src/services/job.service.ts b/server/src/services/job.service.ts index 3f9cd8a221..13d367994b 100644 --- a/server/src/services/job.service.ts +++ b/server/src/services/job.service.ts @@ -17,14 +17,13 @@ import { QueueCleanType, QueueName, } from 'src/interfaces/job.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IMetricRepository } from 'src/interfaces/metric.interface'; import { IPersonRepository } from 'src/interfaces/person.interface'; import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; -import { ImmichLogger } from 'src/utils/logger'; @Injectable() export class JobService { - private logger = new ImmichLogger(JobService.name); private configCore: SystemConfigCore; constructor( @@ -34,8 +33,10 @@ export class JobService { @Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository, @Inject(IPersonRepository) private personRepository: IPersonRepository, @Inject(IMetricRepository) private metricRepository: IMetricRepository, + @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { - this.configCore = SystemConfigCore.create(configRepository); + this.logger.setContext(JobService.name); + this.configCore = SystemConfigCore.create(configRepository, logger); } async handleCommand(queueName: QueueName, dto: JobCommandDto): Promise { diff --git a/server/src/services/library.service.spec.ts b/server/src/services/library.service.spec.ts index d363dab1f4..2122b03208 100644 --- a/server/src/services/library.service.spec.ts +++ b/server/src/services/library.service.spec.ts @@ -11,6 +11,7 @@ import { ICryptoRepository } from 'src/interfaces/crypto.interface'; import { IDatabaseRepository } from 'src/interfaces/database.interface'; import { IJobRepository, ILibraryFileJob, ILibraryRefreshJob, JobName, JobStatus } from 'src/interfaces/job.interface'; import { ILibraryRepository } from 'src/interfaces/library.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; import { LibraryService } from 'src/services/library.service'; @@ -24,6 +25,7 @@ import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.moc import { newDatabaseRepositoryMock } from 'test/repositories/database.repository.mock'; import { newJobRepositoryMock } from 'test/repositories/job.repository.mock'; import { newLibraryRepositoryMock } from 'test/repositories/library.repository.mock'; +import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; import { makeMockWatcher, newStorageRepositoryMock } from 'test/repositories/storage.repository.mock'; import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock'; import { Mocked, vitest } from 'vitest'; @@ -38,6 +40,7 @@ describe(LibraryService.name, () => { let libraryMock: Mocked; let storageMock: Mocked; let databaseMock: Mocked; + let loggerMock: Mocked; beforeEach(() => { configMock = newSystemConfigRepositoryMock(); @@ -47,8 +50,18 @@ describe(LibraryService.name, () => { cryptoMock = newCryptoRepositoryMock(); storageMock = newStorageRepositoryMock(); databaseMock = newDatabaseRepositoryMock(); + loggerMock = newLoggerRepositoryMock(); - sut = new LibraryService(assetMock, configMock, cryptoMock, jobMock, libraryMock, storageMock, databaseMock); + sut = new LibraryService( + assetMock, + configMock, + cryptoMock, + jobMock, + libraryMock, + storageMock, + databaseMock, + loggerMock, + ); databaseMock.tryLock.mockResolvedValue(true); }); @@ -68,7 +81,7 @@ describe(LibraryService.name, () => { expect(configMock.load).toHaveBeenCalled(); expect(jobMock.addCronJob).toHaveBeenCalled(); - SystemConfigCore.create(newSystemConfigRepositoryMock(false)).config$.next({ + SystemConfigCore.create(newSystemConfigRepositoryMock(false), newLoggerRepositoryMock()).config$.next({ library: { scan: { enabled: true, diff --git a/server/src/services/library.service.ts b/server/src/services/library.service.ts index 848c40f78e..00909e9837 100644 --- a/server/src/services/library.service.ts +++ b/server/src/services/library.service.ts @@ -36,9 +36,9 @@ import { JobStatus, } from 'src/interfaces/job.interface'; import { ILibraryRepository } from 'src/interfaces/library.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; -import { ImmichLogger } from 'src/utils/logger'; import { mimeTypes } from 'src/utils/mime-types'; import { handlePromiseError } from 'src/utils/misc'; import { usePagination } from 'src/utils/pagination'; @@ -48,7 +48,6 @@ const LIBRARY_SCAN_BATCH_SIZE = 5000; @Injectable() export class LibraryService { - readonly logger = new ImmichLogger(LibraryService.name); private configCore: SystemConfigCore; private watchLibraries = false; private watchLock = false; @@ -62,8 +61,10 @@ export class LibraryService { @Inject(ILibraryRepository) private repository: ILibraryRepository, @Inject(IStorageRepository) private storageRepository: IStorageRepository, @Inject(IDatabaseRepository) private databaseRepository: IDatabaseRepository, + @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { - this.configCore = SystemConfigCore.create(configRepository); + this.logger.setContext(LibraryService.name); + this.configCore = SystemConfigCore.create(configRepository, this.logger); } async init() { diff --git a/server/src/services/media.service.spec.ts b/server/src/services/media.service.spec.ts index c9f383771f..1b1adcd573 100644 --- a/server/src/services/media.service.spec.ts +++ b/server/src/services/media.service.spec.ts @@ -14,6 +14,7 @@ import { import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface'; import { ICryptoRepository } from 'src/interfaces/crypto.interface'; import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IMediaRepository } from 'src/interfaces/media.interface'; import { IMoveRepository } from 'src/interfaces/move.interface'; import { IPersonRepository } from 'src/interfaces/person.interface'; @@ -27,6 +28,7 @@ import { personStub } from 'test/fixtures/person.stub'; import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock'; import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.mock'; import { newJobRepositoryMock } from 'test/repositories/job.repository.mock'; +import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; import { newMediaRepositoryMock } from 'test/repositories/media.repository.mock'; import { newMoveRepositoryMock } from 'test/repositories/move.repository.mock'; import { newPersonRepositoryMock } from 'test/repositories/person.repository.mock'; @@ -44,6 +46,7 @@ describe(MediaService.name, () => { let personMock: Mocked; let storageMock: Mocked; let cryptoMock: Mocked; + let loggerMock: Mocked; beforeEach(() => { assetMock = newAssetRepositoryMock(); @@ -54,8 +57,19 @@ describe(MediaService.name, () => { personMock = newPersonRepositoryMock(); storageMock = newStorageRepositoryMock(); cryptoMock = newCryptoRepositoryMock(); + loggerMock = newLoggerRepositoryMock(); - sut = new MediaService(assetMock, personMock, jobMock, mediaMock, storageMock, configMock, moveMock, cryptoMock); + sut = new MediaService( + assetMock, + personMock, + jobMock, + mediaMock, + storageMock, + configMock, + moveMock, + cryptoMock, + loggerMock, + ); }); it('should be defined', () => { diff --git a/server/src/services/media.service.ts b/server/src/services/media.service.ts index 3c86c72bd7..47fa31abcc 100644 --- a/server/src/services/media.service.ts +++ b/server/src/services/media.service.ts @@ -25,12 +25,12 @@ import { JobStatus, QueueName, } from 'src/interfaces/job.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { AudioStreamInfo, IMediaRepository, VideoCodecHWConfig, VideoStreamInfo } from 'src/interfaces/media.interface'; import { IMoveRepository } from 'src/interfaces/move.interface'; import { IPersonRepository } from 'src/interfaces/person.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; -import { ImmichLogger } from 'src/utils/logger'; import { AV1Config, H264Config, @@ -46,7 +46,6 @@ import { usePagination } from 'src/utils/pagination'; @Injectable() export class MediaService { - private logger = new ImmichLogger(MediaService.name); private configCore: SystemConfigCore; private storageCore: StorageCore; private hasOpenCL?: boolean = undefined; @@ -60,15 +59,18 @@ export class MediaService { @Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository, @Inject(IMoveRepository) moveRepository: IMoveRepository, @Inject(ICryptoRepository) cryptoRepository: ICryptoRepository, + @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { - this.configCore = SystemConfigCore.create(configRepository); + this.logger.setContext(MediaService.name); + this.configCore = SystemConfigCore.create(configRepository, this.logger); this.storageCore = StorageCore.create( assetRepository, + cryptoRepository, moveRepository, personRepository, - cryptoRepository, - configRepository, storageRepository, + configRepository, + this.logger, ); } diff --git a/server/src/services/metadata.service.spec.ts b/server/src/services/metadata.service.spec.ts index 12a4048888..f1f00bc914 100644 --- a/server/src/services/metadata.service.spec.ts +++ b/server/src/services/metadata.service.spec.ts @@ -11,6 +11,7 @@ import { ICryptoRepository } from 'src/interfaces/crypto.interface'; import { IDatabaseRepository } from 'src/interfaces/database.interface'; import { ClientEvent, IEventRepository } from 'src/interfaces/event.interface'; import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IMediaRepository } from 'src/interfaces/media.interface'; import { IMetadataRepository, ImmichTags } from 'src/interfaces/metadata.interface'; import { IMoveRepository } from 'src/interfaces/move.interface'; @@ -27,6 +28,7 @@ import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.moc import { newDatabaseRepositoryMock } from 'test/repositories/database.repository.mock'; import { newEventRepositoryMock } from 'test/repositories/event.repository.mock'; import { newJobRepositoryMock } from 'test/repositories/job.repository.mock'; +import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; import { newMediaRepositoryMock } from 'test/repositories/media.repository.mock'; import { newMetadataRepositoryMock } from 'test/repositories/metadata.repository.mock'; import { newMoveRepositoryMock } from 'test/repositories/move.repository.mock'; @@ -48,6 +50,7 @@ describe(MetadataService.name, () => { let storageMock: Mocked; let eventMock: Mocked; let databaseMock: Mocked; + let loggerMock: Mocked; let sut: MetadataService; beforeEach(() => { @@ -63,6 +66,7 @@ describe(MetadataService.name, () => { storageMock = newStorageRepositoryMock(); mediaMock = newMediaRepositoryMock(); databaseMock = newDatabaseRepositoryMock(); + loggerMock = newLoggerRepositoryMock(); sut = new MetadataService( albumMock, @@ -77,6 +81,7 @@ describe(MetadataService.name, () => { personMock, storageMock, configMock, + loggerMock, ); }); diff --git a/server/src/services/metadata.service.ts b/server/src/services/metadata.service.ts index 379e034884..c204397e66 100644 --- a/server/src/services/metadata.service.ts +++ b/server/src/services/metadata.service.ts @@ -25,13 +25,13 @@ import { JobStatus, QueueName, } from 'src/interfaces/job.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IMediaRepository } from 'src/interfaces/media.interface'; import { IMetadataRepository, ImmichTags } from 'src/interfaces/metadata.interface'; import { IMoveRepository } from 'src/interfaces/move.interface'; import { IPersonRepository } from 'src/interfaces/person.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; -import { ImmichLogger } from 'src/utils/logger'; import { handlePromiseError } from 'src/utils/misc'; import { usePagination } from 'src/utils/pagination'; @@ -97,7 +97,6 @@ const validate = (value: T): NonNullable | null => { @Injectable() export class MetadataService { - private logger = new ImmichLogger(MetadataService.name); private storageCore: StorageCore; private configCore: SystemConfigCore; private subscription: Subscription | null = null; @@ -115,15 +114,18 @@ export class MetadataService { @Inject(IPersonRepository) personRepository: IPersonRepository, @Inject(IStorageRepository) private storageRepository: IStorageRepository, @Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository, + @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { - this.configCore = SystemConfigCore.create(configRepository); + this.logger.setContext(MetadataService.name); + this.configCore = SystemConfigCore.create(configRepository, this.logger); this.storageCore = StorageCore.create( assetRepository, + cryptoRepository, moveRepository, personRepository, - cryptoRepository, - configRepository, storageRepository, + configRepository, + this.logger, ); } diff --git a/server/src/services/person.service.spec.ts b/server/src/services/person.service.spec.ts index 7f8a58c20e..a9d96bbcea 100644 --- a/server/src/services/person.service.spec.ts +++ b/server/src/services/person.service.spec.ts @@ -6,6 +6,7 @@ import { Colorspace, SystemConfigKey } from 'src/entities/system-config.entity'; import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface'; import { ICryptoRepository } from 'src/interfaces/crypto.interface'; import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface'; import { IMediaRepository } from 'src/interfaces/media.interface'; import { IMoveRepository } from 'src/interfaces/move.interface'; @@ -23,6 +24,7 @@ import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositorie import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock'; import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.mock'; import { newJobRepositoryMock } from 'test/repositories/job.repository.mock'; +import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; import { newMachineLearningRepositoryMock } from 'test/repositories/machine-learning.repository.mock'; import { newMediaRepositoryMock } from 'test/repositories/media.repository.mock'; import { newMoveRepositoryMock } from 'test/repositories/move.repository.mock'; @@ -72,6 +74,7 @@ describe(PersonService.name, () => { let storageMock: Mocked; let searchMock: Mocked; let cryptoMock: Mocked; + let loggerMock: Mocked; let sut: PersonService; beforeEach(() => { @@ -86,6 +89,7 @@ describe(PersonService.name, () => { storageMock = newStorageRepositoryMock(); searchMock = newSearchRepositoryMock(); cryptoMock = newCryptoRepositoryMock(); + loggerMock = newLoggerRepositoryMock(); sut = new PersonService( accessMock, assetMock, @@ -98,6 +102,7 @@ describe(PersonService.name, () => { jobMock, searchMock, cryptoMock, + loggerMock, ); mediaMock.crop.mockResolvedValue(croppedFace); diff --git a/server/src/services/person.service.ts b/server/src/services/person.service.ts index d2bc81b0ea..77b7e552cc 100644 --- a/server/src/services/person.service.ts +++ b/server/src/services/person.service.ts @@ -38,6 +38,7 @@ import { JobStatus, QueueName, } from 'src/interfaces/job.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface'; import { CropOptions, IMediaRepository } from 'src/interfaces/media.interface'; import { IMoveRepository } from 'src/interfaces/move.interface'; @@ -46,7 +47,6 @@ import { ISearchRepository } from 'src/interfaces/search.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; import { CacheControl, ImmichFileResponse } from 'src/utils/file'; -import { ImmichLogger } from 'src/utils/logger'; import { mimeTypes } from 'src/utils/mime-types'; import { usePagination } from 'src/utils/pagination'; import { IsNull } from 'typeorm'; @@ -56,7 +56,6 @@ export class PersonService { private access: AccessCore; private configCore: SystemConfigCore; private storageCore: StorageCore; - readonly logger = new ImmichLogger(PersonService.name); constructor( @Inject(IAccessRepository) accessRepository: IAccessRepository, @@ -70,16 +69,19 @@ export class PersonService { @Inject(IJobRepository) private jobRepository: IJobRepository, @Inject(ISearchRepository) private smartInfoRepository: ISearchRepository, @Inject(ICryptoRepository) cryptoRepository: ICryptoRepository, + @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { this.access = AccessCore.create(accessRepository); - this.configCore = SystemConfigCore.create(configRepository); + this.logger.setContext(PersonService.name); + this.configCore = SystemConfigCore.create(configRepository, this.logger); this.storageCore = StorageCore.create( assetRepository, + cryptoRepository, moveRepository, repository, - cryptoRepository, - configRepository, storageRepository, + configRepository, + this.logger, ); } diff --git a/server/src/services/search.service.spec.ts b/server/src/services/search.service.spec.ts index 24af064382..a81ea87973 100644 --- a/server/src/services/search.service.spec.ts +++ b/server/src/services/search.service.spec.ts @@ -2,6 +2,7 @@ import { mapAsset } from 'src/dtos/asset-response.dto'; import { SearchDto } from 'src/dtos/search.dto'; import { SystemConfigKey } from 'src/entities/system-config.entity'; import { IAssetRepository } from 'src/interfaces/asset.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface'; import { IMetadataRepository } from 'src/interfaces/metadata.interface'; import { IPartnerRepository } from 'src/interfaces/partner.interface'; @@ -13,6 +14,7 @@ import { assetStub } from 'test/fixtures/asset.stub'; import { authStub } from 'test/fixtures/auth.stub'; import { personStub } from 'test/fixtures/person.stub'; import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock'; +import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; import { newMachineLearningRepositoryMock } from 'test/repositories/machine-learning.repository.mock'; import { newMetadataRepositoryMock } from 'test/repositories/metadata.repository.mock'; import { newPartnerRepositoryMock } from 'test/repositories/partner.repository.mock'; @@ -32,6 +34,7 @@ describe(SearchService.name, () => { let searchMock: Mocked; let partnerMock: Mocked; let metadataMock: Mocked; + let loggerMock: Mocked; beforeEach(() => { assetMock = newAssetRepositoryMock(); @@ -41,8 +44,18 @@ describe(SearchService.name, () => { searchMock = newSearchRepositoryMock(); partnerMock = newPartnerRepositoryMock(); metadataMock = newMetadataRepositoryMock(); + loggerMock = newLoggerRepositoryMock(); - sut = new SearchService(configMock, machineMock, personMock, searchMock, assetMock, partnerMock, metadataMock); + sut = new SearchService( + configMock, + machineMock, + personMock, + searchMock, + assetMock, + partnerMock, + metadataMock, + loggerMock, + ); }); it('should work', () => { diff --git a/server/src/services/search.service.ts b/server/src/services/search.service.ts index 9422dac86b..b8e9f13fa6 100644 --- a/server/src/services/search.service.ts +++ b/server/src/services/search.service.ts @@ -18,6 +18,7 @@ import { import { AssetOrder } from 'src/entities/album.entity'; import { AssetEntity } from 'src/entities/asset.entity'; import { IAssetRepository } from 'src/interfaces/asset.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface'; import { IMetadataRepository } from 'src/interfaces/metadata.interface'; import { IPartnerRepository } from 'src/interfaces/partner.interface'; @@ -37,8 +38,10 @@ export class SearchService { @Inject(IAssetRepository) private assetRepository: IAssetRepository, @Inject(IPartnerRepository) private partnerRepository: IPartnerRepository, @Inject(IMetadataRepository) private metadataRepository: IMetadataRepository, + @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { - this.configCore = SystemConfigCore.create(configRepository); + this.logger.setContext(SearchService.name); + this.configCore = SystemConfigCore.create(configRepository, logger); } async searchPerson(auth: AuthDto, dto: SearchPeopleDto): Promise { diff --git a/server/src/services/server-info.service.spec.ts b/server/src/services/server-info.service.spec.ts index 9848c948db..836909b74f 100644 --- a/server/src/services/server-info.service.spec.ts +++ b/server/src/services/server-info.service.spec.ts @@ -1,6 +1,7 @@ import { serverVersion } from 'src/constants'; import { SystemMetadataKey } from 'src/entities/system-metadata.entity'; import { IEventRepository } from 'src/interfaces/event.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IServerInfoRepository } from 'src/interfaces/server-info.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; @@ -8,6 +9,7 @@ import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interf import { IUserRepository } from 'src/interfaces/user.interface'; import { ServerInfoService } from 'src/services/server-info.service'; import { newEventRepositoryMock } from 'test/repositories/event.repository.mock'; +import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock'; import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock'; import { newServerInfoRepositoryMock } from 'test/repositories/system-info.repository.mock'; @@ -23,6 +25,7 @@ describe(ServerInfoService.name, () => { let storageMock: Mocked; let userMock: Mocked; let systemMetadataMock: Mocked; + let loggerMock: Mocked; beforeEach(() => { configMock = newSystemConfigRepositoryMock(); @@ -31,8 +34,17 @@ describe(ServerInfoService.name, () => { storageMock = newStorageRepositoryMock(); userMock = newUserRepositoryMock(); systemMetadataMock = newSystemMetadataRepositoryMock(); + loggerMock = newLoggerRepositoryMock(); - sut = new ServerInfoService(eventMock, configMock, userMock, serverInfoMock, storageMock, systemMetadataMock); + sut = new ServerInfoService( + eventMock, + configMock, + userMock, + serverInfoMock, + storageMock, + systemMetadataMock, + loggerMock, + ); }); it('should work', () => { diff --git a/server/src/services/server-info.service.ts b/server/src/services/server-info.service.ts index 9f0c1e290c..bb092896bf 100644 --- a/server/src/services/server-info.service.ts +++ b/server/src/services/server-info.service.ts @@ -15,19 +15,18 @@ import { } from 'src/dtos/server-info.dto'; import { SystemMetadataKey } from 'src/entities/system-metadata.entity'; import { ClientEvent, IEventRepository, ServerEvent, ServerEventMap } from 'src/interfaces/event.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IServerInfoRepository } from 'src/interfaces/server-info.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { IUserRepository, UserStatsQueryResponse } from 'src/interfaces/user.interface'; import { asHumanReadable } from 'src/utils/bytes'; -import { ImmichLogger } from 'src/utils/logger'; import { mimeTypes } from 'src/utils/mime-types'; import { Version } from 'src/utils/version'; @Injectable() export class ServerInfoService { - private logger = new ImmichLogger(ServerInfoService.name); private configCore: SystemConfigCore; private releaseVersion = serverVersion; private releaseVersionCheckedAt: DateTime | null = null; @@ -38,9 +37,11 @@ export class ServerInfoService { @Inject(IUserRepository) private userRepository: IUserRepository, @Inject(IServerInfoRepository) private repository: IServerInfoRepository, @Inject(IStorageRepository) private storageRepository: IStorageRepository, - @Inject(ISystemMetadataRepository) private readonly systemMetadataRepository: ISystemMetadataRepository, + @Inject(ISystemMetadataRepository) private systemMetadataRepository: ISystemMetadataRepository, + @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { - this.configCore = SystemConfigCore.create(configRepository); + this.logger.setContext(ServerInfoService.name); + this.configCore = SystemConfigCore.create(configRepository, this.logger); } onConnect() {} diff --git a/server/src/services/smart-info.service.spec.ts b/server/src/services/smart-info.service.spec.ts index e4b21a1692..4d85c00253 100644 --- a/server/src/services/smart-info.service.spec.ts +++ b/server/src/services/smart-info.service.spec.ts @@ -3,6 +3,7 @@ import { SystemConfigKey } from 'src/entities/system-config.entity'; import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface'; import { IDatabaseRepository } from 'src/interfaces/database.interface'; import { IJobRepository, JobName } from 'src/interfaces/job.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface'; import { ISearchRepository } from 'src/interfaces/search.interface'; import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; @@ -12,6 +13,7 @@ import { assetStub } from 'test/fixtures/asset.stub'; import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock'; import { newDatabaseRepositoryMock } from 'test/repositories/database.repository.mock'; import { newJobRepositoryMock } from 'test/repositories/job.repository.mock'; +import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; import { newMachineLearningRepositoryMock } from 'test/repositories/machine-learning.repository.mock'; import { newSearchRepositoryMock } from 'test/repositories/search.repository.mock'; import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock'; @@ -30,6 +32,7 @@ describe(SmartInfoService.name, () => { let searchMock: Mocked; let machineMock: Mocked; let databaseMock: Mocked; + let loggerMock: Mocked; beforeEach(() => { assetMock = newAssetRepositoryMock(); @@ -38,7 +41,8 @@ describe(SmartInfoService.name, () => { jobMock = newJobRepositoryMock(); machineMock = newMachineLearningRepositoryMock(); databaseMock = newDatabaseRepositoryMock(); - sut = new SmartInfoService(assetMock, databaseMock, jobMock, machineMock, searchMock, configMock); + loggerMock = newLoggerRepositoryMock(); + sut = new SmartInfoService(assetMock, databaseMock, jobMock, machineMock, searchMock, configMock, loggerMock); assetMock.getByIds.mockResolvedValue([asset]); }); diff --git a/server/src/services/smart-info.service.ts b/server/src/services/smart-info.service.ts index f9d36c238c..9de5edbd88 100644 --- a/server/src/services/smart-info.service.ts +++ b/server/src/services/smart-info.service.ts @@ -11,16 +11,15 @@ import { JobStatus, QueueName, } from 'src/interfaces/job.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface'; import { ISearchRepository } from 'src/interfaces/search.interface'; import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; -import { ImmichLogger } from 'src/utils/logger'; import { usePagination } from 'src/utils/pagination'; @Injectable() export class SmartInfoService { private configCore: SystemConfigCore; - private logger = new ImmichLogger(SmartInfoService.name); constructor( @Inject(IAssetRepository) private assetRepository: IAssetRepository, @@ -29,8 +28,10 @@ export class SmartInfoService { @Inject(IMachineLearningRepository) private machineLearning: IMachineLearningRepository, @Inject(ISearchRepository) private repository: ISearchRepository, @Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository, + @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { - this.configCore = SystemConfigCore.create(configRepository); + this.logger.setContext(SmartInfoService.name); + this.configCore = SystemConfigCore.create(configRepository, this.logger); } async init() { diff --git a/server/src/services/storage-template.service.spec.ts b/server/src/services/storage-template.service.spec.ts index c05dcedde1..952b656546 100644 --- a/server/src/services/storage-template.service.spec.ts +++ b/server/src/services/storage-template.service.spec.ts @@ -8,6 +8,7 @@ import { IAssetRepository } from 'src/interfaces/asset.interface'; import { ICryptoRepository } from 'src/interfaces/crypto.interface'; import { IDatabaseRepository } from 'src/interfaces/database.interface'; import { JobStatus } from 'src/interfaces/job.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IMoveRepository } from 'src/interfaces/move.interface'; import { IPersonRepository } from 'src/interfaces/person.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; @@ -20,6 +21,7 @@ import { newAlbumRepositoryMock } from 'test/repositories/album.repository.mock' import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock'; import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.mock'; import { newDatabaseRepositoryMock } from 'test/repositories/database.repository.mock'; +import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; import { newMoveRepositoryMock } from 'test/repositories/move.repository.mock'; import { newPersonRepositoryMock } from 'test/repositories/person.repository.mock'; import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock'; @@ -38,6 +40,7 @@ describe(StorageTemplateService.name, () => { let userMock: Mocked; let cryptoMock: Mocked; let databaseMock: Mocked; + let loggerMock: Mocked; it('should work', () => { expect(sut).toBeDefined(); @@ -53,6 +56,7 @@ describe(StorageTemplateService.name, () => { userMock = newUserRepositoryMock(); cryptoMock = newCryptoRepositoryMock(); databaseMock = newDatabaseRepositoryMock(); + loggerMock = newLoggerRepositoryMock(); configMock.load.mockResolvedValue([{ key: SystemConfigKey.STORAGE_TEMPLATE_ENABLED, value: true }]); @@ -66,9 +70,10 @@ describe(StorageTemplateService.name, () => { userMock, cryptoMock, databaseMock, + loggerMock, ); - SystemConfigCore.create(configMock).config$.next(defaults); + SystemConfigCore.create(configMock, loggerMock).config$.next(defaults); }); describe('onValidateConfig', () => { diff --git a/server/src/services/storage-template.service.ts b/server/src/services/storage-template.service.ts index 280c37b95b..835f5ea7d7 100644 --- a/server/src/services/storage-template.service.ts +++ b/server/src/services/storage-template.service.ts @@ -24,13 +24,13 @@ import { ICryptoRepository } from 'src/interfaces/crypto.interface'; import { DatabaseLock, IDatabaseRepository } from 'src/interfaces/database.interface'; import { ServerAsyncEvent, ServerAsyncEventMap } from 'src/interfaces/event.interface'; import { IEntityJob, JOBS_ASSET_PAGINATION_SIZE, JobStatus } from 'src/interfaces/job.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IMoveRepository } from 'src/interfaces/move.interface'; import { IPersonRepository } from 'src/interfaces/person.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; import { IUserRepository } from 'src/interfaces/user.interface'; import { getLivePhotoMotionFilename } from 'src/utils/file'; -import { ImmichLogger } from 'src/utils/logger'; import { usePagination } from 'src/utils/pagination'; export interface MoveAssetMetadata { @@ -47,7 +47,6 @@ interface RenderMetadata { @Injectable() export class StorageTemplateService { - private logger = new ImmichLogger(StorageTemplateService.name); private configCore: SystemConfigCore; private storageCore: StorageCore; private _template: { @@ -73,16 +72,19 @@ export class StorageTemplateService { @Inject(IUserRepository) private userRepository: IUserRepository, @Inject(ICryptoRepository) cryptoRepository: ICryptoRepository, @Inject(IDatabaseRepository) private databaseRepository: IDatabaseRepository, + @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { - this.configCore = SystemConfigCore.create(configRepository); + this.logger.setContext(StorageTemplateService.name); + this.configCore = SystemConfigCore.create(configRepository, this.logger); this.configCore.config$.subscribe((config) => this.onConfig(config)); this.storageCore = StorageCore.create( assetRepository, + cryptoRepository, moveRepository, personRepository, - cryptoRepository, - configRepository, storageRepository, + configRepository, + this.logger, ); } diff --git a/server/src/services/storage.service.spec.ts b/server/src/services/storage.service.spec.ts index 7dc2bd76db..ee574e0ba6 100644 --- a/server/src/services/storage.service.spec.ts +++ b/server/src/services/storage.service.spec.ts @@ -1,15 +1,19 @@ +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; import { StorageService } from 'src/services/storage.service'; +import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock'; import { Mocked } from 'vitest'; describe(StorageService.name, () => { let sut: StorageService; let storageMock: Mocked; + let loggerMock: Mocked; beforeEach(() => { storageMock = newStorageRepositoryMock(); - sut = new StorageService(storageMock); + loggerMock = newLoggerRepositoryMock(); + sut = new StorageService(storageMock, loggerMock); }); it('should work', () => { diff --git a/server/src/services/storage.service.ts b/server/src/services/storage.service.ts index 81fdb4f415..829888e244 100644 --- a/server/src/services/storage.service.ts +++ b/server/src/services/storage.service.ts @@ -1,14 +1,17 @@ import { Inject, Injectable } from '@nestjs/common'; import { StorageCore, StorageFolder } from 'src/cores/storage.core'; import { IDeleteFilesJob, JobStatus } from 'src/interfaces/job.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; -import { ImmichLogger } from 'src/utils/logger'; @Injectable() export class StorageService { - private logger = new ImmichLogger(StorageService.name); - - constructor(@Inject(IStorageRepository) private storageRepository: IStorageRepository) {} + constructor( + @Inject(IStorageRepository) private storageRepository: IStorageRepository, + @Inject(ILoggerRepository) private logger: ILoggerRepository, + ) { + this.logger.setContext(StorageService.name); + } init() { const libraryBase = StorageCore.getBaseFolder(StorageFolder.LIBRARY); diff --git a/server/src/services/system-config.service.spec.ts b/server/src/services/system-config.service.spec.ts index bb2a8ecbfa..49bf8d6544 100644 --- a/server/src/services/system-config.service.spec.ts +++ b/server/src/services/system-config.service.spec.ts @@ -20,11 +20,10 @@ import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { ISearchRepository } from 'src/interfaces/search.interface'; import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; import { SystemConfigService } from 'src/services/system-config.service'; -import { ImmichLogger } from 'src/utils/logger'; import { newEventRepositoryMock } from 'test/repositories/event.repository.mock'; import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock'; -import { MockInstance, Mocked, vitest } from 'vitest'; +import { Mocked } from 'vitest'; const updates: SystemConfigEntity[] = [ { key: SystemConfigKey.FFMPEG_CRF, value: 30 }, @@ -184,16 +183,6 @@ describe(SystemConfigService.name, () => { }); describe('getConfig', () => { - let warnLog: MockInstance; - - beforeEach(() => { - warnLog = vitest.spyOn(ImmichLogger.prototype, 'warn'); - }); - - afterEach(() => { - warnLog.mockRestore(); - }); - it('should return the default config', async () => { configMock.load.mockResolvedValue([]); @@ -271,7 +260,7 @@ describe(SystemConfigService.name, () => { configMock.readFile.mockResolvedValue(partialConfig); await sut.getConfig(); - expect(warnLog).toHaveBeenCalled(); + expect(loggerMock.warn).toHaveBeenCalled(); }); const tests = [ @@ -290,7 +279,7 @@ describe(SystemConfigService.name, () => { if (test.warn) { await sut.getConfig(); - expect(warnLog).toHaveBeenCalled(); + expect(loggerMock.warn).toHaveBeenCalled(); } else { await expect(sut.getConfig()).rejects.toBeInstanceOf(Error); } diff --git a/server/src/services/system-config.service.ts b/server/src/services/system-config.service.ts index 9a521115b5..2203f7a687 100644 --- a/server/src/services/system-config.service.ts +++ b/server/src/services/system-config.service.ts @@ -36,9 +36,9 @@ export class SystemConfigService { @Inject(ILoggerRepository) private logger: ILoggerRepository, @Inject(ISearchRepository) private smartInfoRepository: ISearchRepository, ) { - this.core = SystemConfigCore.create(repository); - this.core.config$.subscribe((config) => this.setLogLevel(config)); this.logger.setContext(SystemConfigService.name); + this.core = SystemConfigCore.create(repository, this.logger); + this.core.config$.subscribe((config) => this.setLogLevel(config)); } async init() { diff --git a/server/src/services/user.service.spec.ts b/server/src/services/user.service.spec.ts index 39c37bd8be..1bf4fc1012 100644 --- a/server/src/services/user.service.spec.ts +++ b/server/src/services/user.service.spec.ts @@ -10,6 +10,7 @@ import { IAlbumRepository } from 'src/interfaces/album.interface'; import { ICryptoRepository } from 'src/interfaces/crypto.interface'; import { IJobRepository, JobName } from 'src/interfaces/job.interface'; import { ILibraryRepository } from 'src/interfaces/library.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; import { IUserRepository } from 'src/interfaces/user.interface'; @@ -22,6 +23,7 @@ import { newAlbumRepositoryMock } from 'test/repositories/album.repository.mock' import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.mock'; import { newJobRepositoryMock } from 'test/repositories/job.repository.mock'; import { newLibraryRepositoryMock } from 'test/repositories/library.repository.mock'; +import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock'; import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock'; import { newUserRepositoryMock } from 'test/repositories/user.repository.mock'; @@ -43,6 +45,7 @@ describe(UserService.name, () => { let libraryMock: Mocked; let storageMock: Mocked; let configMock: Mocked; + let loggerMock: Mocked; beforeEach(() => { albumMock = newAlbumRepositoryMock(); @@ -52,8 +55,18 @@ describe(UserService.name, () => { libraryMock = newLibraryRepositoryMock(); storageMock = newStorageRepositoryMock(); userMock = newUserRepositoryMock(); + loggerMock = newLoggerRepositoryMock(); - sut = new UserService(albumMock, cryptoRepositoryMock, jobMock, libraryMock, storageMock, configMock, userMock); + sut = new UserService( + albumMock, + cryptoRepositoryMock, + jobMock, + libraryMock, + storageMock, + configMock, + userMock, + loggerMock, + ); userMock.get.mockImplementation((userId) => Promise.resolve([userStub.admin, userStub.user1].find((user) => user.id === userId) ?? null), diff --git a/server/src/services/user.service.ts b/server/src/services/user.service.ts index a2bc8c7cfc..cb9012d641 100644 --- a/server/src/services/user.service.ts +++ b/server/src/services/user.service.ts @@ -11,16 +11,15 @@ import { IAlbumRepository } from 'src/interfaces/album.interface'; import { ICryptoRepository } from 'src/interfaces/crypto.interface'; import { IEntityJob, IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface'; import { ILibraryRepository } from 'src/interfaces/library.interface'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface'; import { ISystemConfigRepository } from 'src/interfaces/system-config.interface'; import { IUserRepository, UserFindOptions } from 'src/interfaces/user.interface'; import { CacheControl, ImmichFileResponse } from 'src/utils/file'; -import { ImmichLogger } from 'src/utils/logger'; @Injectable() export class UserService { private configCore: SystemConfigCore; - private logger = new ImmichLogger(UserService.name); private userCore: UserCore; constructor( @@ -31,9 +30,11 @@ export class UserService { @Inject(IStorageRepository) private storageRepository: IStorageRepository, @Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository, @Inject(IUserRepository) private userRepository: IUserRepository, + @Inject(ILoggerRepository) private logger: ILoggerRepository, ) { this.userCore = UserCore.create(cryptoRepository, libraryRepository, userRepository); - this.configCore = SystemConfigCore.create(configRepository); + this.logger.setContext(UserService.name); + this.configCore = SystemConfigCore.create(configRepository, this.logger); } async getAll(auth: AuthDto, isAll: boolean): Promise { diff --git a/server/src/utils/misc.ts b/server/src/utils/misc.ts index 3837c62798..c11c936a1a 100644 --- a/server/src/utils/misc.ts +++ b/server/src/utils/misc.ts @@ -17,12 +17,12 @@ import { IMMICH_API_KEY_NAME, serverVersion, } from 'src/constants'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { Metadata } from 'src/middleware/auth.guard'; -import { ImmichLogger } from 'src/utils/logger'; export const isConnectionAborted = (error: Error | any) => error.code === 'ECONNABORTED'; -export const handlePromiseError = (promise: Promise, logger: ImmichLogger): void => { +export const handlePromiseError = (promise: Promise, logger: ILoggerRepository): void => { promise.catch((error: Error | any) => logger.error(`Promise error: ${error}`, error?.stack)); }; diff --git a/server/src/utils/sql.ts b/server/src/utils/sql.ts index 662c40fcba..36b485b88a 100644 --- a/server/src/utils/sql.ts +++ b/server/src/utils/sql.ts @@ -12,6 +12,7 @@ import { format } from 'sql-formatter'; import { databaseConfig } from 'src/database.config'; import { GENERATE_SQL_KEY, GenerateSqlQueries } from 'src/decorators'; import { entities } from 'src/entities'; +import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { repositories } from 'src/repositories'; import { AccessRepository } from 'src/repositories/access.repository'; import { AuthService } from 'src/services/auth.service'; @@ -58,6 +59,9 @@ class SqlGenerator { try { await this.setup(); for (const repository of repositories) { + if (repository.provide === ILoggerRepository) { + continue; + } await this.process(repository); } await this.write();