1
0
mirror of https://github.com/immich-app/immich.git synced 2025-05-29 01:07:40 +02:00

refactor: logging repository (#15540)

This commit is contained in:
Jason Rasmussen 2025-01-23 08:31:30 -05:00 committed by GitHub
parent b31414af8f
commit d3446f3092
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
53 changed files with 159 additions and 172 deletions

View File

@ -13,7 +13,6 @@ import { entities } from 'src/entities';
import { ImmichWorker } from 'src/enum'; import { ImmichWorker } from 'src/enum';
import { IEventRepository } from 'src/interfaces/event.interface'; import { IEventRepository } from 'src/interfaces/event.interface';
import { IJobRepository } from 'src/interfaces/job.interface'; import { IJobRepository } from 'src/interfaces/job.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { ITelemetryRepository } from 'src/interfaces/telemetry.interface'; import { ITelemetryRepository } from 'src/interfaces/telemetry.interface';
import { AuthGuard } from 'src/middleware/auth.guard'; import { AuthGuard } from 'src/middleware/auth.guard';
import { ErrorInterceptor } from 'src/middleware/error.interceptor'; import { ErrorInterceptor } from 'src/middleware/error.interceptor';
@ -22,6 +21,7 @@ import { GlobalExceptionFilter } from 'src/middleware/global-exception.filter';
import { LoggingInterceptor } from 'src/middleware/logging.interceptor'; import { LoggingInterceptor } from 'src/middleware/logging.interceptor';
import { providers, repositories } from 'src/repositories'; import { providers, repositories } from 'src/repositories';
import { ConfigRepository } from 'src/repositories/config.repository'; import { ConfigRepository } from 'src/repositories/config.repository';
import { LoggingRepository } from 'src/repositories/logging.repository';
import { teardownTelemetry } from 'src/repositories/telemetry.repository'; import { teardownTelemetry } from 'src/repositories/telemetry.repository';
import { services } from 'src/services'; import { services } from 'src/services';
import { CliService } from 'src/services/cli.service'; import { CliService } from 'src/services/cli.service';
@ -64,7 +64,7 @@ const imports = [
class BaseModule implements OnModuleInit, OnModuleDestroy { class BaseModule implements OnModuleInit, OnModuleDestroy {
constructor( constructor(
@Inject(IWorker) private worker: ImmichWorker, @Inject(IWorker) private worker: ImmichWorker,
@Inject(ILoggerRepository) logger: ILoggerRepository, logger: LoggingRepository,
@Inject(IEventRepository) private eventRepository: IEventRepository, @Inject(IEventRepository) private eventRepository: IEventRepository,
@Inject(IJobRepository) private jobRepository: IJobRepository, @Inject(IJobRepository) private jobRepository: IJobRepository,
@Inject(ITelemetryRepository) private telemetryRepository: ITelemetryRepository, @Inject(ITelemetryRepository) private telemetryRepository: ITelemetryRepository,

View File

@ -11,10 +11,10 @@ import { join } from 'node:path';
import { format } from 'sql-formatter'; import { format } from 'sql-formatter';
import { GENERATE_SQL_KEY, GenerateSqlQueries } from 'src/decorators'; import { GENERATE_SQL_KEY, GenerateSqlQueries } from 'src/decorators';
import { entities } from 'src/entities'; import { entities } from 'src/entities';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { providers, repositories } from 'src/repositories'; import { providers, repositories } from 'src/repositories';
import { AccessRepository } from 'src/repositories/access.repository'; import { AccessRepository } from 'src/repositories/access.repository';
import { ConfigRepository } from 'src/repositories/config.repository'; import { ConfigRepository } from 'src/repositories/config.repository';
import { LoggingRepository } from 'src/repositories/logging.repository';
import { AuthService } from 'src/services/auth.service'; import { AuthService } from 'src/services/auth.service';
import { Logger } from 'typeorm'; import { Logger } from 'typeorm';
@ -62,7 +62,7 @@ class SqlGenerator {
...repositories.map((repository) => ({ provide: repository, useClass: repository as any })), ...repositories.map((repository) => ({ provide: repository, useClass: repository as any })),
]; ];
for (const repository of targets) { for (const repository of targets) {
if (repository.provide === ILoggerRepository) { if (repository.provide === LoggingRepository) {
continue; continue;
} }
await this.process(repository); await this.process(repository);

View File

@ -4,7 +4,6 @@ import {
Get, Get,
HttpCode, HttpCode,
HttpStatus, HttpStatus,
Inject,
Next, Next,
Param, Param,
ParseFilePipe, ParseFilePipe,
@ -34,10 +33,10 @@ import {
} from 'src/dtos/asset-media.dto'; } from 'src/dtos/asset-media.dto';
import { AuthDto } from 'src/dtos/auth.dto'; import { AuthDto } from 'src/dtos/auth.dto';
import { ImmichHeader, RouteKey } from 'src/enum'; import { ImmichHeader, RouteKey } from 'src/enum';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { AssetUploadInterceptor } from 'src/middleware/asset-upload.interceptor'; import { AssetUploadInterceptor } from 'src/middleware/asset-upload.interceptor';
import { Auth, Authenticated, FileResponse } from 'src/middleware/auth.guard'; import { Auth, Authenticated, FileResponse } from 'src/middleware/auth.guard';
import { FileUploadInterceptor, UploadFiles, getFiles } from 'src/middleware/file-upload.interceptor'; import { FileUploadInterceptor, UploadFiles, getFiles } from 'src/middleware/file-upload.interceptor';
import { LoggingRepository } from 'src/repositories/logging.repository';
import { AssetMediaService } from 'src/services/asset-media.service'; import { AssetMediaService } from 'src/services/asset-media.service';
import { sendFile } from 'src/utils/file'; import { sendFile } from 'src/utils/file';
import { FileNotEmptyValidator, UUIDParamDto } from 'src/validation'; import { FileNotEmptyValidator, UUIDParamDto } from 'src/validation';
@ -46,7 +45,7 @@ import { FileNotEmptyValidator, UUIDParamDto } from 'src/validation';
@Controller(RouteKey.ASSET) @Controller(RouteKey.ASSET)
export class AssetMediaController { export class AssetMediaController {
constructor( constructor(
@Inject(ILoggerRepository) private logger: ILoggerRepository, private logger: LoggingRepository,
private service: AssetMediaService, private service: AssetMediaService,
) {} ) {}

View File

@ -1,4 +1,4 @@
import { Body, Controller, Get, Inject, Next, Param, Post, Put, Query, Res } from '@nestjs/common'; import { Body, Controller, Get, Next, Param, Post, Put, Query, Res } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger'; import { ApiTags } from '@nestjs/swagger';
import { NextFunction, Response } from 'express'; import { NextFunction, Response } from 'express';
import { BulkIdResponseDto } from 'src/dtos/asset-ids.response.dto'; import { BulkIdResponseDto } from 'src/dtos/asset-ids.response.dto';
@ -15,8 +15,8 @@ import {
PersonUpdateDto, PersonUpdateDto,
} from 'src/dtos/person.dto'; } from 'src/dtos/person.dto';
import { Permission } from 'src/enum'; import { Permission } from 'src/enum';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { Auth, Authenticated, FileResponse } from 'src/middleware/auth.guard'; import { Auth, Authenticated, FileResponse } from 'src/middleware/auth.guard';
import { LoggingRepository } from 'src/repositories/logging.repository';
import { PersonService } from 'src/services/person.service'; import { PersonService } from 'src/services/person.service';
import { sendFile } from 'src/utils/file'; import { sendFile } from 'src/utils/file';
import { UUIDParamDto } from 'src/validation'; import { UUIDParamDto } from 'src/validation';
@ -26,7 +26,7 @@ import { UUIDParamDto } from 'src/validation';
export class PersonController { export class PersonController {
constructor( constructor(
private service: PersonService, private service: PersonService,
@Inject(ILoggerRepository) private logger: ILoggerRepository, private logger: LoggingRepository,
) {} ) {}
@Get() @Get()

View File

@ -5,7 +5,6 @@ import {
Get, Get,
HttpCode, HttpCode,
HttpStatus, HttpStatus,
Inject,
Next, Next,
Param, Param,
Post, Post,
@ -22,9 +21,9 @@ import { UserPreferencesResponseDto, UserPreferencesUpdateDto } from 'src/dtos/u
import { CreateProfileImageDto, CreateProfileImageResponseDto } from 'src/dtos/user-profile.dto'; import { CreateProfileImageDto, CreateProfileImageResponseDto } from 'src/dtos/user-profile.dto';
import { UserAdminResponseDto, UserResponseDto, UserUpdateMeDto } from 'src/dtos/user.dto'; import { UserAdminResponseDto, UserResponseDto, UserUpdateMeDto } from 'src/dtos/user.dto';
import { RouteKey } from 'src/enum'; import { RouteKey } from 'src/enum';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { Auth, Authenticated, FileResponse } from 'src/middleware/auth.guard'; import { Auth, Authenticated, FileResponse } from 'src/middleware/auth.guard';
import { FileUploadInterceptor } from 'src/middleware/file-upload.interceptor'; import { FileUploadInterceptor } from 'src/middleware/file-upload.interceptor';
import { LoggingRepository } from 'src/repositories/logging.repository';
import { UserService } from 'src/services/user.service'; import { UserService } from 'src/services/user.service';
import { sendFile } from 'src/utils/file'; import { sendFile } from 'src/utils/file';
import { UUIDParamDto } from 'src/validation'; import { UUIDParamDto } from 'src/validation';
@ -34,7 +33,7 @@ import { UUIDParamDto } from 'src/validation';
export class UserController { export class UserController {
constructor( constructor(
private service: UserService, private service: UserService,
@Inject(ILoggerRepository) private logger: ILoggerRepository, private logger: LoggingRepository,
) {} ) {}
@Get() @Get()

View File

@ -6,12 +6,11 @@ import { PersonEntity } from 'src/entities/person.entity';
import { AssetFileType, AssetPathType, ImageFormat, PathType, PersonPathType, StorageFolder } from 'src/enum'; import { AssetFileType, AssetPathType, ImageFormat, PathType, PersonPathType, StorageFolder } from 'src/enum';
import { IAssetRepository } from 'src/interfaces/asset.interface'; import { IAssetRepository } from 'src/interfaces/asset.interface';
import { ICryptoRepository } from 'src/interfaces/crypto.interface'; import { ICryptoRepository } from 'src/interfaces/crypto.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IMoveRepository } from 'src/interfaces/move.interface'; import { IMoveRepository } from 'src/interfaces/move.interface';
import { IPersonRepository } from 'src/interfaces/person.interface'; import { IPersonRepository } from 'src/interfaces/person.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { IConfigRepository } from 'src/types'; import { IConfigRepository, ILoggingRepository } from 'src/types';
import { getAssetFiles } from 'src/utils/asset.util'; import { getAssetFiles } from 'src/utils/asset.util';
import { getConfig } from 'src/utils/config'; import { getConfig } from 'src/utils/config';
@ -40,7 +39,7 @@ export class StorageCore {
private personRepository: IPersonRepository, private personRepository: IPersonRepository,
private storageRepository: IStorageRepository, private storageRepository: IStorageRepository,
private systemMetadataRepository: ISystemMetadataRepository, private systemMetadataRepository: ISystemMetadataRepository,
private logger: ILoggerRepository, private logger: ILoggingRepository,
) {} ) {}
static create( static create(
@ -51,7 +50,7 @@ export class StorageCore {
personRepository: IPersonRepository, personRepository: IPersonRepository,
storageRepository: IStorageRepository, storageRepository: IStorageRepository,
systemMetadataRepository: ISystemMetadataRepository, systemMetadataRepository: ISystemMetadataRepository,
logger: ILoggerRepository, logger: ILoggingRepository,
) { ) {
if (!instance) { if (!instance) {
instance = new StorageCore( instance = new StorageCore(

View File

@ -1,17 +0,0 @@
import { ImmichWorker, LogLevel } from 'src/enum';
export const ILoggerRepository = 'ILoggerRepository';
export interface ILoggerRepository {
setAppName(name: ImmichWorker): void;
setContext(message: string): void;
setLogLevel(level: LogLevel | false): void;
isLevelEnabled(level: LogLevel): boolean;
verbose(message: any, ...args: any): void;
debug(message: any, ...args: any): void;
log(message: any, ...args: any): void;
warn(message: any, ...args: any): void;
error(message: any, ...args: any): void;
fatal(message: any, ...args: any): void;
}

View File

@ -1,7 +1,6 @@
import { import {
CanActivate, CanActivate,
ExecutionContext, ExecutionContext,
Inject,
Injectable, Injectable,
SetMetadata, SetMetadata,
applyDecorators, applyDecorators,
@ -12,7 +11,7 @@ import { ApiBearerAuth, ApiCookieAuth, ApiOkResponse, ApiQuery, ApiSecurity } fr
import { Request } from 'express'; import { Request } from 'express';
import { AuthDto } from 'src/dtos/auth.dto'; import { AuthDto } from 'src/dtos/auth.dto';
import { ImmichQuery, MetadataKey, Permission } from 'src/enum'; import { ImmichQuery, MetadataKey, Permission } from 'src/enum';
import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { LoggingRepository } from 'src/repositories/logging.repository';
import { AuthService, LoginDetails } from 'src/services/auth.service'; import { AuthService, LoginDetails } from 'src/services/auth.service';
import { UAParser } from 'ua-parser-js'; import { UAParser } from 'ua-parser-js';
@ -67,7 +66,7 @@ export interface AuthenticatedRequest extends Request {
@Injectable() @Injectable()
export class AuthGuard implements CanActivate { export class AuthGuard implements CanActivate {
constructor( constructor(
@Inject(ILoggerRepository) private logger: ILoggerRepository, private logger: LoggingRepository,
private reflector: Reflector, private reflector: Reflector,
private authService: AuthService, private authService: AuthService,
) { ) {

View File

@ -2,19 +2,18 @@ import {
CallHandler, CallHandler,
ExecutionContext, ExecutionContext,
HttpException, HttpException,
Inject,
Injectable, Injectable,
InternalServerErrorException, InternalServerErrorException,
NestInterceptor, NestInterceptor,
} from '@nestjs/common'; } from '@nestjs/common';
import { Observable, catchError, throwError } from 'rxjs'; import { Observable, catchError, throwError } from 'rxjs';
import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { LoggingRepository } from 'src/repositories/logging.repository';
import { logGlobalError } from 'src/utils/logger'; import { logGlobalError } from 'src/utils/logger';
import { routeToErrorMessage } from 'src/utils/misc'; import { routeToErrorMessage } from 'src/utils/misc';
@Injectable() @Injectable()
export class ErrorInterceptor implements NestInterceptor { export class ErrorInterceptor implements NestInterceptor {
constructor(@Inject(ILoggerRepository) private logger: ILoggerRepository) { constructor(private logger: LoggingRepository) {
this.logger.setContext(ErrorInterceptor.name); this.logger.setContext(ErrorInterceptor.name);
} }

View File

@ -1,4 +1,4 @@
import { CallHandler, ExecutionContext, Inject, Injectable, NestInterceptor } from '@nestjs/common'; import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { PATH_METADATA } from '@nestjs/common/constants'; import { PATH_METADATA } from '@nestjs/common/constants';
import { Reflector } from '@nestjs/core'; import { Reflector } from '@nestjs/core';
import { transformException } from '@nestjs/platform-express/multer/multer/multer.utils'; import { transformException } from '@nestjs/platform-express/multer/multer/multer.utils';
@ -8,8 +8,8 @@ import { createHash, randomUUID } from 'node:crypto';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { UploadFieldName } from 'src/dtos/asset-media.dto'; import { UploadFieldName } from 'src/dtos/asset-media.dto';
import { RouteKey } from 'src/enum'; import { RouteKey } from 'src/enum';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { AuthRequest } from 'src/middleware/auth.guard'; import { AuthRequest } from 'src/middleware/auth.guard';
import { LoggingRepository } from 'src/repositories/logging.repository';
import { AssetMediaService, UploadFile } from 'src/services/asset-media.service'; import { AssetMediaService, UploadFile } from 'src/services/asset-media.service';
import { asRequest, mapToUploadFile } from 'src/utils/asset.util'; import { asRequest, mapToUploadFile } from 'src/utils/asset.util';
@ -64,7 +64,7 @@ export class FileUploadInterceptor implements NestInterceptor {
constructor( constructor(
private reflect: Reflector, private reflect: Reflector,
private assetService: AssetMediaService, private assetService: AssetMediaService,
@Inject(ILoggerRepository) private logger: ILoggerRepository, private logger: LoggingRepository,
) { ) {
this.logger.setContext(FileUploadInterceptor.name); this.logger.setContext(FileUploadInterceptor.name);

View File

@ -1,13 +1,13 @@
import { ArgumentsHost, Catch, ExceptionFilter, HttpException, Inject } from '@nestjs/common'; import { ArgumentsHost, Catch, ExceptionFilter, HttpException } from '@nestjs/common';
import { Response } from 'express'; import { Response } from 'express';
import { ClsService } from 'nestjs-cls'; import { ClsService } from 'nestjs-cls';
import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { LoggingRepository } from 'src/repositories/logging.repository';
import { logGlobalError } from 'src/utils/logger'; import { logGlobalError } from 'src/utils/logger';
@Catch() @Catch()
export class GlobalExceptionFilter implements ExceptionFilter<Error> { export class GlobalExceptionFilter implements ExceptionFilter<Error> {
constructor( constructor(
@Inject(ILoggerRepository) private logger: ILoggerRepository, private logger: LoggingRepository,
private cls: ClsService, private cls: ClsService,
) { ) {
this.logger.setContext(GlobalExceptionFilter.name); this.logger.setContext(GlobalExceptionFilter.name);

View File

@ -1,7 +1,7 @@
import { CallHandler, ExecutionContext, Inject, Injectable, NestInterceptor } from '@nestjs/common'; import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import { Observable, finalize } from 'rxjs'; import { Observable, finalize } from 'rxjs';
import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { LoggingRepository } from 'src/repositories/logging.repository';
const maxArrayLength = 100; const maxArrayLength = 100;
const replacer = (key: string, value: unknown) => { const replacer = (key: string, value: unknown) => {
@ -18,7 +18,7 @@ const replacer = (key: string, value: unknown) => {
@Injectable() @Injectable()
export class LoggingInterceptor implements NestInterceptor { export class LoggingInterceptor implements NestInterceptor {
constructor(@Inject(ILoggerRepository) private logger: ILoggerRepository) { constructor(private logger: LoggingRepository) {
this.logger.setContext(LoggingInterceptor.name); this.logger.setContext(LoggingInterceptor.name);
} }

View File

@ -1,14 +1,14 @@
import { Inject, Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { SchedulerRegistry } from '@nestjs/schedule'; import { SchedulerRegistry } from '@nestjs/schedule';
import { CronJob, CronTime } from 'cron'; import { CronJob, CronTime } from 'cron';
import { CronCreate, CronUpdate, ICronRepository } from 'src/interfaces/cron.interface'; import { CronCreate, CronUpdate, ICronRepository } from 'src/interfaces/cron.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { LoggingRepository } from 'src/repositories/logging.repository';
@Injectable() @Injectable()
export class CronRepository implements ICronRepository { export class CronRepository implements ICronRepository {
constructor( constructor(
private schedulerRegistry: SchedulerRegistry, private schedulerRegistry: SchedulerRegistry,
@Inject(ILoggerRepository) private logger: ILoggerRepository, private logger: LoggingRepository,
) { ) {
this.logger.setContext(CronRepository.name); this.logger.setContext(CronRepository.name);
} }

View File

@ -1,4 +1,4 @@
import { Inject, Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { InjectDataSource } from '@nestjs/typeorm'; import { InjectDataSource } from '@nestjs/typeorm';
import AsyncLock from 'async-lock'; import AsyncLock from 'async-lock';
import { Kysely, sql } from 'kysely'; import { Kysely, sql } from 'kysely';
@ -16,8 +16,8 @@ import {
VectorIndex, VectorIndex,
VectorUpdateResult, VectorUpdateResult,
} from 'src/interfaces/database.interface'; } from 'src/interfaces/database.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { ConfigRepository } from 'src/repositories/config.repository'; import { ConfigRepository } from 'src/repositories/config.repository';
import { LoggingRepository } from 'src/repositories/logging.repository';
import { UPSERT_COLUMNS } from 'src/utils/database'; import { UPSERT_COLUMNS } from 'src/utils/database';
import { isValidInteger } from 'src/validation'; import { isValidInteger } from 'src/validation';
import { DataSource, EntityManager, EntityMetadata, QueryRunner } from 'typeorm'; import { DataSource, EntityManager, EntityMetadata, QueryRunner } from 'typeorm';
@ -30,7 +30,7 @@ export class DatabaseRepository implements IDatabaseRepository {
constructor( constructor(
@InjectKysely() private db: Kysely<DB>, @InjectKysely() private db: Kysely<DB>,
@InjectDataSource() private dataSource: DataSource, @InjectDataSource() private dataSource: DataSource,
@Inject(ILoggerRepository) private logger: ILoggerRepository, private logger: LoggingRepository,
configRepository: ConfigRepository, configRepository: ConfigRepository,
) { ) {
this.vectorExtension = configRepository.getEnv().database.vectorExtension; this.vectorExtension = configRepository.getEnv().database.vectorExtension;

View File

@ -1,4 +1,4 @@
import { Inject, Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { ModuleRef, Reflector } from '@nestjs/core'; import { ModuleRef, Reflector } from '@nestjs/core';
import { import {
OnGatewayConnection, OnGatewayConnection,
@ -22,8 +22,8 @@ import {
serverEvents, serverEvents,
ServerEvents, ServerEvents,
} from 'src/interfaces/event.interface'; } from 'src/interfaces/event.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { ConfigRepository } from 'src/repositories/config.repository'; import { ConfigRepository } from 'src/repositories/config.repository';
import { LoggingRepository } from 'src/repositories/logging.repository';
import { AuthService } from 'src/services/auth.service'; import { AuthService } from 'src/services/auth.service';
import { handlePromiseError } from 'src/utils/misc'; import { handlePromiseError } from 'src/utils/misc';
@ -52,7 +52,7 @@ export class EventRepository implements OnGatewayConnection, OnGatewayDisconnect
constructor( constructor(
private moduleRef: ModuleRef, private moduleRef: ModuleRef,
private configRepository: ConfigRepository, private configRepository: ConfigRepository,
@Inject(ILoggerRepository) private logger: ILoggerRepository, private logger: LoggingRepository,
) { ) {
this.logger.setContext(EventRepository.name); this.logger.setContext(EventRepository.name);
} }

View File

@ -7,7 +7,6 @@ import { IDatabaseRepository } from 'src/interfaces/database.interface';
import { IEventRepository } from 'src/interfaces/event.interface'; import { IEventRepository } from 'src/interfaces/event.interface';
import { IJobRepository } from 'src/interfaces/job.interface'; import { IJobRepository } from 'src/interfaces/job.interface';
import { ILibraryRepository } from 'src/interfaces/library.interface'; import { ILibraryRepository } from 'src/interfaces/library.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface'; import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface';
import { IMapRepository } from 'src/interfaces/map.interface'; import { IMapRepository } from 'src/interfaces/map.interface';
import { IMetadataRepository } from 'src/interfaces/metadata.interface'; import { IMetadataRepository } from 'src/interfaces/metadata.interface';
@ -43,7 +42,7 @@ import { DatabaseRepository } from 'src/repositories/database.repository';
import { EventRepository } from 'src/repositories/event.repository'; import { EventRepository } from 'src/repositories/event.repository';
import { JobRepository } from 'src/repositories/job.repository'; import { JobRepository } from 'src/repositories/job.repository';
import { LibraryRepository } from 'src/repositories/library.repository'; import { LibraryRepository } from 'src/repositories/library.repository';
import { LoggerRepository } from 'src/repositories/logger.repository'; import { LoggingRepository } from 'src/repositories/logging.repository';
import { MachineLearningRepository } from 'src/repositories/machine-learning.repository'; import { MachineLearningRepository } from 'src/repositories/machine-learning.repository';
import { MapRepository } from 'src/repositories/map.repository'; import { MapRepository } from 'src/repositories/map.repository';
import { MediaRepository } from 'src/repositories/media.repository'; import { MediaRepository } from 'src/repositories/media.repository';
@ -70,12 +69,12 @@ import { VersionHistoryRepository } from 'src/repositories/version-history.repos
import { ViewRepository } from 'src/repositories/view-repository'; import { ViewRepository } from 'src/repositories/view-repository';
export const repositories = [ export const repositories = [
//
AccessRepository, AccessRepository,
ActivityRepository, ActivityRepository,
AuditRepository, AuditRepository,
ApiKeyRepository, ApiKeyRepository,
ConfigRepository, ConfigRepository,
LoggingRepository,
MediaRepository, MediaRepository,
MemoryRepository, MemoryRepository,
ViewRepository, ViewRepository,
@ -91,7 +90,6 @@ export const providers = [
{ provide: IEventRepository, useClass: EventRepository }, { provide: IEventRepository, useClass: EventRepository },
{ provide: IJobRepository, useClass: JobRepository }, { provide: IJobRepository, useClass: JobRepository },
{ provide: ILibraryRepository, useClass: LibraryRepository }, { provide: ILibraryRepository, useClass: LibraryRepository },
{ provide: ILoggerRepository, useClass: LoggerRepository },
{ provide: IMachineLearningRepository, useClass: MachineLearningRepository }, { provide: IMachineLearningRepository, useClass: MachineLearningRepository },
{ provide: IMapRepository, useClass: MapRepository }, { provide: IMapRepository, useClass: MapRepository },
{ provide: IMetadataRepository, useClass: MetadataRepository }, { provide: IMetadataRepository, useClass: MetadataRepository },

View File

@ -19,8 +19,8 @@ import {
QueueName, QueueName,
QueueStatus, QueueStatus,
} from 'src/interfaces/job.interface'; } from 'src/interfaces/job.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { ConfigRepository } from 'src/repositories/config.repository'; import { ConfigRepository } from 'src/repositories/config.repository';
import { LoggingRepository } from 'src/repositories/logging.repository';
import { getKeyByValue, getMethodNames, ImmichStartupError } from 'src/utils/misc'; import { getKeyByValue, getMethodNames, ImmichStartupError } from 'src/utils/misc';
type JobMapItem = { type JobMapItem = {
@ -39,7 +39,7 @@ export class JobRepository implements IJobRepository {
private moduleRef: ModuleRef, private moduleRef: ModuleRef,
private configRepository: ConfigRepository, private configRepository: ConfigRepository,
@Inject(IEventRepository) private eventRepository: IEventRepository, @Inject(IEventRepository) private eventRepository: IEventRepository,
@Inject(ILoggerRepository) private logger: ILoggerRepository, private logger: LoggingRepository,
) { ) {
this.logger.setContext(JobRepository.name); this.logger.setContext(JobRepository.name);
} }

View File

@ -1,12 +1,12 @@
import { ClsService } from 'nestjs-cls'; import { ClsService } from 'nestjs-cls';
import { ImmichWorker } from 'src/enum'; import { ImmichWorker } from 'src/enum';
import { LoggerRepository } from 'src/repositories/logger.repository'; import { LoggingRepository } from 'src/repositories/logging.repository';
import { IConfigRepository } from 'src/types'; import { IConfigRepository } from 'src/types';
import { mockEnvData, newConfigRepositoryMock } from 'test/repositories/config.repository.mock'; import { mockEnvData, newConfigRepositoryMock } from 'test/repositories/config.repository.mock';
import { Mocked } from 'vitest'; import { Mocked } from 'vitest';
describe(LoggerRepository.name, () => { describe(LoggingRepository.name, () => {
let sut: LoggerRepository; let sut: LoggingRepository;
let configMock: Mocked<IConfigRepository>; let configMock: Mocked<IConfigRepository>;
let clsMock: Mocked<ClsService>; let clsMock: Mocked<ClsService>;
@ -22,7 +22,7 @@ describe(LoggerRepository.name, () => {
it('should use colors', () => { it('should use colors', () => {
configMock.getEnv.mockReturnValue(mockEnvData({ noColor: false })); configMock.getEnv.mockReturnValue(mockEnvData({ noColor: false }));
sut = new LoggerRepository(clsMock, configMock); sut = new LoggingRepository(clsMock, configMock);
sut.setAppName(ImmichWorker.API); sut.setAppName(ImmichWorker.API);
expect(sut['formatContext']('context')).toBe('\u001B[33m[Api:context]\u001B[39m '); expect(sut['formatContext']('context')).toBe('\u001B[33m[Api:context]\u001B[39m ');
@ -31,7 +31,7 @@ describe(LoggerRepository.name, () => {
it('should not use colors when noColor is true', () => { it('should not use colors when noColor is true', () => {
configMock.getEnv.mockReturnValue(mockEnvData({ noColor: true })); configMock.getEnv.mockReturnValue(mockEnvData({ noColor: true }));
sut = new LoggerRepository(clsMock, configMock); sut = new LoggingRepository(clsMock, configMock);
sut.setAppName(ImmichWorker.API); sut.setAppName(ImmichWorker.API);
expect(sut['formatContext']('context')).toBe('[Api:context] '); expect(sut['formatContext']('context')).toBe('[Api:context] ');

View File

@ -3,7 +3,6 @@ import { isLogLevelEnabled } from '@nestjs/common/services/utils/is-log-level-en
import { ClsService } from 'nestjs-cls'; import { ClsService } from 'nestjs-cls';
import { Telemetry } from 'src/decorators'; import { Telemetry } from 'src/decorators';
import { LogLevel } from 'src/enum'; import { LogLevel } from 'src/enum';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { ConfigRepository } from 'src/repositories/config.repository'; import { ConfigRepository } from 'src/repositories/config.repository';
const LOG_LEVELS = [LogLevel.VERBOSE, LogLevel.DEBUG, LogLevel.LOG, LogLevel.WARN, LogLevel.ERROR, LogLevel.FATAL]; const LOG_LEVELS = [LogLevel.VERBOSE, LogLevel.DEBUG, LogLevel.LOG, LogLevel.WARN, LogLevel.ERROR, LogLevel.FATAL];
@ -19,7 +18,7 @@ enum LogColor {
@Injectable({ scope: Scope.TRANSIENT }) @Injectable({ scope: Scope.TRANSIENT })
@Telemetry({ enabled: false }) @Telemetry({ enabled: false })
export class LoggerRepository extends ConsoleLogger implements ILoggerRepository { export class LoggingRepository extends ConsoleLogger {
private static logLevels: LogLevel[] = [LogLevel.LOG, LogLevel.WARN, LogLevel.ERROR, LogLevel.FATAL]; private static logLevels: LogLevel[] = [LogLevel.LOG, LogLevel.WARN, LogLevel.ERROR, LogLevel.FATAL];
private noColor: boolean; private noColor: boolean;
@ -27,7 +26,7 @@ export class LoggerRepository extends ConsoleLogger implements ILoggerRepository
private cls: ClsService, private cls: ClsService,
configRepository: ConfigRepository, configRepository: ConfigRepository,
) { ) {
super(LoggerRepository.name); super(LoggingRepository.name);
const { noColor } = configRepository.getEnv(); const { noColor } = configRepository.getEnv();
this.noColor = noColor; this.noColor = noColor;
@ -36,19 +35,19 @@ export class LoggerRepository extends ConsoleLogger implements ILoggerRepository
private static appName?: string = undefined; private static appName?: string = undefined;
setAppName(name: string): void { setAppName(name: string): void {
LoggerRepository.appName = name.charAt(0).toUpperCase() + name.slice(1); LoggingRepository.appName = name.charAt(0).toUpperCase() + name.slice(1);
} }
isLevelEnabled(level: LogLevel) { isLevelEnabled(level: LogLevel) {
return isLogLevelEnabled(level, LoggerRepository.logLevels); return isLogLevelEnabled(level, LoggingRepository.logLevels);
} }
setLogLevel(level: LogLevel | false): void { setLogLevel(level: LogLevel | false): void {
LoggerRepository.logLevels = level ? LOG_LEVELS.slice(LOG_LEVELS.indexOf(level)) : []; LoggingRepository.logLevels = level ? LOG_LEVELS.slice(LOG_LEVELS.indexOf(level)) : [];
} }
protected formatContext(context: string): string { protected formatContext(context: string): string {
let prefix = LoggerRepository.appName || ''; let prefix = LoggingRepository.appName || '';
if (context) { if (context) {
prefix += (prefix ? ':' : '') + context; prefix += (prefix ? ':' : '') + context;
} }

View File

@ -1,7 +1,6 @@
import { Inject, Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { readFile } from 'node:fs/promises'; import { readFile } from 'node:fs/promises';
import { CLIPConfig } from 'src/dtos/model-config.dto'; import { CLIPConfig } from 'src/dtos/model-config.dto';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { import {
ClipTextualResponse, ClipTextualResponse,
ClipVisualResponse, ClipVisualResponse,
@ -13,10 +12,11 @@ import {
ModelTask, ModelTask,
ModelType, ModelType,
} from 'src/interfaces/machine-learning.interface'; } from 'src/interfaces/machine-learning.interface';
import { LoggingRepository } from 'src/repositories/logging.repository';
@Injectable() @Injectable()
export class MachineLearningRepository implements IMachineLearningRepository { export class MachineLearningRepository implements IMachineLearningRepository {
constructor(@Inject(ILoggerRepository) private logger: ILoggerRepository) { constructor(private logger: LoggingRepository) {
this.logger.setContext(MachineLearningRepository.name); this.logger.setContext(MachineLearningRepository.name);
} }

View File

@ -11,7 +11,6 @@ import { DB, GeodataPlaces, NaturalearthCountries } from 'src/db';
import { AssetEntity, withExif } from 'src/entities/asset.entity'; import { AssetEntity, withExif } from 'src/entities/asset.entity';
import { NaturalEarthCountriesTempEntity } from 'src/entities/natural-earth-countries.entity'; import { NaturalEarthCountriesTempEntity } from 'src/entities/natural-earth-countries.entity';
import { LogLevel, SystemMetadataKey } from 'src/enum'; import { LogLevel, SystemMetadataKey } from 'src/enum';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { import {
GeoPoint, GeoPoint,
IMapRepository, IMapRepository,
@ -21,6 +20,7 @@ import {
} from 'src/interfaces/map.interface'; } from 'src/interfaces/map.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { ConfigRepository } from 'src/repositories/config.repository'; import { ConfigRepository } from 'src/repositories/config.repository';
import { LoggingRepository } from 'src/repositories/logging.repository';
interface MapDB extends DB { interface MapDB extends DB {
geodata_places_tmp: GeodataPlaces; geodata_places_tmp: GeodataPlaces;
@ -32,7 +32,7 @@ export class MapRepository implements IMapRepository {
constructor( constructor(
private configRepository: ConfigRepository, private configRepository: ConfigRepository,
@Inject(ISystemMetadataRepository) private metadataRepository: ISystemMetadataRepository, @Inject(ISystemMetadataRepository) private metadataRepository: ISystemMetadataRepository,
@Inject(ILoggerRepository) private logger: ILoggerRepository, private logger: LoggingRepository,
@InjectKysely() private db: Kysely<MapDB>, @InjectKysely() private db: Kysely<MapDB>,
) { ) {
this.logger.setContext(MapRepository.name); this.logger.setContext(MapRepository.name);

View File

@ -1,4 +1,4 @@
import { Inject, Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { exiftool } from 'exiftool-vendored'; import { exiftool } from 'exiftool-vendored';
import ffmpeg, { FfprobeData } from 'fluent-ffmpeg'; import ffmpeg, { FfprobeData } from 'fluent-ffmpeg';
import { Duration } from 'luxon'; import { Duration } from 'luxon';
@ -7,7 +7,7 @@ import { Writable } from 'node:stream';
import sharp from 'sharp'; import sharp from 'sharp';
import { ORIENTATION_TO_SHARP_ROTATION } from 'src/constants'; import { ORIENTATION_TO_SHARP_ROTATION } from 'src/constants';
import { Colorspace, LogLevel } from 'src/enum'; import { Colorspace, LogLevel } from 'src/enum';
import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { LoggingRepository } from 'src/repositories/logging.repository';
import { import {
DecodeToBufferOptions, DecodeToBufferOptions,
GenerateThumbhashOptions, GenerateThumbhashOptions,
@ -37,7 +37,7 @@ type ProgressEvent = {
@Injectable() @Injectable()
export class MediaRepository { export class MediaRepository {
constructor(@Inject(ILoggerRepository) private logger: ILoggerRepository) { constructor(private logger: LoggingRepository) {
this.logger.setContext(MediaRepository.name); this.logger.setContext(MediaRepository.name);
} }

View File

@ -1,8 +1,8 @@
import { Inject, Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { DefaultReadTaskOptions, ExifTool, Tags } from 'exiftool-vendored'; import { DefaultReadTaskOptions, ExifTool, Tags } from 'exiftool-vendored';
import geotz from 'geo-tz'; import geotz from 'geo-tz';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IMetadataRepository, ImmichTags } from 'src/interfaces/metadata.interface'; import { IMetadataRepository, ImmichTags } from 'src/interfaces/metadata.interface';
import { LoggingRepository } from 'src/repositories/logging.repository';
@Injectable() @Injectable()
export class MetadataRepository implements IMetadataRepository { export class MetadataRepository implements IMetadataRepository {
@ -20,7 +20,7 @@ export class MetadataRepository implements IMetadataRepository {
writeArgs: ['-api', 'largefilesupport=1', '-overwrite_original'], writeArgs: ['-api', 'largefilesupport=1', '-overwrite_original'],
}); });
constructor(@Inject(ILoggerRepository) private logger: ILoggerRepository) { constructor(private logger: LoggingRepository) {
this.logger.setContext(MetadataRepository.name); this.logger.setContext(MetadataRepository.name);
} }

View File

@ -1,19 +1,18 @@
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { EmailRenderRequest, EmailTemplate } from 'src/interfaces/notification.interface'; import { EmailRenderRequest, EmailTemplate } from 'src/interfaces/notification.interface';
import { LoggingRepository } from 'src/repositories/logging.repository';
import { NotificationRepository } from 'src/repositories/notification.repository'; import { NotificationRepository } from 'src/repositories/notification.repository';
import { ILoggingRepository } from 'src/types';
import { newLoggingRepositoryMock } from 'test/repositories/logger.repository.mock';
import { Mocked } from 'vitest'; import { Mocked } from 'vitest';
describe(NotificationRepository.name, () => { describe(NotificationRepository.name, () => {
let sut: NotificationRepository; let sut: NotificationRepository;
let loggerMock: Mocked<ILoggerRepository>; let loggerMock: Mocked<ILoggingRepository>;
beforeEach(() => { beforeEach(() => {
loggerMock = { loggerMock = newLoggingRepositoryMock();
setContext: vitest.fn(),
debug: vitest.fn(),
} as unknown as Mocked<ILoggerRepository>;
sut = new NotificationRepository(loggerMock); sut = new NotificationRepository(loggerMock as ILoggingRepository as LoggingRepository);
}); });
describe('renderEmail', () => { describe('renderEmail', () => {

View File

@ -1,4 +1,4 @@
import { Inject, Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { render } from '@react-email/render'; import { render } from '@react-email/render';
import { createTransport } from 'nodemailer'; import { createTransport } from 'nodemailer';
import React from 'react'; import React from 'react';
@ -6,7 +6,6 @@ import { AlbumInviteEmail } from 'src/emails/album-invite.email';
import { AlbumUpdateEmail } from 'src/emails/album-update.email'; import { AlbumUpdateEmail } from 'src/emails/album-update.email';
import { TestEmail } from 'src/emails/test.email'; import { TestEmail } from 'src/emails/test.email';
import { WelcomeEmail } from 'src/emails/welcome.email'; import { WelcomeEmail } from 'src/emails/welcome.email';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { import {
EmailRenderRequest, EmailRenderRequest,
EmailTemplate, EmailTemplate,
@ -15,10 +14,11 @@ import {
SendEmailResponse, SendEmailResponse,
SmtpOptions, SmtpOptions,
} from 'src/interfaces/notification.interface'; } from 'src/interfaces/notification.interface';
import { LoggingRepository } from 'src/repositories/logging.repository';
@Injectable() @Injectable()
export class NotificationRepository implements INotificationRepository { export class NotificationRepository implements INotificationRepository {
constructor(@Inject(ILoggerRepository) private logger: ILoggerRepository) { constructor(private logger: LoggingRepository) {
this.logger.setContext(NotificationRepository.name); this.logger.setContext(NotificationRepository.name);
} }

View File

@ -1,11 +1,11 @@
import { Inject, Injectable, InternalServerErrorException } from '@nestjs/common'; import { Injectable, InternalServerErrorException } from '@nestjs/common';
import { custom, generators, Issuer } from 'openid-client'; import { custom, generators, Issuer } from 'openid-client';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IOAuthRepository, OAuthConfig, OAuthProfile } from 'src/interfaces/oauth.interface'; import { IOAuthRepository, OAuthConfig, OAuthProfile } from 'src/interfaces/oauth.interface';
import { LoggingRepository } from 'src/repositories/logging.repository';
@Injectable() @Injectable()
export class OAuthRepository implements IOAuthRepository { export class OAuthRepository implements IOAuthRepository {
constructor(@Inject(ILoggerRepository) private logger: ILoggerRepository) { constructor(private logger: LoggingRepository) {
this.logger.setContext(OAuthRepository.name); this.logger.setContext(OAuthRepository.name);
} }

View File

@ -1,12 +1,12 @@
import { Inject, Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { ChildProcessWithoutNullStreams, spawn, SpawnOptionsWithoutStdio } from 'node:child_process'; import { ChildProcessWithoutNullStreams, spawn, SpawnOptionsWithoutStdio } from 'node:child_process';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IProcessRepository } from 'src/interfaces/process.interface'; import { IProcessRepository } from 'src/interfaces/process.interface';
import { LoggingRepository } from 'src/repositories/logging.repository';
import { StorageRepository } from 'src/repositories/storage.repository'; import { StorageRepository } from 'src/repositories/storage.repository';
@Injectable() @Injectable()
export class ProcessRepository implements IProcessRepository { export class ProcessRepository implements IProcessRepository {
constructor(@Inject(ILoggerRepository) private logger: ILoggerRepository) { constructor(private logger: LoggingRepository) {
this.logger.setContext(StorageRepository.name); this.logger.setContext(StorageRepository.name);
} }

View File

@ -1,4 +1,4 @@
import { Inject, Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { Kysely, OrderByDirectionExpression, sql } from 'kysely'; import { Kysely, OrderByDirectionExpression, sql } from 'kysely';
import { InjectKysely } from 'nestjs-kysely'; import { InjectKysely } from 'nestjs-kysely';
import { randomUUID } from 'node:crypto'; import { randomUUID } from 'node:crypto';
@ -7,7 +7,6 @@ import { DummyValue, GenerateSql } from 'src/decorators';
import { AssetEntity, searchAssetBuilder } from 'src/entities/asset.entity'; import { AssetEntity, searchAssetBuilder } from 'src/entities/asset.entity';
import { GeodataPlacesEntity } from 'src/entities/geodata-places.entity'; import { GeodataPlacesEntity } from 'src/entities/geodata-places.entity';
import { AssetType } from 'src/enum'; import { AssetType } from 'src/enum';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { import {
AssetDuplicateSearch, AssetDuplicateSearch,
AssetSearchOptions, AssetSearchOptions,
@ -20,6 +19,7 @@ import {
SearchPaginationOptions, SearchPaginationOptions,
SmartSearchOptions, SmartSearchOptions,
} from 'src/interfaces/search.interface'; } from 'src/interfaces/search.interface';
import { LoggingRepository } from 'src/repositories/logging.repository';
import { anyUuid, asUuid } from 'src/utils/database'; import { anyUuid, asUuid } from 'src/utils/database';
import { Paginated } from 'src/utils/pagination'; import { Paginated } from 'src/utils/pagination';
import { isValidInteger } from 'src/validation'; import { isValidInteger } from 'src/validation';
@ -27,7 +27,7 @@ import { isValidInteger } from 'src/validation';
@Injectable() @Injectable()
export class SearchRepository implements ISearchRepository { export class SearchRepository implements ISearchRepository {
constructor( constructor(
@Inject(ILoggerRepository) private logger: ILoggerRepository, private logger: LoggingRepository,
@InjectKysely() private db: Kysely<DB>, @InjectKysely() private db: Kysely<DB>,
) { ) {
this.logger.setContext(SearchRepository.name); this.logger.setContext(SearchRepository.name);

View File

@ -1,12 +1,12 @@
import { Inject, Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { exiftool } from 'exiftool-vendored'; import { exiftool } from 'exiftool-vendored';
import { exec as execCallback } from 'node:child_process'; import { exec as execCallback } from 'node:child_process';
import { readFile } from 'node:fs/promises'; import { readFile } from 'node:fs/promises';
import { promisify } from 'node:util'; import { promisify } from 'node:util';
import sharp from 'sharp'; import sharp from 'sharp';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { GitHubRelease, IServerInfoRepository, ServerBuildVersions } from 'src/interfaces/server-info.interface'; import { GitHubRelease, IServerInfoRepository, ServerBuildVersions } from 'src/interfaces/server-info.interface';
import { ConfigRepository } from 'src/repositories/config.repository'; import { ConfigRepository } from 'src/repositories/config.repository';
import { LoggingRepository } from 'src/repositories/logging.repository';
const exec = promisify(execCallback); const exec = promisify(execCallback);
const maybeFirstLine = async (command: string): Promise<string> => { const maybeFirstLine = async (command: string): Promise<string> => {
@ -37,7 +37,7 @@ const getLockfileVersion = (name: string, lockfile?: BuildLockfile) => {
export class ServerInfoRepository implements IServerInfoRepository { export class ServerInfoRepository implements IServerInfoRepository {
constructor( constructor(
private configRepository: ConfigRepository, private configRepository: ConfigRepository,
@Inject(ILoggerRepository) private logger: ILoggerRepository, private logger: LoggingRepository,
) { ) {
this.logger.setContext(ServerInfoRepository.name); this.logger.setContext(ServerInfoRepository.name);
} }

View File

@ -1,8 +1,9 @@
import mockfs from 'mock-fs'; import mockfs from 'mock-fs';
import { CrawlOptionsDto } from 'src/dtos/library.dto'; import { CrawlOptionsDto } from 'src/dtos/library.dto';
import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { LoggingRepository } from 'src/repositories/logging.repository';
import { StorageRepository } from 'src/repositories/storage.repository'; import { StorageRepository } from 'src/repositories/storage.repository';
import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; import { ILoggingRepository } from 'src/types';
import { newLoggingRepositoryMock } from 'test/repositories/logger.repository.mock';
interface Test { interface Test {
test: string; test: string;
@ -181,11 +182,11 @@ const tests: Test[] = [
describe(StorageRepository.name, () => { describe(StorageRepository.name, () => {
let sut: StorageRepository; let sut: StorageRepository;
let logger: ILoggerRepository; let logger: ILoggingRepository;
beforeEach(() => { beforeEach(() => {
logger = newLoggerRepositoryMock(); logger = newLoggingRepositoryMock();
sut = new StorageRepository(logger); sut = new StorageRepository(logger as LoggingRepository);
}); });
afterEach(() => { afterEach(() => {

View File

@ -1,4 +1,4 @@
import { Inject, Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import archiver from 'archiver'; import archiver from 'archiver';
import chokidar, { WatchOptions } from 'chokidar'; import chokidar, { WatchOptions } from 'chokidar';
import { escapePath, glob, globStream } from 'fast-glob'; import { escapePath, glob, globStream } from 'fast-glob';
@ -7,7 +7,6 @@ import fs from 'node:fs/promises';
import path from 'node:path'; import path from 'node:path';
import { Writable } from 'node:stream'; import { Writable } from 'node:stream';
import { CrawlOptionsDto, WalkOptionsDto } from 'src/dtos/library.dto'; import { CrawlOptionsDto, WalkOptionsDto } from 'src/dtos/library.dto';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { import {
DiskUsage, DiskUsage,
IStorageRepository, IStorageRepository,
@ -15,11 +14,12 @@ import {
ImmichZipStream, ImmichZipStream,
WatchEvents, WatchEvents,
} from 'src/interfaces/storage.interface'; } from 'src/interfaces/storage.interface';
import { LoggingRepository } from 'src/repositories/logging.repository';
import { mimeTypes } from 'src/utils/mime-types'; import { mimeTypes } from 'src/utils/mime-types';
@Injectable() @Injectable()
export class StorageRepository implements IStorageRepository { export class StorageRepository implements IStorageRepository {
constructor(@Inject(ILoggerRepository) private logger: ILoggerRepository) { constructor(private logger: LoggingRepository) {
this.logger.setContext(StorageRepository.name); this.logger.setContext(StorageRepository.name);
} }

View File

@ -1,18 +1,17 @@
import { Inject, Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
import { Chunked, ChunkedSet, DummyValue, GenerateSql } from 'src/decorators'; import { Chunked, ChunkedSet, DummyValue, GenerateSql } from 'src/decorators';
import { TagEntity } from 'src/entities/tag.entity'; import { TagEntity } from 'src/entities/tag.entity';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { AssetTagItem, ITagRepository } from 'src/interfaces/tag.interface'; import { AssetTagItem, ITagRepository } from 'src/interfaces/tag.interface';
import { DataSource, In, Repository, TreeRepository } from 'typeorm'; import { LoggingRepository } from 'src/repositories/logging.repository';
import { DataSource, In, Repository } from 'typeorm';
@Injectable() @Injectable()
export class TagRepository implements ITagRepository { export class TagRepository implements ITagRepository {
constructor( constructor(
@InjectDataSource() private dataSource: DataSource, @InjectDataSource() private dataSource: DataSource,
@InjectRepository(TagEntity) private repository: Repository<TagEntity>, @InjectRepository(TagEntity) private repository: Repository<TagEntity>,
@InjectRepository(TagEntity) private tree: TreeRepository<TagEntity>, private logger: LoggingRepository,
@Inject(ILoggerRepository) private logger: ILoggerRepository,
) { ) {
this.logger.setContext(TagRepository.name); this.logger.setContext(TagRepository.name);
} }

View File

@ -1,4 +1,4 @@
import { Inject, Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core'; import { Reflector } from '@nestjs/core';
import { MetricOptions } from '@opentelemetry/api'; import { MetricOptions } from '@opentelemetry/api';
import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks'; import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks';
@ -15,9 +15,9 @@ import { MetricService } from 'nestjs-otel';
import { copyMetadataFromFunctionToFunction } from 'nestjs-otel/lib/opentelemetry.utils'; import { copyMetadataFromFunctionToFunction } from 'nestjs-otel/lib/opentelemetry.utils';
import { serverVersion } from 'src/constants'; import { serverVersion } from 'src/constants';
import { ImmichTelemetry, MetadataKey } from 'src/enum'; import { ImmichTelemetry, MetadataKey } from 'src/enum';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IMetricGroupRepository, ITelemetryRepository, MetricGroupOptions } from 'src/interfaces/telemetry.interface'; import { IMetricGroupRepository, ITelemetryRepository, MetricGroupOptions } from 'src/interfaces/telemetry.interface';
import { ConfigRepository } from 'src/repositories/config.repository'; import { ConfigRepository } from 'src/repositories/config.repository';
import { LoggingRepository } from 'src/repositories/logging.repository';
class MetricGroupRepository implements IMetricGroupRepository { class MetricGroupRepository implements IMetricGroupRepository {
private enabled = false; private enabled = false;
@ -96,7 +96,7 @@ export class TelemetryRepository implements ITelemetryRepository {
private metricService: MetricService, private metricService: MetricService,
private reflect: Reflector, private reflect: Reflector,
private configRepository: ConfigRepository, private configRepository: ConfigRepository,
@Inject(ILoggerRepository) private logger: ILoggerRepository, private logger: LoggingRepository,
) { ) {
const { telemetry } = this.configRepository.getEnv(); const { telemetry } = this.configRepository.getEnv();
const { metrics } = telemetry; const { metrics } = telemetry;

View File

@ -1,10 +1,10 @@
import { Inject, Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { Cron, CronExpression, Interval } from '@nestjs/schedule'; import { Cron, CronExpression, Interval } from '@nestjs/schedule';
import { NextFunction, Request, Response } from 'express'; import { NextFunction, Request, Response } from 'express';
import { readFileSync } from 'node:fs'; import { readFileSync } from 'node:fs';
import { ONE_HOUR } from 'src/constants'; import { ONE_HOUR } from 'src/constants';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { ConfigRepository } from 'src/repositories/config.repository'; import { ConfigRepository } from 'src/repositories/config.repository';
import { LoggingRepository } from 'src/repositories/logging.repository';
import { AuthService } from 'src/services/auth.service'; import { AuthService } from 'src/services/auth.service';
import { JobService } from 'src/services/job.service'; import { JobService } from 'src/services/job.service';
import { SharedLinkService } from 'src/services/shared-link.service'; import { SharedLinkService } from 'src/services/shared-link.service';
@ -39,7 +39,7 @@ export class ApiService {
private sharedLinkService: SharedLinkService, private sharedLinkService: SharedLinkService,
private versionService: VersionService, private versionService: VersionService,
private configRepository: ConfigRepository, private configRepository: ConfigRepository,
@Inject(ILoggerRepository) private logger: ILoggerRepository, private logger: LoggingRepository,
) { ) {
this.logger.setContext(ApiService.name); this.logger.setContext(ApiService.name);
} }

View File

@ -15,7 +15,6 @@ import { IDatabaseRepository } from 'src/interfaces/database.interface';
import { IEventRepository } from 'src/interfaces/event.interface'; import { IEventRepository } from 'src/interfaces/event.interface';
import { IJobRepository } from 'src/interfaces/job.interface'; import { IJobRepository } from 'src/interfaces/job.interface';
import { ILibraryRepository } from 'src/interfaces/library.interface'; import { ILibraryRepository } from 'src/interfaces/library.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface'; import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface';
import { IMapRepository } from 'src/interfaces/map.interface'; import { IMapRepository } from 'src/interfaces/map.interface';
import { IMetadataRepository } from 'src/interfaces/metadata.interface'; import { IMetadataRepository } from 'src/interfaces/metadata.interface';
@ -42,6 +41,7 @@ import { ActivityRepository } from 'src/repositories/activity.repository';
import { ApiKeyRepository } from 'src/repositories/api-key.repository'; import { ApiKeyRepository } from 'src/repositories/api-key.repository';
import { AuditRepository } from 'src/repositories/audit.repository'; import { AuditRepository } from 'src/repositories/audit.repository';
import { ConfigRepository } from 'src/repositories/config.repository'; import { ConfigRepository } from 'src/repositories/config.repository';
import { LoggingRepository } from 'src/repositories/logging.repository';
import { MediaRepository } from 'src/repositories/media.repository'; import { MediaRepository } from 'src/repositories/media.repository';
import { MemoryRepository } from 'src/repositories/memory.repository'; import { MemoryRepository } from 'src/repositories/memory.repository';
import { ViewRepository } from 'src/repositories/view-repository'; import { ViewRepository } from 'src/repositories/view-repository';
@ -52,7 +52,7 @@ export class BaseService {
protected storageCore: StorageCore; protected storageCore: StorageCore;
constructor( constructor(
@Inject(ILoggerRepository) protected logger: ILoggerRepository, protected logger: LoggingRepository,
protected accessRepository: AccessRepository, protected accessRepository: AccessRepository,
protected activityRepository: ActivityRepository, protected activityRepository: ActivityRepository,
protected auditRepository: AuditRepository, protected auditRepository: AuditRepository,

View File

@ -5,9 +5,8 @@ import {
IDatabaseRepository, IDatabaseRepository,
VectorExtension, VectorExtension,
} from 'src/interfaces/database.interface'; } from 'src/interfaces/database.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { DatabaseService } from 'src/services/database.service'; import { DatabaseService } from 'src/services/database.service';
import { IConfigRepository } from 'src/types'; import { IConfigRepository, ILoggingRepository } from 'src/types';
import { mockEnvData } from 'test/repositories/config.repository.mock'; import { mockEnvData } from 'test/repositories/config.repository.mock';
import { newTestService } from 'test/utils'; import { newTestService } from 'test/utils';
import { Mocked } from 'vitest'; import { Mocked } from 'vitest';
@ -17,7 +16,7 @@ describe(DatabaseService.name, () => {
let configMock: Mocked<IConfigRepository>; let configMock: Mocked<IConfigRepository>;
let databaseMock: Mocked<IDatabaseRepository>; let databaseMock: Mocked<IDatabaseRepository>;
let loggerMock: Mocked<ILoggerRepository>; let loggerMock: Mocked<ILoggingRepository>;
let extensionRange: string; let extensionRange: string;
let versionBelowRange: string; let versionBelowRange: string;
let minVersionInRange: string; let minVersionInRange: string;

View File

@ -2,9 +2,9 @@ import { BadRequestException } from '@nestjs/common';
import { DownloadResponseDto } from 'src/dtos/download.dto'; import { DownloadResponseDto } from 'src/dtos/download.dto';
import { AssetEntity } from 'src/entities/asset.entity'; import { AssetEntity } from 'src/entities/asset.entity';
import { IAssetRepository } from 'src/interfaces/asset.interface'; import { IAssetRepository } from 'src/interfaces/asset.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface';
import { DownloadService } from 'src/services/download.service'; import { DownloadService } from 'src/services/download.service';
import { ILoggingRepository } from 'src/types';
import { assetStub } from 'test/fixtures/asset.stub'; import { assetStub } from 'test/fixtures/asset.stub';
import { authStub } from 'test/fixtures/auth.stub'; import { authStub } from 'test/fixtures/auth.stub';
import { IAccessRepositoryMock } from 'test/repositories/access.repository.mock'; import { IAccessRepositoryMock } from 'test/repositories/access.repository.mock';
@ -26,7 +26,7 @@ describe(DownloadService.name, () => {
let sut: DownloadService; let sut: DownloadService;
let accessMock: IAccessRepositoryMock; let accessMock: IAccessRepositoryMock;
let assetMock: Mocked<IAssetRepository>; let assetMock: Mocked<IAssetRepository>;
let loggerMock: Mocked<ILoggerRepository>; let loggerMock: Mocked<ILoggingRepository>;
let storageMock: Mocked<IStorageRepository>; let storageMock: Mocked<IStorageRepository>;
it('should work', () => { it('should work', () => {

View File

@ -1,10 +1,10 @@
import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface'; import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface';
import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface'; import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { ISearchRepository } from 'src/interfaces/search.interface'; import { ISearchRepository } from 'src/interfaces/search.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { DuplicateService } from 'src/services/duplicate.service'; import { DuplicateService } from 'src/services/duplicate.service';
import { SearchService } from 'src/services/search.service'; import { SearchService } from 'src/services/search.service';
import { ILoggingRepository } from 'src/types';
import { assetStub } from 'test/fixtures/asset.stub'; import { assetStub } from 'test/fixtures/asset.stub';
import { authStub } from 'test/fixtures/auth.stub'; import { authStub } from 'test/fixtures/auth.stub';
import { newTestService } from 'test/utils'; import { newTestService } from 'test/utils';
@ -17,7 +17,7 @@ describe(SearchService.name, () => {
let assetMock: Mocked<IAssetRepository>; let assetMock: Mocked<IAssetRepository>;
let jobMock: Mocked<IJobRepository>; let jobMock: Mocked<IJobRepository>;
let loggerMock: Mocked<ILoggerRepository>; let loggerMock: Mocked<ILoggingRepository>;
let searchMock: Mocked<ISearchRepository>; let searchMock: Mocked<ISearchRepository>;
let systemMock: Mocked<ISystemMetadataRepository>; let systemMock: Mocked<ISystemMetadataRepository>;

View File

@ -3,10 +3,9 @@ import { defaults, SystemConfig } from 'src/config';
import { ImmichWorker } from 'src/enum'; import { ImmichWorker } from 'src/enum';
import { IAssetRepository } from 'src/interfaces/asset.interface'; import { IAssetRepository } from 'src/interfaces/asset.interface';
import { IJobRepository, JobCommand, JobItem, JobName, JobStatus, QueueName } from 'src/interfaces/job.interface'; import { IJobRepository, JobCommand, JobItem, JobName, JobStatus, QueueName } from 'src/interfaces/job.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { ITelemetryRepository } from 'src/interfaces/telemetry.interface'; import { ITelemetryRepository } from 'src/interfaces/telemetry.interface';
import { JobService } from 'src/services/job.service'; import { JobService } from 'src/services/job.service';
import { IConfigRepository } from 'src/types'; import { IConfigRepository, ILoggingRepository } from 'src/types';
import { assetStub } from 'test/fixtures/asset.stub'; import { assetStub } from 'test/fixtures/asset.stub';
import { newTestService } from 'test/utils'; import { newTestService } from 'test/utils';
import { Mocked } from 'vitest'; import { Mocked } from 'vitest';
@ -16,7 +15,7 @@ describe(JobService.name, () => {
let assetMock: Mocked<IAssetRepository>; let assetMock: Mocked<IAssetRepository>;
let configMock: Mocked<IConfigRepository>; let configMock: Mocked<IConfigRepository>;
let jobMock: Mocked<IJobRepository>; let jobMock: Mocked<IJobRepository>;
let loggerMock: Mocked<ILoggerRepository>; let loggerMock: Mocked<ILoggingRepository>;
let telemetryMock: Mocked<ITelemetryRepository>; let telemetryMock: Mocked<ITelemetryRepository>;
beforeEach(() => { beforeEach(() => {

View File

@ -15,13 +15,12 @@ import {
} from 'src/enum'; } from 'src/enum';
import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface'; import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface';
import { IJobRepository, JobCounts, JobName, JobStatus } from 'src/interfaces/job.interface'; import { IJobRepository, JobCounts, JobName, JobStatus } from 'src/interfaces/job.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IMoveRepository } from 'src/interfaces/move.interface'; import { IMoveRepository } from 'src/interfaces/move.interface';
import { IPersonRepository } from 'src/interfaces/person.interface'; import { IPersonRepository } from 'src/interfaces/person.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { MediaService } from 'src/services/media.service'; import { MediaService } from 'src/services/media.service';
import { IMediaRepository, RawImageInfo } from 'src/types'; import { ILoggingRepository, IMediaRepository, RawImageInfo } from 'src/types';
import { assetStub } from 'test/fixtures/asset.stub'; import { assetStub } from 'test/fixtures/asset.stub';
import { faceStub } from 'test/fixtures/face.stub'; import { faceStub } from 'test/fixtures/face.stub';
import { probeStub } from 'test/fixtures/media.stub'; import { probeStub } from 'test/fixtures/media.stub';
@ -34,7 +33,7 @@ describe(MediaService.name, () => {
let assetMock: Mocked<IAssetRepository>; let assetMock: Mocked<IAssetRepository>;
let jobMock: Mocked<IJobRepository>; let jobMock: Mocked<IJobRepository>;
let loggerMock: Mocked<ILoggerRepository>; let loggerMock: Mocked<ILoggingRepository>;
let mediaMock: Mocked<IMediaRepository>; let mediaMock: Mocked<IMediaRepository>;
let moveMock: Mocked<IMoveRepository>; let moveMock: Mocked<IMoveRepository>;
let personMock: Mocked<IPersonRepository>; let personMock: Mocked<IPersonRepository>;

View File

@ -1,9 +1,8 @@
import { SystemMetadataKey } from 'src/enum'; import { SystemMetadataKey } from 'src/enum';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { StorageService } from 'src/services/storage.service'; import { StorageService } from 'src/services/storage.service';
import { IConfigRepository } from 'src/types'; import { IConfigRepository, ILoggingRepository } from 'src/types';
import { ImmichStartupError } from 'src/utils/misc'; import { ImmichStartupError } from 'src/utils/misc';
import { mockEnvData } from 'test/repositories/config.repository.mock'; import { mockEnvData } from 'test/repositories/config.repository.mock';
import { newTestService } from 'test/utils'; import { newTestService } from 'test/utils';
@ -13,7 +12,7 @@ describe(StorageService.name, () => {
let sut: StorageService; let sut: StorageService;
let configMock: Mocked<IConfigRepository>; let configMock: Mocked<IConfigRepository>;
let loggerMock: Mocked<ILoggerRepository>; let loggerMock: Mocked<ILoggingRepository>;
let storageMock: Mocked<IStorageRepository>; let storageMock: Mocked<IStorageRepository>;
let systemMock: Mocked<ISystemMetadataRepository>; let systemMock: Mocked<ISystemMetadataRepository>;

View File

@ -14,10 +14,9 @@ import {
} from 'src/enum'; } from 'src/enum';
import { IEventRepository } from 'src/interfaces/event.interface'; import { IEventRepository } from 'src/interfaces/event.interface';
import { QueueName } from 'src/interfaces/job.interface'; import { QueueName } from 'src/interfaces/job.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { SystemConfigService } from 'src/services/system-config.service'; import { SystemConfigService } from 'src/services/system-config.service';
import { DeepPartial, IConfigRepository } from 'src/types'; import { DeepPartial, IConfigRepository, ILoggingRepository } from 'src/types';
import { mockEnvData } from 'test/repositories/config.repository.mock'; import { mockEnvData } from 'test/repositories/config.repository.mock';
import { newTestService } from 'test/utils'; import { newTestService } from 'test/utils';
import { Mocked } from 'vitest'; import { Mocked } from 'vitest';
@ -203,7 +202,7 @@ describe(SystemConfigService.name, () => {
let configMock: Mocked<IConfigRepository>; let configMock: Mocked<IConfigRepository>;
let eventMock: Mocked<IEventRepository>; let eventMock: Mocked<IEventRepository>;
let loggerMock: Mocked<ILoggerRepository>; let loggerMock: Mocked<ILoggingRepository>;
let systemMock: Mocked<ISystemMetadataRepository>; let systemMock: Mocked<ISystemMetadataRepository>;
beforeEach(() => { beforeEach(() => {

View File

@ -4,12 +4,11 @@ import { serverVersion } from 'src/constants';
import { ImmichEnvironment, SystemMetadataKey } from 'src/enum'; import { ImmichEnvironment, SystemMetadataKey } from 'src/enum';
import { IEventRepository } from 'src/interfaces/event.interface'; import { IEventRepository } from 'src/interfaces/event.interface';
import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface'; import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IServerInfoRepository } from 'src/interfaces/server-info.interface'; import { IServerInfoRepository } from 'src/interfaces/server-info.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { IVersionHistoryRepository } from 'src/interfaces/version-history.interface'; import { IVersionHistoryRepository } from 'src/interfaces/version-history.interface';
import { VersionService } from 'src/services/version.service'; import { VersionService } from 'src/services/version.service';
import { IConfigRepository } from 'src/types'; import { IConfigRepository, ILoggingRepository } from 'src/types';
import { mockEnvData } from 'test/repositories/config.repository.mock'; import { mockEnvData } from 'test/repositories/config.repository.mock';
import { newTestService } from 'test/utils'; import { newTestService } from 'test/utils';
import { Mocked } from 'vitest'; import { Mocked } from 'vitest';
@ -30,7 +29,7 @@ describe(VersionService.name, () => {
let configMock: Mocked<IConfigRepository>; let configMock: Mocked<IConfigRepository>;
let eventMock: Mocked<IEventRepository>; let eventMock: Mocked<IEventRepository>;
let jobMock: Mocked<IJobRepository>; let jobMock: Mocked<IJobRepository>;
let loggerMock: Mocked<ILoggerRepository>; let loggerMock: Mocked<ILoggingRepository>;
let serverInfoMock: Mocked<IServerInfoRepository>; let serverInfoMock: Mocked<IServerInfoRepository>;
let systemMock: Mocked<ISystemMetadataRepository>; let systemMock: Mocked<ISystemMetadataRepository>;
let versionHistoryMock: Mocked<IVersionHistoryRepository>; let versionHistoryMock: Mocked<IVersionHistoryRepository>;

View File

@ -5,6 +5,7 @@ import { ActivityRepository } from 'src/repositories/activity.repository';
import { ApiKeyRepository } from 'src/repositories/api-key.repository'; import { ApiKeyRepository } from 'src/repositories/api-key.repository';
import { AuditRepository } from 'src/repositories/audit.repository'; import { AuditRepository } from 'src/repositories/audit.repository';
import { ConfigRepository } from 'src/repositories/config.repository'; import { ConfigRepository } from 'src/repositories/config.repository';
import { LoggingRepository } from 'src/repositories/logging.repository';
import { MediaRepository } from 'src/repositories/media.repository'; import { MediaRepository } from 'src/repositories/media.repository';
import { MemoryRepository } from 'src/repositories/memory.repository'; import { MemoryRepository } from 'src/repositories/memory.repository';
import { ViewRepository } from 'src/repositories/view-repository'; import { ViewRepository } from 'src/repositories/view-repository';
@ -25,6 +26,19 @@ export type IAccessRepository = { [K in keyof AccessRepository]: RepositoryInter
export type IApiKeyRepository = RepositoryInterface<ApiKeyRepository>; export type IApiKeyRepository = RepositoryInterface<ApiKeyRepository>;
export type IAuditRepository = RepositoryInterface<AuditRepository>; export type IAuditRepository = RepositoryInterface<AuditRepository>;
export type IConfigRepository = RepositoryInterface<ConfigRepository>; export type IConfigRepository = RepositoryInterface<ConfigRepository>;
export type ILoggingRepository = Pick<
LoggingRepository,
| 'verbose'
| 'log'
| 'debug'
| 'warn'
| 'error'
| 'fatal'
| 'isLevelEnabled'
| 'setLogLevel'
| 'setContext'
| 'setAppName'
>;
export type IMediaRepository = RepositoryInterface<MediaRepository>; export type IMediaRepository = RepositoryInterface<MediaRepository>;
export type IMemoryRepository = RepositoryInterface<MemoryRepository>; export type IMemoryRepository = RepositoryInterface<MemoryRepository>;
export type IViewRepository = RepositoryInterface<ViewRepository>; export type IViewRepository = RepositoryInterface<ViewRepository>;

View File

@ -7,9 +7,8 @@ import { SystemConfig, defaults } from 'src/config';
import { SystemConfigDto } from 'src/dtos/system-config.dto'; import { SystemConfigDto } from 'src/dtos/system-config.dto';
import { SystemMetadataKey } from 'src/enum'; import { SystemMetadataKey } from 'src/enum';
import { DatabaseLock } from 'src/interfaces/database.interface'; import { DatabaseLock } from 'src/interfaces/database.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface'; import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { DeepPartial, IConfigRepository } from 'src/types'; import { DeepPartial, IConfigRepository, ILoggingRepository } from 'src/types';
import { getKeysDeep, unsetDeep } from 'src/utils/misc'; import { getKeysDeep, unsetDeep } from 'src/utils/misc';
export type SystemConfigValidator = (config: SystemConfig, newConfig: SystemConfig) => void | Promise<void>; export type SystemConfigValidator = (config: SystemConfig, newConfig: SystemConfig) => void | Promise<void>;
@ -17,7 +16,7 @@ export type SystemConfigValidator = (config: SystemConfig, newConfig: SystemConf
type RepoDeps = { type RepoDeps = {
configRepo: IConfigRepository; configRepo: IConfigRepository;
metadataRepo: ISystemMetadataRepository; metadataRepo: ISystemMetadataRepository;
logger: ILoggerRepository; logger: ILoggingRepository;
}; };
const asyncLock = new AsyncLock(); const asyncLock = new AsyncLock();

View File

@ -4,8 +4,8 @@ import { access, constants } from 'node:fs/promises';
import { basename, extname, isAbsolute } from 'node:path'; import { basename, extname, isAbsolute } from 'node:path';
import { promisify } from 'node:util'; import { promisify } from 'node:util';
import { CacheControl } from 'src/enum'; import { CacheControl } from 'src/enum';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { ImmichReadStream } from 'src/interfaces/storage.interface'; import { ImmichReadStream } from 'src/interfaces/storage.interface';
import { ILoggingRepository } from 'src/types';
import { isConnectionAborted } from 'src/utils/misc'; import { isConnectionAborted } from 'src/utils/misc';
export function getFileNameWithoutExtension(path: string): string { export function getFileNameWithoutExtension(path: string): string {
@ -37,7 +37,7 @@ export const sendFile = async (
res: Response, res: Response,
next: NextFunction, next: NextFunction,
handler: () => Promise<ImmichFileResponse>, handler: () => Promise<ImmichFileResponse>,
logger: ILoggerRepository, logger: ILoggingRepository,
): Promise<void> => { ): Promise<void> => {
const _sendFile = (path: string, options: SendFileOptions) => const _sendFile = (path: string, options: SendFileOptions) =>
promisify<string, SendFileOptions>(res.sendFile).bind(res)(path, options); promisify<string, SendFileOptions>(res.sendFile).bind(res)(path, options);

View File

@ -1,8 +1,8 @@
import { HttpException } from '@nestjs/common'; import { HttpException } from '@nestjs/common';
import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { ILoggingRepository } from 'src/types';
import { TypeORMError } from 'typeorm'; import { TypeORMError } from 'typeorm';
export const logGlobalError = (logger: ILoggerRepository, error: Error) => { export const logGlobalError = (logger: ILoggingRepository, error: Error) => {
if (error instanceof HttpException) { if (error instanceof HttpException) {
const status = error.getStatus(); const status = error.getStatus();
const response = error.getResponse(); const response = error.getResponse();

View File

@ -13,7 +13,7 @@ import path from 'node:path';
import { SystemConfig } from 'src/config'; import { SystemConfig } from 'src/config';
import { CLIP_MODEL_INFO, serverVersion } from 'src/constants'; import { CLIP_MODEL_INFO, serverVersion } from 'src/constants';
import { ImmichCookie, ImmichHeader, MetadataKey } from 'src/enum'; import { ImmichCookie, ImmichHeader, MetadataKey } from 'src/enum';
import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { ILoggingRepository } from 'src/types';
export class ImmichStartupError extends Error {} export class ImmichStartupError extends Error {}
export const isStartUpError = (error: unknown): error is ImmichStartupError => error instanceof ImmichStartupError; export const isStartUpError = (error: unknown): error is ImmichStartupError => error instanceof ImmichStartupError;
@ -96,7 +96,7 @@ export const isFaceImportEnabled = (metadata: SystemConfig['metadata']) => metad
export const isConnectionAborted = (error: Error | any) => error.code === 'ECONNABORTED'; export const isConnectionAborted = (error: Error | any) => error.code === 'ECONNABORTED';
export const handlePromiseError = <T>(promise: Promise<T>, logger: ILoggerRepository): void => { export const handlePromiseError = <T>(promise: Promise<T>, logger: ILoggingRepository): void => {
promise.catch((error: Error | any) => logger.error(`Promise error: ${error}`, error?.stack)); promise.catch((error: Error | any) => logger.error(`Promise error: ${error}`, error?.stack));
}; };

View File

@ -7,9 +7,9 @@ import sirv from 'sirv';
import { ApiModule } from 'src/app.module'; import { ApiModule } from 'src/app.module';
import { excludePaths, serverVersion } from 'src/constants'; import { excludePaths, serverVersion } from 'src/constants';
import { ImmichEnvironment } from 'src/enum'; import { ImmichEnvironment } from 'src/enum';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { WebSocketAdapter } from 'src/middleware/websocket.adapter'; import { WebSocketAdapter } from 'src/middleware/websocket.adapter';
import { ConfigRepository } from 'src/repositories/config.repository'; import { ConfigRepository } from 'src/repositories/config.repository';
import { LoggingRepository } from 'src/repositories/logging.repository';
import { bootstrapTelemetry } from 'src/repositories/telemetry.repository'; import { bootstrapTelemetry } from 'src/repositories/telemetry.repository';
import { ApiService } from 'src/services/api.service'; import { ApiService } from 'src/services/api.service';
import { isStartUpError, useSwagger } from 'src/utils/misc'; import { isStartUpError, useSwagger } from 'src/utils/misc';
@ -23,7 +23,7 @@ async function bootstrap() {
} }
const app = await NestFactory.create<NestExpressApplication>(ApiModule, { bufferLogs: true }); const app = await NestFactory.create<NestExpressApplication>(ApiModule, { bufferLogs: true });
const logger = await app.resolve<ILoggerRepository>(ILoggerRepository); const logger = await app.resolve(LoggingRepository);
const configRepository = app.get(ConfigRepository); const configRepository = app.get(ConfigRepository);
const { environment, host, port, resourcePaths } = configRepository.getEnv(); const { environment, host, port, resourcePaths } = configRepository.getEnv();

View File

@ -2,9 +2,9 @@ import { NestFactory } from '@nestjs/core';
import { isMainThread } from 'node:worker_threads'; import { isMainThread } from 'node:worker_threads';
import { MicroservicesModule } from 'src/app.module'; import { MicroservicesModule } from 'src/app.module';
import { serverVersion } from 'src/constants'; import { serverVersion } from 'src/constants';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { WebSocketAdapter } from 'src/middleware/websocket.adapter'; import { WebSocketAdapter } from 'src/middleware/websocket.adapter';
import { ConfigRepository } from 'src/repositories/config.repository'; import { ConfigRepository } from 'src/repositories/config.repository';
import { LoggingRepository } from 'src/repositories/logging.repository';
import { bootstrapTelemetry } from 'src/repositories/telemetry.repository'; import { bootstrapTelemetry } from 'src/repositories/telemetry.repository';
import { isStartUpError } from 'src/utils/misc'; import { isStartUpError } from 'src/utils/misc';
@ -15,7 +15,7 @@ export async function bootstrap() {
} }
const app = await NestFactory.create(MicroservicesModule, { bufferLogs: true }); const app = await NestFactory.create(MicroservicesModule, { bufferLogs: true });
const logger = await app.resolve(ILoggerRepository); const logger = await app.resolve(LoggingRepository);
logger.setContext('Bootstrap'); logger.setContext('Bootstrap');
app.useLogger(logger); app.useLogger(logger);
app.useWebSocketAdapter(new WebSocketAdapter(app)); app.useWebSocketAdapter(new WebSocketAdapter(app));

View File

@ -5,13 +5,17 @@ import { join } from 'node:path';
import { AssetEntity } from 'src/entities/asset.entity'; import { AssetEntity } from 'src/entities/asset.entity';
import { IAssetRepository } from 'src/interfaces/asset.interface'; import { IAssetRepository } from 'src/interfaces/asset.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface'; import { IStorageRepository } from 'src/interfaces/storage.interface';
import { LoggingRepository } from 'src/repositories/logging.repository';
import { MetadataRepository } from 'src/repositories/metadata.repository'; import { MetadataRepository } from 'src/repositories/metadata.repository';
import { MetadataService } from 'src/services/metadata.service'; import { MetadataService } from 'src/services/metadata.service';
import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; import { ILoggingRepository } from 'src/types';
import { newLoggingRepositoryMock } from 'test/repositories/logger.repository.mock';
import { newRandomImage, newTestService } from 'test/utils'; import { newRandomImage, newTestService } from 'test/utils';
import { Mocked } from 'vitest'; import { Mocked } from 'vitest';
const metadataRepository = new MetadataRepository(newLoggerRepositoryMock()); const metadataRepository = new MetadataRepository(
newLoggingRepositoryMock() as ILoggingRepository as LoggingRepository,
);
const createTestFile = async (exifData: Record<string, any>) => { const createTestFile = async (exifData: Record<string, any>) => {
const data = newRandomImage(); const data = newRandomImage();

View File

@ -1,7 +1,7 @@
import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { ILoggingRepository } from 'src/types';
import { Mocked, vitest } from 'vitest'; import { Mocked, vitest } from 'vitest';
export const newLoggerRepositoryMock = (): Mocked<ILoggerRepository> => { export const newLoggingRepositoryMock = (): Mocked<ILoggingRepository> => {
return { return {
setLogLevel: vitest.fn(), setLogLevel: vitest.fn(),
setContext: vitest.fn(), setContext: vitest.fn(),

View File

@ -7,6 +7,7 @@ import { AccessRepository } from 'src/repositories/access.repository';
import { ActivityRepository } from 'src/repositories/activity.repository'; import { ActivityRepository } from 'src/repositories/activity.repository';
import { ApiKeyRepository } from 'src/repositories/api-key.repository'; import { ApiKeyRepository } from 'src/repositories/api-key.repository';
import { AuditRepository } from 'src/repositories/audit.repository'; import { AuditRepository } from 'src/repositories/audit.repository';
import { LoggingRepository } from 'src/repositories/logging.repository';
import { MediaRepository } from 'src/repositories/media.repository'; import { MediaRepository } from 'src/repositories/media.repository';
import { MemoryRepository } from 'src/repositories/memory.repository'; import { MemoryRepository } from 'src/repositories/memory.repository';
import { ViewRepository } from 'src/repositories/view-repository'; import { ViewRepository } from 'src/repositories/view-repository';
@ -16,6 +17,7 @@ import {
IActivityRepository, IActivityRepository,
IApiKeyRepository, IApiKeyRepository,
IAuditRepository, IAuditRepository,
ILoggingRepository,
IMediaRepository, IMediaRepository,
IMemoryRepository, IMemoryRepository,
IViewRepository, IViewRepository,
@ -34,7 +36,7 @@ import { newDatabaseRepositoryMock } from 'test/repositories/database.repository
import { newEventRepositoryMock } from 'test/repositories/event.repository.mock'; import { newEventRepositoryMock } from 'test/repositories/event.repository.mock';
import { newJobRepositoryMock } from 'test/repositories/job.repository.mock'; import { newJobRepositoryMock } from 'test/repositories/job.repository.mock';
import { newLibraryRepositoryMock } from 'test/repositories/library.repository.mock'; import { newLibraryRepositoryMock } from 'test/repositories/library.repository.mock';
import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock'; import { newLoggingRepositoryMock } from 'test/repositories/logger.repository.mock';
import { newMachineLearningRepositoryMock } from 'test/repositories/machine-learning.repository.mock'; import { newMachineLearningRepositoryMock } from 'test/repositories/machine-learning.repository.mock';
import { newMapRepositoryMock } from 'test/repositories/map.repository.mock'; import { newMapRepositoryMock } from 'test/repositories/map.repository.mock';
import { newMediaRepositoryMock } from 'test/repositories/media.repository.mock'; import { newMediaRepositoryMock } from 'test/repositories/media.repository.mock';
@ -78,7 +80,7 @@ export const newTestService = <T extends BaseService>(
const { metadataRepository } = overrides || {}; const { metadataRepository } = overrides || {};
const accessMock = newAccessRepositoryMock(); const accessMock = newAccessRepositoryMock();
const loggerMock = newLoggerRepositoryMock(); const loggerMock = newLoggingRepositoryMock();
const cronMock = newCronRepositoryMock(); const cronMock = newCronRepositoryMock();
const cryptoMock = newCryptoRepositoryMock(); const cryptoMock = newCryptoRepositoryMock();
const activityMock = newActivityRepositoryMock(); const activityMock = newActivityRepositoryMock();
@ -118,7 +120,7 @@ export const newTestService = <T extends BaseService>(
const viewMock = newViewRepositoryMock(); const viewMock = newViewRepositoryMock();
const sut = new Service( const sut = new Service(
loggerMock, loggerMock as ILoggingRepository as LoggingRepository,
accessMock as IAccessRepository as AccessRepository, accessMock as IAccessRepository as AccessRepository,
activityMock as IActivityRepository as ActivityRepository, activityMock as IActivityRepository as ActivityRepository,
auditMock as IAuditRepository as AuditRepository, auditMock as IAuditRepository as AuditRepository,