1
0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2025-01-19 18:26:46 +01:00

refactor(server): logger (#9472)

This commit is contained in:
Jason Rasmussen 2024-05-14 08:48:49 -04:00 committed by GitHub
parent b1ca5455b5
commit 46868b3336
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 46 additions and 43 deletions

View file

@ -4,6 +4,7 @@ import {
Get, Get,
HttpCode, HttpCode,
HttpStatus, HttpStatus,
Inject,
Next, Next,
Param, Param,
ParseFilePipe, ParseFilePipe,
@ -30,6 +31,7 @@ import {
ServeFileDto, ServeFileDto,
} from 'src/dtos/asset-v1.dto'; } from 'src/dtos/asset-v1.dto';
import { AuthDto, ImmichHeader } from 'src/dtos/auth.dto'; import { AuthDto, ImmichHeader } from 'src/dtos/auth.dto';
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, ImmichFile, Route, mapToUploadFile } from 'src/middleware/file-upload.interceptor'; import { FileUploadInterceptor, ImmichFile, Route, mapToUploadFile } from 'src/middleware/file-upload.interceptor';
@ -46,7 +48,10 @@ interface UploadFiles {
@ApiTags('Asset') @ApiTags('Asset')
@Controller(Route.ASSET) @Controller(Route.ASSET)
export class AssetControllerV1 { export class AssetControllerV1 {
constructor(private service: AssetServiceV1) {} constructor(
private service: AssetServiceV1,
@Inject(ILoggerRepository) private logger: ILoggerRepository,
) {}
@Post('upload') @Post('upload')
@UseInterceptors(AssetUploadInterceptor, FileUploadInterceptor) @UseInterceptors(AssetUploadInterceptor, FileUploadInterceptor)
@ -95,7 +100,7 @@ export class AssetControllerV1 {
@Param() { id }: UUIDParamDto, @Param() { id }: UUIDParamDto,
@Query() dto: ServeFileDto, @Query() dto: ServeFileDto,
) { ) {
await sendFile(res, next, () => this.service.serveFile(auth, id, dto)); await sendFile(res, next, () => this.service.serveFile(auth, id, dto), this.logger);
} }
@Get('/thumbnail/:id') @Get('/thumbnail/:id')
@ -108,7 +113,7 @@ export class AssetControllerV1 {
@Param() { id }: UUIDParamDto, @Param() { id }: UUIDParamDto,
@Query() dto: GetAssetThumbnailDto, @Query() dto: GetAssetThumbnailDto,
) { ) {
await sendFile(res, next, () => this.service.serveThumbnail(auth, id, dto)); await sendFile(res, next, () => this.service.serveThumbnail(auth, id, dto), this.logger);
} }
/** /**

View file

@ -1,9 +1,10 @@
import { Body, Controller, HttpCode, HttpStatus, Next, Param, Post, Res, StreamableFile } from '@nestjs/common'; import { Body, Controller, HttpCode, HttpStatus, Inject, Next, Param, Post, Res, StreamableFile } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger'; import { ApiTags } from '@nestjs/swagger';
import { NextFunction, Response } from 'express'; import { NextFunction, Response } from 'express';
import { AssetIdsDto } from 'src/dtos/asset.dto'; import { AssetIdsDto } from 'src/dtos/asset.dto';
import { AuthDto } from 'src/dtos/auth.dto'; import { AuthDto } from 'src/dtos/auth.dto';
import { DownloadInfoDto, DownloadResponseDto } from 'src/dtos/download.dto'; import { DownloadInfoDto, DownloadResponseDto } from 'src/dtos/download.dto';
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 { DownloadService } from 'src/services/download.service'; import { DownloadService } from 'src/services/download.service';
import { asStreamableFile, sendFile } from 'src/utils/file'; import { asStreamableFile, sendFile } from 'src/utils/file';
@ -12,7 +13,10 @@ import { UUIDParamDto } from 'src/validation';
@ApiTags('Download') @ApiTags('Download')
@Controller('download') @Controller('download')
export class DownloadController { export class DownloadController {
constructor(private service: DownloadService) {} constructor(
private service: DownloadService,
@Inject(ILoggerRepository) private logger: ILoggerRepository,
) {}
@Post('info') @Post('info')
@Authenticated({ sharedLink: true }) @Authenticated({ sharedLink: true })
@ -38,6 +42,6 @@ export class DownloadController {
@Auth() auth: AuthDto, @Auth() auth: AuthDto,
@Param() { id }: UUIDParamDto, @Param() { id }: UUIDParamDto,
) { ) {
await sendFile(res, next, () => this.service.downloadFile(auth, id)); await sendFile(res, next, () => this.service.downloadFile(auth, id), this.logger);
} }
} }

View file

@ -1,4 +1,4 @@
import { Body, Controller, Get, Next, Param, Post, Put, Query, Res } from '@nestjs/common'; import { Body, Controller, Get, Inject, 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,6 +15,7 @@ import {
PersonStatisticsResponseDto, PersonStatisticsResponseDto,
PersonUpdateDto, PersonUpdateDto,
} from 'src/dtos/person.dto'; } from 'src/dtos/person.dto';
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 { 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';
@ -23,7 +24,10 @@ import { UUIDParamDto } from 'src/validation';
@ApiTags('Person') @ApiTags('Person')
@Controller('person') @Controller('person')
export class PersonController { export class PersonController {
constructor(private service: PersonService) {} constructor(
private service: PersonService,
@Inject(ILoggerRepository) private logger: ILoggerRepository,
) {}
@Get() @Get()
@Authenticated() @Authenticated()
@ -74,7 +78,7 @@ export class PersonController {
@Auth() auth: AuthDto, @Auth() auth: AuthDto,
@Param() { id }: UUIDParamDto, @Param() { id }: UUIDParamDto,
) { ) {
await sendFile(res, next, () => this.service.getThumbnail(auth, id)); await sendFile(res, next, () => this.service.getThumbnail(auth, id), this.logger);
} }
@Get(':id/assets') @Get(':id/assets')

View file

@ -5,6 +5,7 @@ import {
Get, Get,
HttpCode, HttpCode,
HttpStatus, HttpStatus,
Inject,
Next, Next,
Param, Param,
Post, Post,
@ -19,6 +20,7 @@ import { NextFunction, Response } from 'express';
import { AuthDto } from 'src/dtos/auth.dto'; import { AuthDto } from 'src/dtos/auth.dto';
import { CreateProfileImageDto, CreateProfileImageResponseDto } from 'src/dtos/user-profile.dto'; import { CreateProfileImageDto, CreateProfileImageResponseDto } from 'src/dtos/user-profile.dto';
import { CreateUserDto, DeleteUserDto, UpdateUserDto, UserResponseDto } from 'src/dtos/user.dto'; import { CreateUserDto, DeleteUserDto, UpdateUserDto, UserResponseDto } from 'src/dtos/user.dto';
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, Route } from 'src/middleware/file-upload.interceptor'; import { FileUploadInterceptor, Route } from 'src/middleware/file-upload.interceptor';
import { UserService } from 'src/services/user.service'; import { UserService } from 'src/services/user.service';
@ -28,7 +30,10 @@ import { UUIDParamDto } from 'src/validation';
@ApiTags('User') @ApiTags('User')
@Controller(Route.USER) @Controller(Route.USER)
export class UserController { export class UserController {
constructor(private service: UserService) {} constructor(
private service: UserService,
@Inject(ILoggerRepository) private logger: ILoggerRepository,
) {}
@Get() @Get()
@Authenticated() @Authenticated()
@ -100,6 +105,6 @@ export class UserController {
@FileResponse() @FileResponse()
@Authenticated() @Authenticated()
async getProfileImage(@Res() res: Response, @Next() next: NextFunction, @Param() { id }: UUIDParamDto) { async getProfileImage(@Res() res: Response, @Next() next: NextFunction, @Param() { id }: UUIDParamDto) {
await sendFile(res, next, () => this.service.getProfileImage(id)); await sendFile(res, next, () => this.service.getProfileImage(id), this.logger);
} }
} }

View file

@ -1,15 +1,27 @@
import { Injectable, Scope } from '@nestjs/common'; import { ConsoleLogger, Injectable, Scope } from '@nestjs/common';
import { isLogLevelEnabled } from '@nestjs/common/services/utils/is-log-level-enabled.util';
import { ClsService } from 'nestjs-cls'; import { ClsService } from 'nestjs-cls';
import { LogLevel } from 'src/entities/system-config.entity'; import { LogLevel } from 'src/entities/system-config.entity';
import { ILoggerRepository } from 'src/interfaces/logger.interface'; import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { ImmichLogger } from 'src/utils/logger';
const LOG_LEVELS = [LogLevel.VERBOSE, LogLevel.DEBUG, LogLevel.LOG, LogLevel.WARN, LogLevel.ERROR, LogLevel.FATAL];
@Injectable({ scope: Scope.TRANSIENT }) @Injectable({ scope: Scope.TRANSIENT })
export class LoggerRepository extends ImmichLogger implements ILoggerRepository { export class LoggerRepository extends ConsoleLogger implements ILoggerRepository {
private static logLevels: LogLevel[] = [LogLevel.LOG, LogLevel.WARN, LogLevel.ERROR, LogLevel.FATAL];
constructor(private cls: ClsService) { constructor(private cls: ClsService) {
super(LoggerRepository.name); super(LoggerRepository.name);
} }
isLevelEnabled(level: LogLevel) {
return isLogLevelEnabled(level, LoggerRepository.logLevels);
}
setLogLevel(level: LogLevel): void {
LoggerRepository.logLevels = LOG_LEVELS.slice(LOG_LEVELS.indexOf(level));
}
protected formatContext(context: string): string { protected formatContext(context: string): string {
let formattedContext = super.formatContext(context); let formattedContext = super.formatContext(context);
@ -20,8 +32,4 @@ export class LoggerRepository extends ImmichLogger implements ILoggerRepository
return formattedContext; return formattedContext;
} }
setLogLevel(level: LogLevel): void {
ImmichLogger.setLogLevel(level);
}
} }

View file

@ -3,8 +3,8 @@ import { NextFunction, Response } from 'express';
import { access, constants } from 'node:fs/promises'; 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 { ILoggerRepository } from 'src/interfaces/logger.interface';
import { ImmichReadStream } from 'src/interfaces/storage.interface'; import { ImmichReadStream } from 'src/interfaces/storage.interface';
import { ImmichLogger } from 'src/utils/logger';
import { isConnectionAborted } from 'src/utils/misc'; import { isConnectionAborted } from 'src/utils/misc';
export function getFileNameWithoutExtension(path: string): string { export function getFileNameWithoutExtension(path: string): string {
@ -33,12 +33,11 @@ export class ImmichFileResponse {
type SendFile = Parameters<Response['sendFile']>; type SendFile = Parameters<Response['sendFile']>;
type SendFileOptions = SendFile[1]; type SendFileOptions = SendFile[1];
const logger = new ImmichLogger('SendFile');
export const sendFile = async ( export const sendFile = async (
res: Response, res: Response,
next: NextFunction, next: NextFunction,
handler: () => Promise<ImmichFileResponse>, handler: () => Promise<ImmichFileResponse>,
logger: ILoggerRepository,
): 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,22 +0,0 @@
import { ConsoleLogger } from '@nestjs/common';
import { isLogLevelEnabled } from '@nestjs/common/services/utils/is-log-level-enabled.util';
import { LogLevel } from 'src/entities/system-config.entity';
const LOG_LEVELS = [LogLevel.VERBOSE, LogLevel.DEBUG, LogLevel.LOG, LogLevel.WARN, LogLevel.ERROR, LogLevel.FATAL];
// TODO move implementation to logger.repository.ts
export class ImmichLogger extends ConsoleLogger {
private static logLevels: LogLevel[] = [LogLevel.LOG, LogLevel.WARN, LogLevel.ERROR, LogLevel.FATAL];
constructor(context: string) {
super(context);
}
isLevelEnabled(level: LogLevel) {
return isLogLevelEnabled(level, ImmichLogger.logLevels);
}
static setLogLevel(level: LogLevel | false): void {
ImmichLogger.logLevels = level === false ? [] : LOG_LEVELS.slice(LOG_LEVELS.indexOf(level));
}
}