feat(web,server)!: runtime log level (#5672)

* feat: change log level at runtime

* chore: open api

* chore: prefer env over runtime

* chore: remove default env value
This commit is contained in:
Jason Rasmussen
2023-12-14 11:55:40 -05:00
committed by GitHub
parent f2270ad757
commit 9768931275
61 changed files with 771 additions and 117 deletions

View File

@@ -45,6 +45,12 @@ export enum SystemConfigKey {
JOB_LIBRARY_CONCURRENCY = 'job.library.concurrency',
JOB_MIGRATION_CONCURRENCY = 'job.migration.concurrency',
LIBRARY_SCAN_ENABLED = 'library.scan.enabled',
LIBRARY_SCAN_CRON_EXPRESSION = 'library.scan.cronExpression',
LOGGING_ENABLED = 'logging.enabled',
LOGGING_LEVEL = 'logging.level',
MACHINE_LEARNING_ENABLED = 'machineLearning.enabled',
MACHINE_LEARNING_URL = 'machineLearning.url',
@@ -94,9 +100,6 @@ export enum SystemConfigKey {
TRASH_DAYS = 'trash.days',
THEME_CUSTOM_CSS = 'theme.customCss',
LIBRARY_SCAN_ENABLED = 'library.scan.enabled',
LIBRARY_SCAN_CRON_EXPRESSION = 'library.scan.cronExpression',
}
export enum TranscodePolicy {
@@ -144,6 +147,15 @@ export enum Colorspace {
P3 = 'p3',
}
export enum LogLevel {
VERBOSE = 'verbose',
DEBUG = 'debug',
LOG = 'log',
WARN = 'warn',
ERROR = 'error',
FATAL = 'fatal',
}
export interface SystemConfig {
ffmpeg: {
crf: number;
@@ -165,6 +177,10 @@ export interface SystemConfig {
tonemap: ToneMapping;
};
job: Record<QueueName, { concurrency: number }>;
logging: {
enabled: boolean;
level: LogLevel;
};
machineLearning: {
enabled: boolean;
url: string;

View File

@@ -0,0 +1,21 @@
import { ConsoleLogger } from '@nestjs/common';
import { isLogLevelEnabled } from '@nestjs/common/services/utils/is-log-level-enabled.util';
import { LogLevel } from './entities';
const LOG_LEVELS = [LogLevel.VERBOSE, LogLevel.DEBUG, LogLevel.LOG, LogLevel.WARN, LogLevel.ERROR, LogLevel.FATAL];
export class ImmichLogger extends ConsoleLogger {
private static logLevels: LogLevel[] = [];
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));
}
}

View File

@@ -6,7 +6,7 @@ import {
OnServerEventCallback,
ServerEvent,
} from '@app/domain';
import { Logger } from '@nestjs/common';
import { ImmichLogger } from '@app/infra/logger';
import {
OnGatewayConnection,
OnGatewayDisconnect,
@@ -20,7 +20,7 @@ import { Server, Socket } from 'socket.io';
export class CommunicationRepository
implements OnGatewayConnection, OnGatewayDisconnect, OnGatewayInit, ICommunicationRepository
{
private logger = new Logger(CommunicationRepository.name);
private logger = new ImmichLogger(CommunicationRepository.name);
private onConnectCallbacks: OnConnectCallback[] = [];
private onServerEventCallbacks: Record<ServerEvent, OnServerEventCallback[]> = {
[ServerEvent.CONFIG_UPDATE]: [],

View File

@@ -6,7 +6,7 @@ import {
IStorageRepository,
mimeTypes,
} from '@app/domain';
import { Logger } from '@nestjs/common';
import { ImmichLogger } from '@app/infra/logger';
import archiver from 'archiver';
import { constants, createReadStream, existsSync, mkdirSync } from 'fs';
import fs, { readdir, writeFile } from 'fs/promises';
@@ -18,7 +18,7 @@ import path from 'path';
const moveFile = promisify<string, string, mv.Options>(mv);
export class FilesystemProvider implements IStorageRepository {
private logger = new Logger(FilesystemProvider.name);
private logger = new ImmichLogger(FilesystemProvider.name);
createZipStream(): ImmichZipStream {
const archive = archiver('zip', { store: true });

View File

@@ -8,8 +8,9 @@ import {
QueueName,
QueueStatus,
} from '@app/domain';
import { ImmichLogger } from '@app/infra/logger';
import { getQueueToken } from '@nestjs/bullmq';
import { Injectable, Logger } from '@nestjs/common';
import { Injectable } from '@nestjs/common';
import { ModuleRef } from '@nestjs/core';
import { SchedulerRegistry } from '@nestjs/schedule';
import { Job, JobsOptions, Processor, Queue, Worker, WorkerOptions } from 'bullmq';
@@ -19,7 +20,7 @@ import { bullConfig } from '../infra.config';
@Injectable()
export class JobRepository implements IJobRepository {
private workers: Partial<Record<QueueName, Worker>> = {};
private logger = new Logger(JobRepository.name);
private logger = new ImmichLogger(JobRepository.name);
constructor(
private moduleRef: ModuleRef,

View File

@@ -1,6 +1,6 @@
import { CropOptions, IMediaRepository, ResizeOptions, TranscodeOptions, VideoInfo } from '@app/domain';
import { Colorspace } from '@app/infra/entities';
import { Logger } from '@nestjs/common';
import { ImmichLogger } from '@app/infra/logger';
import ffmpeg, { FfprobeData } from 'fluent-ffmpeg';
import fs from 'fs/promises';
import sharp from 'sharp';
@@ -11,7 +11,7 @@ const probe = promisify<string, FfprobeData>(ffmpeg.ffprobe);
sharp.concurrency(0);
export class MediaRepository implements IMediaRepository {
private logger = new Logger(MediaRepository.name);
private logger = new ImmichLogger(MediaRepository.name);
crop(input: string | Buffer, options: CropOptions): Promise<Buffer> {
return sharp(input, { failOn: 'none' })

View File

@@ -7,7 +7,8 @@ import {
} from '@app/domain';
import { DatabaseLock, RequireLock } from '@app/infra';
import { GeodataAdmin1Entity, GeodataAdmin2Entity, GeodataPlacesEntity, SystemMetadataKey } from '@app/infra/entities';
import { Inject, Logger } from '@nestjs/common';
import { ImmichLogger } from '@app/infra/logger';
import { Inject } from '@nestjs/common';
import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
import { DefaultReadTaskOptions, exiftool, Tags } from 'exiftool-vendored';
import { createReadStream, existsSync } from 'fs';
@@ -31,7 +32,7 @@ export class MetadataRepository implements IMetadataRepository {
@InjectDataSource() private dataSource: DataSource,
) {}
private logger = new Logger(MetadataRepository.name);
private logger = new ImmichLogger(MetadataRepository.name);
@RequireLock(DatabaseLock.GeodataImport)
async init(): Promise<void> {

View File

@@ -2,7 +2,8 @@ import { Embedding, EmbeddingSearch, ISmartInfoRepository } from '@app/domain';
import { getCLIPModelInfo } from '@app/domain/smart-info/smart-info.constant';
import { DatabaseLock, RequireLock, asyncLock } from '@app/infra';
import { AssetEntity, AssetFaceEntity, SmartInfoEntity, SmartSearchEntity } from '@app/infra/entities';
import { Injectable, Logger } from '@nestjs/common';
import { ImmichLogger } from '@app/infra/logger';
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { DummyValue, GenerateSql } from '../infra.util';
@@ -10,7 +11,7 @@ import { asVector, isValidInteger } from '../infra.utils';
@Injectable()
export class SmartInfoRepository implements ISmartInfoRepository {
private logger = new Logger(SmartInfoRepository.name);
private logger = new ImmichLogger(SmartInfoRepository.name);
private faceColumns: string[];
constructor(