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:
parent
b1ca5455b5
commit
46868b3336
7 changed files with 46 additions and 43 deletions
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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));
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue