Explorar o código

Added Log level to background service (#685)

Alex %!s(int64=2) %!d(string=hai) anos
pai
achega
e79e92c60f

+ 5 - 0
docker/.env.example

@@ -36,6 +36,11 @@ REDIS_HOSTNAME=immich_redis
 UPLOAD_LOCATION=absolute_location_on_your_machine_where_you_want_to_store_the_backup
 
 
+###################################################################################
+# Log message level - [simple|verbose]
+###################################################################################
+
+LOG_LEVEL=simple
 
 
 ###################################################################################

+ 39 - 32
server/apps/microservices/src/microservices.module.ts

@@ -13,7 +13,7 @@ import {
 } from '@app/job/constants/queue-name.constant';
 import { BullModule } from '@nestjs/bull';
 import { Module } from '@nestjs/common';
-import { ConfigModule } from '@nestjs/config';
+import { ConfigModule, ConfigService } from '@nestjs/config';
 import { TypeOrmModule } from '@nestjs/typeorm';
 import { CommunicationModule } from '../../immich/src/api-v1/communication/communication.module';
 import { MicroservicesService } from './microservices.service';
@@ -40,42 +40,48 @@ import { VideoTranscodeProcessor } from './processors/video-transcode.processor'
         },
       }),
     }),
-    BullModule.registerQueue({
-      name: thumbnailGeneratorQueueName,
-      defaultJobOptions: {
-        attempts: 3,
-        removeOnComplete: true,
-        removeOnFail: false,
+    BullModule.registerQueue(
+      {
+        name: thumbnailGeneratorQueueName,
+        defaultJobOptions: {
+          attempts: 3,
+          removeOnComplete: true,
+          removeOnFail: false,
+        },
       },
-    }, {
-      name: assetUploadedQueueName,
-      defaultJobOptions: {
-        attempts: 3,
-        removeOnComplete: true,
-        removeOnFail: false,
+      {
+        name: assetUploadedQueueName,
+        defaultJobOptions: {
+          attempts: 3,
+          removeOnComplete: true,
+          removeOnFail: false,
+        },
       },
-    }, {
-      name: metadataExtractionQueueName,
-      defaultJobOptions: {
-        attempts: 3,
-        removeOnComplete: true,
-        removeOnFail: false,
+      {
+        name: metadataExtractionQueueName,
+        defaultJobOptions: {
+          attempts: 3,
+          removeOnComplete: true,
+          removeOnFail: false,
+        },
       },
-    }, {
-      name: videoConversionQueueName,
-      defaultJobOptions: {
-        attempts: 3,
-        removeOnComplete: true,
-        removeOnFail: false,
+      {
+        name: videoConversionQueueName,
+        defaultJobOptions: {
+          attempts: 3,
+          removeOnComplete: true,
+          removeOnFail: false,
+        },
       },
-    }, {
-      name: generateChecksumQueueName,
-      defaultJobOptions: {
-        attempts: 3,
-        removeOnComplete: true,
-        removeOnFail: false,
+      {
+        name: generateChecksumQueueName,
+        defaultJobOptions: {
+          attempts: 3,
+          removeOnComplete: true,
+          removeOnFail: false,
+        },
       },
-    }),
+    ),
     CommunicationModule,
   ],
   controllers: [],
@@ -86,6 +92,7 @@ import { VideoTranscodeProcessor } from './processors/video-transcode.processor'
     MetadataExtractionProcessor,
     VideoTranscodeProcessor,
     GenerateChecksumProcessor,
+    ConfigService,
   ],
   exports: [],
 })

+ 11 - 0
server/apps/microservices/src/processors/metadata-extraction.processor.ts

@@ -1,3 +1,4 @@
+import { ImmichLogLevel } from '@app/common/constants/log-level.constant';
 import { AssetEntity } from '@app/database/entities/asset.entity';
 import { ExifEntity } from '@app/database/entities/exif.entity';
 import { SmartInfoEntity } from '@app/database/entities/smart-info.entity';
@@ -16,6 +17,7 @@ import { MapiResponse } from '@mapbox/mapbox-sdk/lib/classes/mapi-response';
 import mapboxGeocoding, { GeocodeService } from '@mapbox/mapbox-sdk/services/geocoding';
 import { Process, Processor } from '@nestjs/bull';
 import { Logger } from '@nestjs/common';
+import { ConfigService } from '@nestjs/config';
 import { InjectRepository } from '@nestjs/typeorm';
 import axios from 'axios';
 import { Job } from 'bull';
@@ -28,6 +30,7 @@ import { Repository } from 'typeorm/repository/Repository';
 @Processor(metadataExtractionQueueName)
 export class MetadataExtractionProcessor {
   private geocodingClient?: GeocodeService;
+  private logLevel: ImmichLogLevel;
 
   constructor(
     @InjectRepository(AssetEntity)
@@ -38,12 +41,16 @@ export class MetadataExtractionProcessor {
 
     @InjectRepository(SmartInfoEntity)
     private smartInfoRepository: Repository<SmartInfoEntity>,
+
+    private configService: ConfigService,
   ) {
     if (process.env.ENABLE_MAPBOX == 'true' && process.env.MAPBOX_KEY) {
       this.geocodingClient = mapboxGeocoding({
         accessToken: process.env.MAPBOX_KEY,
       });
     }
+
+    this.logLevel = this.configService.get('LOG_LEVEL') || ImmichLogLevel.SIMPLE;
   }
 
   @Process(exifExtractionProcessorName)
@@ -139,6 +146,10 @@ export class MetadataExtractionProcessor {
       await this.exifRepository.save(newExif);
     } catch (e) {
       Logger.error(`Error extracting EXIF ${String(e)}`, 'extractExif');
+
+      if (this.logLevel === ImmichLogLevel.VERBOSE) {
+        console.trace('Error extracting EXIF', e);
+      }
     }
   }
 

+ 29 - 5
server/apps/microservices/src/processors/thumbnail.processor.ts

@@ -1,3 +1,4 @@
+import { ImmichLogLevel } from '@app/common/constants/log-level.constant';
 import { AssetEntity, AssetType } from '@app/database/entities/asset.entity';
 import {
   WebpGeneratorProcessor,
@@ -11,6 +12,7 @@ import {
 } from '@app/job';
 import { InjectQueue, Process, Processor } from '@nestjs/bull';
 import { Logger } from '@nestjs/common';
+import { ConfigService } from '@nestjs/config';
 import { InjectRepository } from '@nestjs/typeorm';
 import { mapAsset } from 'apps/immich/src/api-v1/asset/response-dto/asset-response.dto';
 import { Job, Queue } from 'bull';
@@ -23,6 +25,8 @@ import { CommunicationGateway } from '../../../immich/src/api-v1/communication/c
 
 @Processor(thumbnailGeneratorQueueName)
 export class ThumbnailGeneratorProcessor {
+  private logLevel: ImmichLogLevel;
+
   constructor(
     @InjectRepository(AssetEntity)
     private assetRepository: Repository<AssetEntity>,
@@ -34,7 +38,11 @@ export class ThumbnailGeneratorProcessor {
 
     @InjectQueue(metadataExtractionQueueName)
     private metadataExtractionQueue: Queue,
-  ) {}
+
+    private configService: ConfigService,
+  ) {
+    this.logLevel = this.configService.get('LOG_LEVEL') || ImmichLogLevel.SIMPLE;
+  }
 
   @Process({ name: generateJPEGThumbnailProcessorName, concurrency: 3 })
   async generateJPEGThumbnail(job: Job<JpegGeneratorProcessor>) {
@@ -51,8 +59,16 @@ export class ThumbnailGeneratorProcessor {
     const jpegThumbnailPath = resizePath + originalFilename + '.jpeg';
 
     if (asset.type == AssetType.IMAGE) {
-      await sharp(asset.originalPath).resize(1440, 2560, { fit: 'inside' }).jpeg().rotate().toFile(jpegThumbnailPath);
-      await this.assetRepository.update({ id: asset.id }, { resizePath: jpegThumbnailPath });
+      try {
+        await sharp(asset.originalPath).resize(1440, 2560, { fit: 'inside' }).jpeg().rotate().toFile(jpegThumbnailPath);
+        await this.assetRepository.update({ id: asset.id }, { resizePath: jpegThumbnailPath });
+      } catch (error) {
+        Logger.error('Failed to generate jpeg thumbnail for asset: ' + asset.id);
+
+        if (this.logLevel == ImmichLogLevel.VERBOSE) {
+          console.trace('Failed to generate jpeg thumbnail for asset', error);
+        }
+      }
 
       // Update resize path to send to generate webp queue
       asset.resizePath = jpegThumbnailPath;
@@ -105,7 +121,15 @@ export class ThumbnailGeneratorProcessor {
 
     const webpPath = asset.resizePath.replace('jpeg', 'webp');
 
-    await sharp(asset.resizePath).resize(250).webp().rotate().toFile(webpPath);
-    await this.assetRepository.update({ id: asset.id }, { webpPath: webpPath });
+    try {
+      await sharp(asset.resizePath).resize(250).webp().rotate().toFile(webpPath);
+      await this.assetRepository.update({ id: asset.id }, { webpPath: webpPath });
+    } catch (error) {
+      Logger.error('Failed to generate webp thumbnail for asset: ' + asset.id);
+
+      if (this.logLevel == ImmichLogLevel.VERBOSE) {
+        console.trace('Failed to generate webp thumbnail for asset', error);
+      }
+    }
   }
 }

+ 1 - 0
server/libs/common/src/config/app.config.ts

@@ -16,5 +16,6 @@ export const immichAppConfig: ConfigModuleOptions = {
       then: Joi.string().optional().allow(null, ''),
       otherwise: Joi.string().required(),
     }),
+    LOG_LEVEL: Joi.string().optional().valid('simple', 'verbose').default('simple'),
   }),
 };

+ 4 - 0
server/libs/common/src/constants/log-level.constant.ts

@@ -0,0 +1,4 @@
+export enum ImmichLogLevel {
+  SIMPLE = 'simple',
+  VERBOSE = 'verbose',
+}