diff --git a/.github/workflows/cd-core.yaml b/.github/workflows/cd-core.yaml index 8fe2d7797c..28fa135da5 100644 --- a/.github/workflows/cd-core.yaml +++ b/.github/workflows/cd-core.yaml @@ -17,7 +17,7 @@ jobs: - name: Install dependencies run: yarn install --immutable - name: Build core package - run: yarn build:core + run: yarn workspace @human-protocol/core build - name: Change core version uses: jossef/action-set-json-field@v2 with: diff --git a/.github/workflows/cd-deploy-contracts.yaml b/.github/workflows/cd-deploy-contracts.yaml index ba255fec28..af1248a670 100644 --- a/.github/workflows/cd-deploy-contracts.yaml +++ b/.github/workflows/cd-deploy-contracts.yaml @@ -42,7 +42,7 @@ jobs: - name: Install dependencies run: yarn --immutable - name: Build core package - run: yarn build:core + run: yarn workspace @human-protocol/core build - name: Networks list id: networks run: | diff --git a/.github/workflows/cd-logger.yaml b/.github/workflows/cd-logger.yaml index 02366d03ce..d262ede44e 100644 --- a/.github/workflows/cd-logger.yaml +++ b/.github/workflows/cd-logger.yaml @@ -19,7 +19,7 @@ jobs: - name: Install dependencies run: yarn install --immutable - name: Build logger package - run: yarn build:logger + run: yarn workspace @human-protocol/logger build - name: Publish package run: yarn workspace @human-protocol/logger npm publish --access public env: diff --git a/.github/workflows/cd-node-sdk.yaml b/.github/workflows/cd-node-sdk.yaml index dc066b215b..daf25ad3ae 100644 --- a/.github/workflows/cd-node-sdk.yaml +++ b/.github/workflows/cd-node-sdk.yaml @@ -22,7 +22,7 @@ jobs: - name: Install dependencies run: yarn install --immutable - name: Build core package - run: yarn build:core + run: yarn workspace @human-protocol/core build - name: Change Node.js SDK version from release tag uses: jossef/action-set-json-field@v2 if: ${{ github.event_name != 'workflow_dispatch' }} diff --git a/.github/workflows/cd-python-sdk.yaml b/.github/workflows/cd-python-sdk.yaml index 77be10ccb7..13d865d86d 100644 --- a/.github/workflows/cd-python-sdk.yaml +++ b/.github/workflows/cd-python-sdk.yaml @@ -22,7 +22,7 @@ jobs: - name: Install dependencies run: yarn install - name: Build core package - run: yarn build:core + run: yarn workspace @human-protocol/core build - name: Set up Python uses: actions/setup-python@v5 with: diff --git a/.github/workflows/cd-subgraph.yaml b/.github/workflows/cd-subgraph.yaml index 9a61753575..f1b56efd35 100644 --- a/.github/workflows/cd-subgraph.yaml +++ b/.github/workflows/cd-subgraph.yaml @@ -51,7 +51,7 @@ jobs: run: yarn install --immutable - name: Build core package if: steps.filter_networks.outputs.continue == 'true' - run: yarn build:core + run: yarn workspace @human-protocol/core build - name: Generate and build Subgraph if: steps.filter_networks.outputs.continue == 'true' run: yarn generate && yarn build diff --git a/.github/workflows/ci-test-node-sdk.yaml b/.github/workflows/ci-test-node-sdk.yaml index 3aa1436b77..6d7bd2a3d5 100644 --- a/.github/workflows/ci-test-node-sdk.yaml +++ b/.github/workflows/ci-test-node-sdk.yaml @@ -19,6 +19,6 @@ jobs: - name: Install dependencies run: yarn install --immutable - name: Build core package - run: yarn build:core + run: yarn workspace @human-protocol/core build - name: Run Node.js SDK test run: yarn workspace @human-protocol/sdk test diff --git a/.github/workflows/ci-test-python-sdk.yaml b/.github/workflows/ci-test-python-sdk.yaml index 99597a2d81..3db01fbf34 100644 --- a/.github/workflows/ci-test-python-sdk.yaml +++ b/.github/workflows/ci-test-python-sdk.yaml @@ -19,7 +19,7 @@ jobs: - name: Install core package dependencies run: yarn install --immutable - name: Build core package - run: yarn build:core + run: yarn workspace @human-protocol/core build - name: Set up Python 3.10 uses: actions/setup-python@v5 with: diff --git a/.github/workflows/ci-test-subgraph.yaml b/.github/workflows/ci-test-subgraph.yaml index a84c675469..976c341b3b 100644 --- a/.github/workflows/ci-test-subgraph.yaml +++ b/.github/workflows/ci-test-subgraph.yaml @@ -20,7 +20,7 @@ jobs: - name: Install dependencies run: yarn install --immutable - name: Build core package - run: yarn build:core + run: yarn workspace @human-protocol/core build - name: Generate manifest for Polygon for tests run: NETWORK=polygon yarn workspace @human-protocol/subgraph generate - name: Run subgraph test diff --git a/package.json b/package.json index e767ca9cea..5a50d4fe39 100644 --- a/package.json +++ b/package.json @@ -8,10 +8,7 @@ "scripts": { "clean": "yarn workspaces foreach --all -p run clean", "lint": "yarn workspaces foreach --all -p run lint", - "build:core": "yarn workspace @human-protocol/core build", - "build:sdk": "yarn workspace @human-protocol/sdk build", - "build:logger": "yarn workspace @human-protocol/logger build", - "build:libs": "yarn build:core && yarn build:sdk && yarn build:logger", + "build:libs": "yarn workspaces foreach -Rpt --from '{@human-protocol/sdk,packages/libs/*}' run build", "docker:infra-up": "make -C ./docker-setup -f Makefile.dev infra-up", "docker:infra-stop": "make -C ./docker-setup -f Makefile.dev infra-stop", "docker:infra-down": "make -C ./docker-setup -f Makefile.dev infra-down", diff --git a/packages/apps/job-launcher/server/.env.example b/packages/apps/job-launcher/server/.env.example index d892a45d20..55590e127e 100644 --- a/packages/apps/job-launcher/server/.env.example +++ b/packages/apps/job-launcher/server/.env.example @@ -84,10 +84,8 @@ HCAPTCHA_SECRET=0x0000000000000000000000000000000000000000 # Stripe PAYMENT_PROVIDER_SECRET_KEY=disabled -PAYMENT_PROVIDER_APP_NAME=Launcher Server Local -PAYMENT_PROVIDER_APP_VERSION=1.0.0 +PAYMENT_PROVIDER_APP_NAME=Job Launcher Server Local PAYMENT_PROVIDER_APP_INFO_URL=http://local.app -PAYMENT_PROVIDER_API_VERSION=2022-11-15 # Sendgrid SENDGRID_API_KEY=sendgrid-disabled diff --git a/packages/apps/job-launcher/server/Dockerfile b/packages/apps/job-launcher/server/Dockerfile index 72663d1e27..e837d0a8ec 100644 --- a/packages/apps/job-launcher/server/Dockerfile +++ b/packages/apps/job-launcher/server/Dockerfile @@ -16,6 +16,7 @@ COPY ${APP_PATH}/package.json ./${APP_PATH}/ # so we need to copy and build them COPY packages/core ./packages/core COPY packages/sdk ./packages/sdk +COPY packages/libs ./packages/libs RUN yarn install diff --git a/packages/apps/job-launcher/server/package.json b/packages/apps/job-launcher/server/package.json index fc7451e68c..249528e9e8 100644 --- a/packages/apps/job-launcher/server/package.json +++ b/packages/apps/job-launcher/server/package.json @@ -30,6 +30,7 @@ "dependencies": { "@google-cloud/storage": "^7.15.0", "@google-cloud/vision": "^4.3.2", + "@human-protocol/logger": "workspace:*", "@human-protocol/sdk": "workspace:*", "@nestjs/axios": "^3.1.2", "@nestjs/common": "^10.2.7", diff --git a/packages/apps/job-launcher/server/src/app.module.ts b/packages/apps/job-launcher/server/src/app.module.ts index 03fcb7b581..b351d7e082 100644 --- a/packages/apps/job-launcher/server/src/app.module.ts +++ b/packages/apps/job-launcher/server/src/app.module.ts @@ -1,6 +1,10 @@ import { Module } from '@nestjs/common'; import { APP_FILTER, APP_GUARD, APP_INTERCEPTOR, APP_PIPE } from '@nestjs/core'; +import { ServeStaticModule } from '@nestjs/serve-static'; +import { ScheduleModule } from '@nestjs/schedule'; import { ConfigModule } from '@nestjs/config'; +import { join } from 'path'; + import { AppController } from './app.controller'; import { DatabaseModule } from './database/database.module'; import { JwtAuthGuard } from './common/guards'; @@ -12,18 +16,16 @@ import { JobModule } from './modules/job/job.module'; import { PaymentModule } from './modules/payment/payment.module'; import { Web3Module } from './modules/web3/web3.module'; import { envValidator } from './common/config/env-schema'; -import { ServeStaticModule } from '@nestjs/serve-static'; -import { join } from 'path'; import { StorageModule } from './modules/storage/storage.module'; import { CronJobModule } from './modules/cron-job/cron-job.module'; import { SnakeCaseInterceptor } from './common/interceptors/snake-case'; import { WebhookModule } from './modules/webhook/webhook.module'; import { EnvConfigModule } from './common/config/config.module'; import { ExceptionFilter } from './common/exceptions/exception.filter'; -import { ScheduleModule } from '@nestjs/schedule'; import { StatisticModule } from './modules/statistic/statistic.module'; import { QualificationModule } from './modules/qualification/qualification.module'; import { TransformEnumInterceptor } from './common/interceptors/transform-enum.interceptor'; +import Environment from './common/utils/environment'; @Module({ providers: [ @@ -54,7 +56,7 @@ import { TransformEnumInterceptor } from './common/interceptors/transform-enum.i /** * First value found takes precendece */ - envFilePath: [`.env.${process.env.NODE_ENV}`, '.env.local', '.env'], + envFilePath: [`.env.${Environment.name}`, '.env.local', '.env'], validationSchema: envValidator, }), DatabaseModule, diff --git a/packages/apps/job-launcher/server/src/common/config/env-schema.ts b/packages/apps/job-launcher/server/src/common/config/env-schema.ts index 50e853d2dc..e7fd7cbc95 100644 --- a/packages/apps/job-launcher/server/src/common/config/env-schema.ts +++ b/packages/apps/job-launcher/server/src/common/config/env-schema.ts @@ -2,7 +2,6 @@ import * as Joi from 'joi'; export const envValidator = Joi.object({ // General - NODE_ENV: Joi.string(), HOST: Joi.string(), PORT: Joi.string(), FE_URL: Joi.string(), diff --git a/packages/apps/job-launcher/server/src/common/config/payment-provider-config.service.ts b/packages/apps/job-launcher/server/src/common/config/payment-provider-config.service.ts index c28a642d2e..84b385912f 100644 --- a/packages/apps/job-launcher/server/src/common/config/payment-provider-config.service.ts +++ b/packages/apps/job-launcher/server/src/common/config/payment-provider-config.service.ts @@ -26,23 +26,23 @@ export class PaymentProviderConfigService { /** * The name of the application interacting with the payment providers API. - * Default: 'Fortune' + * Default: 'Job Launcher Server' */ get appName(): string { return this.configService.get( 'PAYMENT_PROVIDER_APP_NAME', - 'Fortune', + 'Job Launcher Server', ); } /** * The version of the application interacting with the payment providers API. - * Default: '0.0.1' + * Default: '1.0.0' */ get appVersion(): string { return this.configService.get( 'PAYMENT_PROVIDER_APP_VERSION', - '0.0.1', + '1.0.0', ); } diff --git a/packages/apps/job-launcher/server/src/common/config/server-config.service.ts b/packages/apps/job-launcher/server/src/common/config/server-config.service.ts index 6f26a2a109..a7901183d9 100644 --- a/packages/apps/job-launcher/server/src/common/config/server-config.service.ts +++ b/packages/apps/job-launcher/server/src/common/config/server-config.service.ts @@ -5,14 +5,6 @@ import { ConfigService } from '@nestjs/config'; export class ServerConfigService { constructor(private configService: ConfigService) {} - /** - * The environment in which the server is running (e.g., 'development', 'production'). - * Default: 'development' - */ - get nodeEnv(): string { - return this.configService.get('NODE_ENV', 'development'); - } - /** * The hostname or IP address on which the server will run. * Default: 'localhost' diff --git a/packages/apps/job-launcher/server/src/common/exceptions/exception.filter.ts b/packages/apps/job-launcher/server/src/common/exceptions/exception.filter.ts index 7ad8be772a..d0d6a808e8 100644 --- a/packages/apps/job-launcher/server/src/common/exceptions/exception.filter.ts +++ b/packages/apps/job-launcher/server/src/common/exceptions/exception.filter.ts @@ -3,9 +3,9 @@ import { Catch, ExceptionFilter as IExceptionFilter, HttpStatus, - Logger, } from '@nestjs/common'; import { Request, Response } from 'express'; + import { ValidationError, AuthError, @@ -15,10 +15,11 @@ import { ServerError, DatabaseError, } from '../errors'; +import logger from '../../logger'; @Catch() export class ExceptionFilter implements IExceptionFilter { - private logger = new Logger(ExceptionFilter.name); + private readonly logger = logger.child({ context: ExceptionFilter.name }); private getStatus(exception: any): number { if (exception instanceof ValidationError) { @@ -49,10 +50,7 @@ export class ExceptionFilter implements IExceptionFilter { const status = this.getStatus(exception); const message = exception.message || 'Internal server error'; - this.logger.error( - `Exception caught: ${message}`, - exception.stack || 'No stack trace available', - ); + this.logger.error('Unhandled exception', exception); response.status(status).json({ statusCode: status, diff --git a/packages/apps/job-launcher/server/src/common/guards/signature.auth.ts b/packages/apps/job-launcher/server/src/common/guards/signature.auth.ts index 8b536358f5..a3c2d11ac5 100644 --- a/packages/apps/job-launcher/server/src/common/guards/signature.auth.ts +++ b/packages/apps/job-launcher/server/src/common/guards/signature.auth.ts @@ -1,18 +1,15 @@ import { EscrowUtils } from '@human-protocol/sdk'; -import { - CanActivate, - ExecutionContext, - Injectable, - Logger, -} from '@nestjs/common'; +import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; + import { HEADER_SIGNATURE_KEY } from '../constants'; import { Role } from '../enums/role'; import { AuthError } from '../errors'; import { verifySignature } from '../utils/signature'; +import logger from '../../logger'; @Injectable() export class SignatureAuthGuard implements CanActivate { - private readonly logger = new Logger(SignatureAuthGuard.name); + private readonly logger = logger.child({ context: SignatureAuthGuard.name }); constructor(private role: Role[]) {} @@ -49,10 +46,7 @@ export class SignatureAuthGuard implements CanActivate { return true; } } catch (error) { - this.logger.error( - `Error verifying signature: ${error.message}`, - error.stack, - ); + this.logger.error('Error verifying signature', error); } throw new AuthError('Unauthorized'); diff --git a/packages/apps/job-launcher/server/src/common/guards/whitelist.auth.ts b/packages/apps/job-launcher/server/src/common/guards/whitelist.auth.ts index 5683a2b81f..e7ad6ea6c5 100644 --- a/packages/apps/job-launcher/server/src/common/guards/whitelist.auth.ts +++ b/packages/apps/job-launcher/server/src/common/guards/whitelist.auth.ts @@ -1,15 +1,12 @@ -import { - CanActivate, - ExecutionContext, - Injectable, - Logger, -} from '@nestjs/common'; +import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; + import { WhitelistService } from '../../modules/whitelist/whitelist.service'; import { AuthError } from '../errors'; +import logger from '../../logger'; @Injectable() export class WhitelistAuthGuard implements CanActivate { - private readonly logger = new Logger(WhitelistAuthGuard.name); + private readonly logger = logger.child({ context: WhitelistAuthGuard.name }); constructor(private readonly whitelistService: WhitelistService) {} @@ -18,7 +15,7 @@ export class WhitelistAuthGuard implements CanActivate { const user = request.user; if (!user) { - this.logger.error('User object is missing in the request.', request); + this.logger.error('User object is missing in the request'); throw new AuthError('User not found.'); } diff --git a/packages/apps/job-launcher/server/src/common/utils/environment.ts b/packages/apps/job-launcher/server/src/common/utils/environment.ts new file mode 100644 index 0000000000..05d5c87255 --- /dev/null +++ b/packages/apps/job-launcher/server/src/common/utils/environment.ts @@ -0,0 +1,26 @@ +enum EnvironmentName { + LOCAL = 'local', + DEVELOPMENT = 'development', + TEST = 'test', + STAGING = 'staging', + PRODUCTION = 'production', +} + +class Environment { + static readonly name: string = + process.env.NODE_ENV || EnvironmentName.DEVELOPMENT; + + static isDevelopment(): boolean { + return [ + EnvironmentName.DEVELOPMENT, + EnvironmentName.TEST, + EnvironmentName.LOCAL, + ].includes(Environment.name as EnvironmentName); + } + + static isTest(): boolean { + return Environment.name === EnvironmentName.TEST; + } +} + +export default Environment; diff --git a/packages/apps/job-launcher/server/src/common/utils/slack.ts b/packages/apps/job-launcher/server/src/common/utils/slack.ts index e74d4fd02f..cb6ef3156e 100644 --- a/packages/apps/job-launcher/server/src/common/utils/slack.ts +++ b/packages/apps/job-launcher/server/src/common/utils/slack.ts @@ -1,12 +1,13 @@ -import { Logger } from '@nestjs/common'; import axios from 'axios'; +import logger from '../../logger'; + +const slackLogger = logger.child({ context: 'sendSlackNotification' }); + export async function sendSlackNotification( webhookUrl: string, message: string, ): Promise { - const logger = new Logger('Slack'); - const payload = { text: message, }; @@ -17,10 +18,10 @@ export async function sendSlackNotification( try { await axios.post(webhookUrl, payload); - logger.log('Slack notification sent:', payload); + slackLogger.debug('Slack notification sent', payload); return true; - } catch (e) { - logger.error('Error sending Slack notification:', e); + } catch (error) { + slackLogger.error('Error sending Slack notification', error); return false; } } diff --git a/packages/apps/job-launcher/server/src/database/database.module.ts b/packages/apps/job-launcher/server/src/database/database.module.ts index cc711645a9..66d72e30d2 100644 --- a/packages/apps/job-launcher/server/src/database/database.module.ts +++ b/packages/apps/job-launcher/server/src/database/database.module.ts @@ -10,7 +10,6 @@ import { TypeOrmLoggerModule, TypeOrmLoggerService } from './typeorm'; import { JobEntity } from '../modules/job/job.entity'; import { ContentModerationRequestEntity } from '../modules/content-moderation/content-moderation-request.entity'; import { PaymentEntity } from '../modules/payment/payment.entity'; -import { ServerConfigService } from '../common/config/server-config.service'; import { DatabaseConfigService } from '../common/config/database-config.service'; import { ApiKeyEntity } from '../modules/auth/apikey.entity'; import { WebhookEntity } from '../modules/webhook/webhook.entity'; @@ -22,15 +21,10 @@ import { WhitelistEntity } from '../modules/whitelist/whitelist.entity'; imports: [ TypeOrmModule.forRootAsync({ imports: [TypeOrmLoggerModule], - inject: [ - TypeOrmLoggerService, - DatabaseConfigService, - ServerConfigService, - ], + inject: [TypeOrmLoggerService, DatabaseConfigService], useFactory: ( typeOrmLoggerService: TypeOrmLoggerService, databaseConfigService: DatabaseConfigService, - serverConfigService: ServerConfigService, ) => { const loggerOptions = databaseConfigService.logging?.split(', '); typeOrmLoggerService.setOptions( @@ -72,7 +66,6 @@ import { WhitelistEntity } from '../modules/whitelist/whitelist.entity'; username: databaseConfigService.user, password: databaseConfigService.password, database: databaseConfigService.database, - keepConnectionAlive: serverConfigService.nodeEnv === 'test', migrationsRun: false, ssl: databaseConfigService.ssl, }; diff --git a/packages/apps/job-launcher/server/src/database/migrations/1749498615107-RenameStripeCustomerIdColumn.ts b/packages/apps/job-launcher/server/src/database/migrations/1749498615107-RenameStripeCustomerIdColumn.ts index ff6bb88c1b..adb2f1fd30 100644 --- a/packages/apps/job-launcher/server/src/database/migrations/1749498615107-RenameStripeCustomerIdColumn.ts +++ b/packages/apps/job-launcher/server/src/database/migrations/1749498615107-RenameStripeCustomerIdColumn.ts @@ -1,7 +1,8 @@ import { MigrationInterface, QueryRunner } from 'typeorm'; -export class RenameStripeCustomerIdColumn1749498615107 implements MigrationInterface { - +export class RenameStripeCustomerIdColumn1749498615107 + implements MigrationInterface +{ name = 'RenameStripeCustomerIdColumn1749498615107'; public async up(queryRunner: QueryRunner): Promise { @@ -25,4 +26,4 @@ export class RenameStripeCustomerIdColumn1749498615107 implements MigrationInter RENAME COLUMN "payment_provider_id" TO "stripe_customer_id" `); } -} +} diff --git a/packages/apps/job-launcher/server/src/logger/index.ts b/packages/apps/job-launcher/server/src/logger/index.ts new file mode 100644 index 0000000000..50ec6a69cc --- /dev/null +++ b/packages/apps/job-launcher/server/src/logger/index.ts @@ -0,0 +1,24 @@ +import { createLogger, NestLogger, LogLevel } from '@human-protocol/logger'; + +import Environment from '../common/utils/environment'; + +const isDevelopment = Environment.isDevelopment(); + +const defaultLogger = createLogger( + { + name: 'DefaultLogger', + level: isDevelopment ? LogLevel.DEBUG : LogLevel.INFO, + pretty: isDevelopment, + disabled: Environment.isTest(), + }, + { + environment: Environment.name, + service: 'job-launcher', + }, +); + +export const nestLoggerOverride = new NestLogger( + defaultLogger.child({ name: 'NestLogger' }), +); + +export default defaultLogger; diff --git a/packages/apps/job-launcher/server/src/main.ts b/packages/apps/job-launcher/server/src/main.ts index bb5e4019e0..1ee1a55318 100644 --- a/packages/apps/job-launcher/server/src/main.ts +++ b/packages/apps/job-launcher/server/src/main.ts @@ -8,12 +8,14 @@ import { useContainer } from 'class-validator'; import helmet from 'helmet'; import { AppModule } from './app.module'; import { ServerConfigService } from './common/config/server-config.service'; +import logger, { nestLoggerOverride } from './logger'; async function bootstrap() { const app = await NestFactory.create(AppModule, { cors: { exposedHeaders: ['Content-Disposition'], }, + logger: nestLoggerOverride, }); useContainer(app.select(AppModule), { fallbackOnErrors: true }); @@ -38,7 +40,7 @@ async function bootstrap() { const port = serverConfigService.port; await app.listen(port, host, async () => { - console.info(`API server is running on http://${host}:${port}`); + logger.info(`API server is running on http://${host}:${port}`); }); } diff --git a/packages/apps/job-launcher/server/src/modules/auth/auth.controller.ts b/packages/apps/job-launcher/server/src/modules/auth/auth.controller.ts index cdd9440f7f..73566fd130 100644 --- a/packages/apps/job-launcher/server/src/modules/auth/auth.controller.ts +++ b/packages/apps/job-launcher/server/src/modules/auth/auth.controller.ts @@ -4,7 +4,6 @@ import { Controller, HttpCode, Ip, - Logger, Post, Req, Request, @@ -39,6 +38,8 @@ import { AuthService } from './auth.service'; import { TokenType } from './token.entity'; import { TokenRepository } from './token.repository'; +import logger from '../../logger'; + @ApiTags('Auth') @ApiResponse({ status: 400, @@ -58,7 +59,7 @@ import { TokenRepository } from './token.repository'; }) @Controller('/auth') export class AuthJwtController { - private readonly logger = new Logger(AuthJwtController.name); + private readonly logger = logger.child({ context: AuthJwtController.name }); constructor( private readonly authService: AuthService, @@ -245,11 +246,8 @@ export class AuthJwtController { try { const apiKey = await this.authService.createOrUpdateAPIKey(req.user); return { apiKey }; - } catch (e) { - this.logger.log( - e.message, - `${AuthJwtController.name} - ${ErrorAuth.ApiKeyCouldNotBeCreatedOrUpdated}`, - ); + } catch (error) { + this.logger.error(ErrorAuth.ApiKeyCouldNotBeCreatedOrUpdated, error); throw new ValidationError(ErrorAuth.ApiKeyCouldNotBeCreatedOrUpdated); } } diff --git a/packages/apps/job-launcher/server/src/modules/content-moderation/gcv-content-moderation.service.ts b/packages/apps/job-launcher/server/src/modules/content-moderation/gcv-content-moderation.service.ts index d4bd6f8b0c..f1a422c51d 100644 --- a/packages/apps/job-launcher/server/src/modules/content-moderation/gcv-content-moderation.service.ts +++ b/packages/apps/job-launcher/server/src/modules/content-moderation/gcv-content-moderation.service.ts @@ -1,6 +1,6 @@ import { Storage } from '@google-cloud/storage'; import { ImageAnnotatorClient, protos } from '@google-cloud/vision'; -import { Injectable, Logger } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import NodeCache from 'node-cache'; import { SlackConfigService } from '../../common/config/slack-config.service'; import { VisionConfigService } from '../../common/config/vision-config.service'; @@ -31,10 +31,13 @@ import { ContentModerationRequestEntity } from './content-moderation-request.ent import { ContentModerationRequestRepository } from './content-moderation-request.repository'; import { ModerationResultDto } from './content-moderation.dto'; import { IContentModeratorService } from './content-moderation.interface'; +import logger from '../../logger'; @Injectable() export class GCVContentModerationService implements IContentModeratorService { - private readonly logger = new Logger(GCVContentModerationService.name); + private readonly logger = logger.child({ + context: GCVContentModerationService.name, + }); private visionClient: ImageAnnotatorClient; private storage: Storage; @@ -153,11 +156,12 @@ export class GCVContentModerationService implements IContentModeratorService { jobEntity.status = JobStatus.UNDER_MODERATION; await this.jobRepository.updateOne(jobEntity); } - } catch (err) { - this.logger.error( - `Error creating requests for job ${jobEntity.id}: ${err.message}`, - ); - throw err; + } catch (error) { + this.logger.error('Error creating requests for job', { + error, + jobId: jobEntity.id, + }); + throw error; } } @@ -176,10 +180,13 @@ export class GCVContentModerationService implements IContentModeratorService { requests.map(async (requestEntity) => { try { await this.processSingleRequest(requestEntity); - } catch (err) { - this.logger.error( - `Error processing request ${requestEntity.id} (job ${jobEntity.id}): ${err.message}`, - ); + } catch (error) { + this.logger.error('Error processing moderation request', { + moderationRequestId: requestEntity.id, + jobId: jobEntity.id, + error, + }); + requestEntity.status = ContentModerationRequestStatus.FAILED; await this.contentModerationRequestRepository.updateOne( requestEntity, @@ -187,11 +194,13 @@ export class GCVContentModerationService implements IContentModeratorService { } }), ); - } catch (err) { - this.logger.error( - `Error processing requests for job ${jobEntity.id}: ${err.message}`, - ); - throw err; + } catch (error) { + this.logger.error('Error processing moderation requests', { + error, + jobId: jobEntity.id, + }); + + throw error; } } @@ -211,10 +220,13 @@ export class GCVContentModerationService implements IContentModeratorService { requests.map(async (requestEntity) => { try { await this.parseSingleRequest(requestEntity); - } catch (err) { - this.logger.error( - `Error parsing request ${requestEntity.id} for job ${jobEntity.id}: ${err.message}`, - ); + } catch (error) { + this.logger.error('Error parsing moderation request', { + moderationRequestId: requestEntity.id, + jobId: jobEntity.id, + error, + }); + requestEntity.status = ContentModerationRequestStatus.FAILED; await this.contentModerationRequestRepository.updateOne( requestEntity, @@ -222,11 +234,12 @@ export class GCVContentModerationService implements IContentModeratorService { } }), ); - } catch (err) { - this.logger.error( - `Error parsing results for job ${jobEntity.id}: ${err.message}`, - ); - throw err; + } catch (error) { + this.logger.error('Error parsing moderation results', { + jobId: jobEntity.id, + error, + }); + throw error; } } @@ -266,9 +279,12 @@ export class GCVContentModerationService implements IContentModeratorService { jobEntity.status = JobStatus.POSSIBLE_ABUSE_IN_REVIEW; await this.jobRepository.updateOne(jobEntity); } - } catch (err) { - this.logger.error(`Error finalizing job ${jobEntity.id}: ${err.message}`); - throw err; + } catch (error) { + this.logger.error('Error finalizing moderation job', { + jobId: jobEntity.id, + error, + }); + throw error; } } @@ -327,11 +343,11 @@ export class GCVContentModerationService implements IContentModeratorService { const [operation] = await this.visionClient.asyncBatchAnnotateImages(requestPayload); const [filesResponse] = await operation.promise(); - this.logger.log( - `Output written to GCS: ${filesResponse?.outputConfig?.gcsDestination?.uri}`, - ); + this.logger.debug('Output written to GCS', { + url: filesResponse?.outputConfig?.gcsDestination?.uri, + }); } catch (error) { - this.logger.error('Error analyzing images:', error); + this.logger.error('Error analyzing images', error); throw new Error(ErrorContentModeration.ContentModerationFailed); } } @@ -389,11 +405,11 @@ export class GCVContentModerationService implements IContentModeratorService { } } return this.categorizeModerationResults(allResponses); - } catch (err) { - if (err.message === ErrorContentModeration.NoResultsFound) { - throw err; + } catch (error) { + if (error.message === ErrorContentModeration.NoResultsFound) { + throw error; } - this.logger.error('Error collecting moderation results:', err); + this.logger.error('Error collecting moderation results', error); throw new Error(ErrorContentModeration.ResultsParsingFailed); } } diff --git a/packages/apps/job-launcher/server/src/modules/cron-job/cron-job.service.spec.ts b/packages/apps/job-launcher/server/src/modules/cron-job/cron-job.service.spec.ts index dd397c871f..82643408eb 100644 --- a/packages/apps/job-launcher/server/src/modules/cron-job/cron-job.service.spec.ts +++ b/packages/apps/job-launcher/server/src/modules/cron-job/cron-job.service.spec.ts @@ -1078,7 +1078,7 @@ describe('CronJobService', () => { }); }); - describe('syncJobStuses Cron Job', () => { + describe('syncJobStatuses Cron Job', () => { let cronJobEntityMock: Partial; let jobEntityMock: Partial; let escrowEventMock: Partial; @@ -1129,7 +1129,7 @@ describe('CronJobService', () => { const startCronJobMock = jest.spyOn(service, 'startCronJob'); - await service.syncJobStuses(); + await service.syncJobStatuses(); expect(startCronJobMock).not.toHaveBeenCalled(); }); @@ -1139,7 +1139,7 @@ describe('CronJobService', () => { .spyOn(service, 'startCronJob') .mockResolvedValueOnce(cronJobEntityMock as any); - await service.syncJobStuses(); + await service.syncJobStatuses(); expect(service.startCronJob).toHaveBeenCalledWith( CronJobType.SyncJobStatuses, @@ -1151,7 +1151,7 @@ describe('CronJobService', () => { .spyOn(jobRepository, 'findManyByChainIdsAndEscrowAddresses') .mockResolvedValueOnce([jobEntityMock as any]); - await service.syncJobStuses(); + await service.syncJobStatuses(); expect(EscrowUtils.getStatusEvents).toHaveBeenCalled(); expect( @@ -1174,9 +1174,13 @@ describe('CronJobService', () => { .spyOn(EscrowUtils, 'getStatusEvents') .mockRejectedValue(new Error('Test error')); - await service.syncJobStuses(); + await service.syncJobStatuses(); - expect(loggerErrorSpy).toHaveBeenCalledWith(expect.any(Error)); + expect(loggerErrorSpy).toHaveBeenCalledWith( + 'Error in syncJobStatuses cron job', + expect.any(Error), + ); + loggerErrorSpy.mockRestore(); }); it('should complete the cron job entity to unlock', async () => { @@ -1184,7 +1188,7 @@ describe('CronJobService', () => { .spyOn(service, 'completeCronJob') .mockResolvedValueOnce(cronJobEntityMock as any); - await service.syncJobStuses(); + await service.syncJobStatuses(); expect(service.completeCronJob).toHaveBeenCalledWith( cronJobEntityMock as any, diff --git a/packages/apps/job-launcher/server/src/modules/cron-job/cron-job.service.ts b/packages/apps/job-launcher/server/src/modules/cron-job/cron-job.service.ts index abfc46cea1..8e41a57729 100644 --- a/packages/apps/job-launcher/server/src/modules/cron-job/cron-job.service.ts +++ b/packages/apps/job-launcher/server/src/modules/cron-job/cron-job.service.ts @@ -1,5 +1,4 @@ -import { Injectable, Logger } from '@nestjs/common'; -import { v4 as uuidv4 } from 'uuid'; +import { Injectable } from '@nestjs/common'; import { ErrorContentModeration, ErrorCronJob, @@ -30,10 +29,11 @@ import { WebhookRepository } from '../webhook/webhook.repository'; import { WebhookService } from '../webhook/webhook.service'; import { CronJobEntity } from './cron-job.entity'; import { CronJobRepository } from './cron-job.repository'; +import logger from '../../logger'; @Injectable() export class CronJobService { - private readonly logger = new Logger(CronJobService.name); + private readonly logger = logger.child({ context: CronJobService.name }); constructor( private readonly cronJobRepository: CronJobRepository, @@ -67,7 +67,7 @@ export class CronJobService { return false; } - this.logger.log('Previous cron job is not completed yet'); + this.logger.info('Previous cron job is not completed yet'); return true; } @@ -102,21 +102,20 @@ export class CronJobService { jobs.map(async (jobEntity) => { try { await this.contentModerationService.moderateJob(jobEntity); - } catch (err) { - const errorId = uuidv4(); - const failedReason = `${ErrorContentModeration.ResultsParsingFailed} (Error ID: ${errorId})`; - this.logger.error( - `Error parse job moderation results job. Error ID: ${errorId}, Job ID: ${jobEntity.id}, Reason: ${failedReason}, Message: ${err.message}`, - ); + } catch (error) { + this.logger.error('Error parse job moderation results job', { + jobId: jobEntity.id, + error, + }); await this.jobService.handleProcessJobFailure( jobEntity, - failedReason, + ErrorContentModeration.ResultsParsingFailed, ); } }), ); - } catch (err) { - this.logger.error(`Error in moderateContentCronJob: ${err.message}`); + } catch (error) { + this.logger.error('Error in moderateContentCronJob', error); } await this.completeCronJob(cronJobEntity); @@ -132,7 +131,7 @@ export class CronJobService { return; } - this.logger.log('Create escrow START'); + this.logger.info('Create escrow START'); const cronJob = await this.startCronJob(CronJobType.CreateEscrow); try { @@ -142,23 +141,22 @@ export class CronJobService { for (const jobEntity of jobEntities) { try { await this.jobService.createEscrow(jobEntity); - } catch (err) { - const errorId = uuidv4(); - const failedReason = `${ErrorEscrow.NotCreated} (Error ID: ${errorId})`; - this.logger.error( - `Error creating escrow. Error ID: ${errorId}, Job ID: ${jobEntity.id}, Reason: ${failedReason}, Message: ${err.message}`, - ); + } catch (error) { + this.logger.error('Error in moderateContentCronJob', { + jobId: jobEntity.id, + error, + }); await this.jobService.handleProcessJobFailure( jobEntity, - failedReason, + ErrorEscrow.NotCreated, ); } } - } catch (e) { - this.logger.error(e); + } catch (error) { + this.logger.error('Error in createEscrow cron job', error); } - this.logger.log('Create escrow STOP'); + this.logger.info('Create escrow STOP'); await this.completeCronJob(cronJob); } @@ -172,7 +170,7 @@ export class CronJobService { return; } - this.logger.log('Setup escrow START'); + this.logger.info('Setup escrow START'); const cronJob = await this.startCronJob(CronJobType.SetupEscrow); try { @@ -183,23 +181,22 @@ export class CronJobService { for (const jobEntity of jobEntities) { try { await this.jobService.setupEscrow(jobEntity); - } catch (err) { - const errorId = uuidv4(); - const failedReason = `${ErrorEscrow.NotSetup} (Error ID: ${errorId})`; - this.logger.error( - `Error setting up escrow. Error ID: ${errorId}, Job ID: ${jobEntity.id}, Reason: ${failedReason}, Message: ${err.message}`, - ); + } catch (error) { + this.logger.error('Error setting up escrow', { + jobId: jobEntity.id, + error, + }); await this.jobService.handleProcessJobFailure( jobEntity, - failedReason, + ErrorEscrow.NotSetup, ); } } - } catch (e) { - this.logger.error(e); + } catch (error) { + this.logger.error('Error in setupEscrow cron job', error); } - this.logger.log('Setup escrow STOP'); + this.logger.info('Setup escrow STOP'); await this.completeCronJob(cronJob); } @@ -213,7 +210,7 @@ export class CronJobService { return; } - this.logger.log('Fund escrow START'); + this.logger.info('Fund escrow START'); const cronJob = await this.startCronJob(CronJobType.FundEscrow); try { @@ -224,23 +221,22 @@ export class CronJobService { for (const jobEntity of jobEntities) { try { await this.jobService.fundEscrow(jobEntity); - } catch (err) { - const errorId = uuidv4(); - const failedReason = `${ErrorEscrow.NotFunded} (Error ID: ${errorId})`; - this.logger.error( - `Error funding escrow. Error ID: ${errorId}, Job ID: ${jobEntity.id}, Reason: ${failedReason}, Message: ${err.message}`, - ); + } catch (error) { + this.logger.error('Error funding escrow', { + jobId: jobEntity.id, + error, + }); await this.jobService.handleProcessJobFailure( jobEntity, - failedReason, + ErrorEscrow.NotFunded, ); } } - } catch (e) { - this.logger.error(e); + } catch (error) { + this.logger.error('Error in fundEscrow cron job', error); } - this.logger.log('Fund escrow STOP'); + this.logger.info('Fund escrow STOP'); await this.completeCronJob(cronJob); } @@ -254,7 +250,7 @@ export class CronJobService { return; } - this.logger.log('Cancel jobs START'); + this.logger.info('Cancel jobs START'); const cronJob = await this.startCronJob(CronJobType.CancelEscrow); try { @@ -304,23 +300,22 @@ export class CronJobService { }); await this.webhookRepository.createUnique(webhookEntity); } - } catch (err) { - const errorId = uuidv4(); - const failedReason = `${ErrorEscrow.NotCanceled} (Error ID: ${errorId})`; - this.logger.error( - `Error canceling escrow. Error ID: ${errorId}, Job ID: ${jobEntity.id}, Reason: ${failedReason}, Message: ${err.message}`, - ); + } catch (error) { + this.logger.error('Error canceling escrow', { + jobId: jobEntity.id, + error, + }); await this.jobService.handleProcessJobFailure( jobEntity, - failedReason, + ErrorEscrow.NotCanceled, ); } } - } catch (e) { - this.logger.error(e); + } catch (error) { + this.logger.error('Error in cancelEscrow cron job', error); } await this.completeCronJob(cronJob); - this.logger.log('Cancel jobs STOP'); + this.logger.info('Cancel jobs STOP'); return true; } @@ -338,7 +333,7 @@ export class CronJobService { return; } - this.logger.log('Pending webhooks START'); + this.logger.info('Pending webhooks START'); const cronJob = await this.startCronJob(CronJobType.ProcessPendingWebhook); try { @@ -350,19 +345,22 @@ export class CronJobService { for (const webhookEntity of webhookEntities) { try { await this.webhookService.sendWebhook(webhookEntity); - } catch (err) { - this.logger.error(`Error sending webhook: ${err.message}`); + } catch (error) { + this.logger.error('Error sending webhook', { + webhookId: webhookEntity.id, + error, + }); await this.webhookService.handleWebhookError(webhookEntity); continue; } webhookEntity.status = WebhookStatus.COMPLETED; await this.webhookRepository.updateOne(webhookEntity); } - } catch (e) { - this.logger.error(e); + } catch (error) { + this.logger.error('Error in processPendingWebhooks cron job', error); } - this.logger.log('Pending webhooks STOP'); + this.logger.info('Pending webhooks STOP'); await this.completeCronJob(cronJob); } @@ -378,7 +376,7 @@ export class CronJobService { return; } - this.logger.log('Abuse START'); + this.logger.info('Abuse START'); const cronJob = await this.startCronJob(CronJobType.Abuse); try { @@ -395,7 +393,9 @@ export class CronJobService { webhookEntity.escrowAddress, ); if (!jobEntity) { - this.logger.log(ErrorJob.NotFound, JobService.name); + this.logger.error('Job not found for webhook', { + webhookId: webhookEntity.id, + }); throw new NotFoundError(ErrorJob.NotFound); } if ( @@ -410,21 +410,23 @@ export class CronJobService { await this.jobRepository.updateOne(jobEntity); } await this.paymentService.createSlash(jobEntity); - } catch (err) { - this.logger.error( - `Error slashing escrow (address: ${webhookEntity.escrowAddress}, chainId: ${webhookEntity.chainId}: ${err.message}`, - ); + } catch (error) { + this.logger.error('Error slashing escrow', { + escrowAddress: webhookEntity.escrowAddress, + chainId: webhookEntity.chainId, + error, + }); await this.webhookService.handleWebhookError(webhookEntity); continue; } webhookEntity.status = WebhookStatus.COMPLETED; await this.webhookRepository.updateOne(webhookEntity); } - } catch (e) { - this.logger.error(e); + } catch (error) { + this.logger.error('Error in processAbuse cron job', error); } - this.logger.log('Abuse STOP'); + this.logger.info('Abuse STOP'); await this.completeCronJob(cronJob); } @@ -433,7 +435,7 @@ export class CronJobService { * @returns {Promise} - Returns a promise that resolves when the operation is complete. */ @Cron('30 */2 * * * *') - public async syncJobStuses(): Promise { + public async syncJobStatuses(): Promise { const lastCronJob = await this.cronJobRepository.findOneByType( CronJobType.SyncJobStatuses, ); @@ -442,7 +444,7 @@ export class CronJobService { return; } - this.logger.log('Update jobs START'); + this.logger.info('Update jobs START'); const cronJob = await this.startCronJob(CronJobType.SyncJobStatuses); try { @@ -469,7 +471,7 @@ export class CronJobService { } while (eventsBatch.length === 100); } if (events.length === 0) { - this.logger.log('No events to process'); + this.logger.info('No events to process for syncJobStatuses cron job'); await this.completeCronJob(cronJob); return; } @@ -535,11 +537,11 @@ export class CronJobService { cronJob.lastSubgraphTime = new Date(latestEventTimestamp + 1000); // Add one sec to avoid getting the last processed event await this.cronJobRepository.save(cronJob); } - } catch (e) { - this.logger.error(e); + } catch (error) { + this.logger.error('Error in syncJobStatuses cron job', error); } - this.logger.log('Update jobs STOP'); + this.logger.info('Update jobs STOP'); await this.completeCronJob(cronJob); } } diff --git a/packages/apps/job-launcher/server/src/modules/job/job.controller.spec.ts b/packages/apps/job-launcher/server/src/modules/job/job.controller.spec.ts index 3c33b1179f..36d1da5072 100644 --- a/packages/apps/job-launcher/server/src/modules/job/job.controller.spec.ts +++ b/packages/apps/job-launcher/server/src/modules/job/job.controller.spec.ts @@ -111,7 +111,7 @@ describe('JobController', () => { expect(result).toBe(1); expect(mockMutexManagerService.runExclusive).toHaveBeenCalledWith( - { id: `user${mockRequest.user.id}` }, + `user${mockRequest.user.id}`, MUTEX_TIMEOUT, expect.any(Function), ); @@ -176,7 +176,7 @@ describe('JobController', () => { ).rejects.toThrow('Unauthorized'); expect(mockMutexManagerService.runExclusive).toHaveBeenCalledWith( - { id: `user${mockRequest.user.id}` }, + `user${mockRequest.user.id}`, MUTEX_TIMEOUT, expect.any(Function), ); @@ -206,7 +206,7 @@ describe('JobController', () => { expect(result).toBe(1); expect(mockMutexManagerService.runExclusive).toHaveBeenCalledWith( - { id: `user${mockRequest.user.id}` }, + `user${mockRequest.user.id}`, expect.any(Number), expect.any(Function), ); @@ -227,7 +227,7 @@ describe('JobController', () => { ).rejects.toThrow(UnauthorizedException); expect(mockMutexManagerService.runExclusive).toHaveBeenCalledWith( - { id: `user${mockRequest.user.id}` }, + `user${mockRequest.user.id}`, expect.any(Number), expect.any(Function), ); @@ -244,7 +244,7 @@ describe('JobController', () => { ).rejects.toThrow(ConflictException); expect(mockMutexManagerService.runExclusive).toHaveBeenCalledWith( - { id: `user${mockRequest.user.id}` }, + `user${mockRequest.user.id}`, expect.any(Number), expect.any(Function), ); @@ -261,7 +261,7 @@ describe('JobController', () => { ).rejects.toThrow(BadRequestException); expect(mockMutexManagerService.runExclusive).toHaveBeenCalledWith( - { id: `user${mockRequest.user.id}` }, + `user${mockRequest.user.id}`, expect.any(Number), expect.any(Function), ); @@ -310,7 +310,7 @@ describe('JobController', () => { expect(result).toBe(1); expect(mockMutexManagerService.runExclusive).toHaveBeenCalledWith( - { id: `user${mockRequest.user.id}` }, + `user${mockRequest.user.id}`, expect.any(Number), expect.any(Function), ); @@ -331,7 +331,7 @@ describe('JobController', () => { ).rejects.toThrow(UnauthorizedException); expect(mockMutexManagerService.runExclusive).toHaveBeenCalledWith( - { id: `user${mockRequest.user.id}` }, + `user${mockRequest.user.id}`, expect.any(Number), expect.any(Function), ); @@ -348,7 +348,7 @@ describe('JobController', () => { ).rejects.toThrow(ConflictException); expect(mockMutexManagerService.runExclusive).toHaveBeenCalledWith( - { id: `user${mockRequest.user.id}` }, + `user${mockRequest.user.id}`, expect.any(Number), expect.any(Function), ); @@ -365,7 +365,7 @@ describe('JobController', () => { ).rejects.toThrow(BadRequestException); expect(mockMutexManagerService.runExclusive).toHaveBeenCalledWith( - { id: `user${mockRequest.user.id}` }, + `user${mockRequest.user.id}`, expect.any(Number), expect.any(Function), ); diff --git a/packages/apps/job-launcher/server/src/modules/job/job.controller.ts b/packages/apps/job-launcher/server/src/modules/job/job.controller.ts index 4b6034f1f8..c23e19395d 100644 --- a/packages/apps/job-launcher/server/src/modules/job/job.controller.ts +++ b/packages/apps/job-launcher/server/src/modules/job/job.controller.ts @@ -84,7 +84,7 @@ export class JobController { @Request() req: RequestWithUser, ): Promise { return await this.mutexManagerService.runExclusive( - { id: `user${req.user.id}` }, + `user${req.user.id}`, MUTEX_TIMEOUT, async () => { return await this.jobService.createJob( @@ -128,7 +128,7 @@ export class JobController { } return await this.mutexManagerService.runExclusive( - { id: `user${req.user.id}` }, + `user${req.user.id}`, MUTEX_TIMEOUT, async () => { return await this.jobService.createJob( @@ -168,7 +168,7 @@ export class JobController { @Request() req: RequestWithUser, ): Promise { return await this.mutexManagerService.runExclusive( - { id: `user${req.user.id}` }, + `user${req.user.id}`, MUTEX_TIMEOUT, async () => { return await this.jobService.createJob(req.user, data.type, data); @@ -204,7 +204,7 @@ export class JobController { @Request() req: RequestWithUser, ): Promise { return await this.mutexManagerService.runExclusive( - { id: `user${req.user.id}` }, + `user${req.user.id}`, MUTEX_TIMEOUT, async () => { return await this.jobService.createJob(req.user, data.type, data); @@ -243,7 +243,7 @@ export class JobController { // 'Hcaptcha jobs disabled temporally', // ); // return await this.mutexManagerService.runExclusive( - // { id: `user${req.user.id}` }, + // `user${req.user.id}`, // MUTEX_TIMEOUT, // async () => { // return await this.jobService.createJob( @@ -348,7 +348,7 @@ export class JobController { @Request() req: RequestWithUser, ): Promise { await this.mutexManagerService.runExclusive( - { id: `user${req.user.id}` }, + `user${req.user.id}`, MUTEX_TIMEOUT, async () => { return await this.jobService.requestToCancelJobByAddress( @@ -387,7 +387,7 @@ export class JobController { @Request() req: RequestWithUser, ): Promise { await this.mutexManagerService.runExclusive( - { id: `user${req.user.id}` }, + `user${req.user.id}`, MUTEX_TIMEOUT, async () => { return await this.jobService.requestToCancelJobById( diff --git a/packages/apps/job-launcher/server/src/modules/job/job.module.ts b/packages/apps/job-launcher/server/src/modules/job/job.module.ts index cdca136425..531a5e8beb 100644 --- a/packages/apps/job-launcher/server/src/modules/job/job.module.ts +++ b/packages/apps/job-launcher/server/src/modules/job/job.module.ts @@ -1,4 +1,4 @@ -import { Logger, Module } from '@nestjs/common'; +import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { ConfigModule } from '@nestjs/config'; @@ -35,7 +35,6 @@ import { ManifestModule } from '../manifest/manifest.module'; ], controllers: [JobController], providers: [ - Logger, JobService, JobRepository, WebhookRepository, diff --git a/packages/apps/job-launcher/server/src/modules/job/job.service.ts b/packages/apps/job-launcher/server/src/modules/job/job.service.ts index e18688b745..b619abbcb9 100644 --- a/packages/apps/job-launcher/server/src/modules/job/job.service.ts +++ b/packages/apps/job-launcher/server/src/modules/job/job.service.ts @@ -9,7 +9,7 @@ import { NETWORKS, StorageParams, } from '@human-protocol/sdk'; -import { Inject, Injectable, Logger } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import { ModuleRef } from '@nestjs/core'; import { ValidationError as ClassValidationError, @@ -76,12 +76,15 @@ import { import { JobEntity } from './job.entity'; import { EscrowAction } from './job.interface'; import { JobRepository } from './job.repository'; +import logger from '../../logger'; + @Injectable() export class JobService { - public readonly logger = new Logger(JobService.name); + private readonly logger = logger.child({ context: JobService.name }); public readonly storageParams: StorageParams; public readonly bucket: string; private cronJobRepository: CronJobRepository; + constructor( @Inject(Web3Service) private readonly web3Service: Web3Service, @@ -583,11 +586,10 @@ export class JobService { } if (allFortuneValidationErrors.length > 0) { - this.logger.log( - ErrorJob.ResultValidationFailed, - JobService.name, - allFortuneValidationErrors, - ); + this.logger.error(ErrorJob.ResultValidationFailed, { + jobId: jobEntity.id, + validationErrors: allFortuneValidationErrors, + }); throw new ValidationError(ErrorJob.ResultValidationFailed); } return data; diff --git a/packages/apps/job-launcher/server/src/modules/manifest/manifest.service.ts b/packages/apps/job-launcher/server/src/modules/manifest/manifest.service.ts index 61836dde66..d497c898f2 100644 --- a/packages/apps/job-launcher/server/src/modules/manifest/manifest.service.ts +++ b/packages/apps/job-launcher/server/src/modules/manifest/manifest.service.ts @@ -8,7 +8,6 @@ import { import { ValidationError as ClassValidationError, Injectable, - Logger, } from '@nestjs/common'; import { validate } from 'class-validator'; import { ethers } from 'ethers'; @@ -74,7 +73,6 @@ import { @Injectable() export class ManifestService { - public readonly logger = new Logger(ManifestService.name); public readonly storageParams: StorageParams; public readonly bucket: string; diff --git a/packages/apps/job-launcher/server/src/modules/mutex/mutex-manager.service.spec.ts b/packages/apps/job-launcher/server/src/modules/mutex/mutex-manager.service.spec.ts index c41b3077be..d2c23877a4 100644 --- a/packages/apps/job-launcher/server/src/modules/mutex/mutex-manager.service.spec.ts +++ b/packages/apps/job-launcher/server/src/modules/mutex/mutex-manager.service.spec.ts @@ -22,7 +22,7 @@ describe('MutexManagerService', () => { let task1Executed = false; let task2Executed = false; - const userId = { id: 'user1' }; + const userId = 'user1'; const task1 = service.runExclusive(userId, timeout, async () => { await new Promise((resolve) => setTimeout(resolve, 100)); // Simulate async work @@ -41,7 +41,7 @@ describe('MutexManagerService', () => { }); it('should timeout if lock is not acquired in time', async () => { - const userId = { id: 'user2' }; + const userId = 'user2'; // Simulate a long async work to hold the lock service.runExclusive(userId, timeout, async () => { @@ -53,6 +53,6 @@ describe('MutexManagerService', () => { service.runExclusive(userId, timeout, async () => { await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulate async work }), - ).rejects.toThrow('Function execution timed out for user2'); + ).rejects.toThrow('Function execution timed out for key'); }); }); diff --git a/packages/apps/job-launcher/server/src/modules/mutex/mutex-manager.service.ts b/packages/apps/job-launcher/server/src/modules/mutex/mutex-manager.service.ts index 159face8a5..30b0e50a76 100644 --- a/packages/apps/job-launcher/server/src/modules/mutex/mutex-manager.service.ts +++ b/packages/apps/job-launcher/server/src/modules/mutex/mutex-manager.service.ts @@ -1,15 +1,16 @@ -import { Injectable, Logger, OnModuleDestroy } from '@nestjs/common'; +import { Injectable, OnModuleDestroy } from '@nestjs/common'; import { E_TIMEOUT, Mutex, MutexInterface, withTimeout } from 'async-mutex'; import { ServerError } from '../../common/errors'; +import logger from '../../logger'; @Injectable() export class MutexManagerService implements OnModuleDestroy { - private mutexes: WeakMap = new WeakMap(); - private mutexTimeouts: Map = new Map(); + private mutexes: Map = new Map(); + private mutexTimeouts: Map = new Map(); private mutexTimeoutDuration = 120000; // 2 minutes - public readonly logger = new Logger(MutexManagerService.name); + private readonly logger = logger.child({ context: MutexManagerService.name }); - private getMutex(key: object, timeout: number): MutexInterface { + private getMutex(key: string, timeout: number): MutexInterface { if (!this.mutexes.has(key)) { const mutex: MutexInterface = withTimeout( new Mutex(), @@ -23,7 +24,7 @@ export class MutexManagerService implements OnModuleDestroy { return this.mutexes.get(key)!; } - private scheduleMutexCleanup(key: object): void { + private scheduleMutexCleanup(key: string): void { if (this.mutexTimeouts.has(key)) { clearTimeout(this.mutexTimeouts.get(key)); } @@ -34,47 +35,43 @@ export class MutexManagerService implements OnModuleDestroy { this.mutexTimeouts.set(key, timeout); } - private cleanupMutex(key: object): void { + private cleanupMutex(key: string): void { this.mutexes.delete(key); this.mutexTimeouts.delete(key); } async runExclusive( - key: object, + key: string, timeout: number, callback: () => Promise, ): Promise { const mutex = this.getMutex(key, timeout); try { - this.logger.log( - `Attempting to acquire lock for ${(key as any).id as string}...`, - ); + this.logger.debug('Attempting to acquire lock for key', { + key, + }); + const result = await mutex.runExclusive(async () => { - this.logger.log( - `Lock acquired for ${(key as any).id as string}, executing function...`, - ); - this.logger.log( - `Function executed for ${(key as any).id as string}, lock released.`, - ); + this.logger.debug('`Lock acquired for key', { + key, + }); return await callback(); }); + + this.logger.debug('Function executed for key, lock released', { + key, + }); + return result; } catch (e) { if (e === E_TIMEOUT) { - this.logger.error( - `Function execution timed out for ${(key as any).id as string}`, - ); - throw new Error( - `Function execution timed out for ${(key as any).id as string}`, - ); + const errorMessage = 'Function execution timed out for key'; + this.logger.error(errorMessage, { key }); + throw new Error(errorMessage); } - this.logger.error( - `Function execution failed for ${(key as any).id as string}`, - e, - ); - throw new ServerError( - `Function execution failed for ${(key as any).id as string}`, - ); + const errorMessage = 'Function execution failed for key'; + this.logger.error(errorMessage, { key }); + throw new ServerError(errorMessage); } } diff --git a/packages/apps/job-launcher/server/src/modules/payment/payment.service.ts b/packages/apps/job-launcher/server/src/modules/payment/payment.service.ts index 6454eef906..f8bd94c771 100644 --- a/packages/apps/job-launcher/server/src/modules/payment/payment.service.ts +++ b/packages/apps/job-launcher/server/src/modules/payment/payment.service.ts @@ -3,7 +3,7 @@ import { HMToken, HMToken__factory, } from '@human-protocol/core/typechain-types'; -import { Injectable, Logger } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { ethers, formatUnits } from 'ethers'; import { NetworkConfigService } from '../../common/config/network-config.service'; import { ServerConfigService } from '../../common/config/server-config.service'; @@ -46,10 +46,11 @@ import { RateService } from '../rate/rate.service'; import { UserEntity } from '../user/user.entity'; import { UserRepository } from '../user/user.repository'; import { PaymentProvider } from './providers/payment-provider.abstract'; +import logger from '../../logger'; @Injectable() export class PaymentService { - private readonly logger = new Logger(PaymentService.name); + private readonly logger = logger.child({ context: PaymentService.name }); constructor( private readonly networkConfigService: NetworkConfigService, @@ -79,7 +80,10 @@ export class PaymentService { const setup = await this.paymentProvider.retrieveCardSetup(data.setupId); if (!setup) { - this.logger.log(ErrorPayment.SetupNotFound, PaymentService.name); + this.logger.error(ErrorPayment.SetupNotFound, { + userId: user.id, + setupId: data.setupId, + }); throw new NotFoundError(ErrorPayment.SetupNotFound); } @@ -222,9 +226,14 @@ export class PaymentService { throw new ServerError(ErrorPayment.InvalidTransactionData); } - if ((await transaction.confirmations()) < TX_CONFIRMATION_TRESHOLD) { + const nConfirmations = await transaction.confirmations(); + if (nConfirmations < TX_CONFIRMATION_TRESHOLD) { this.logger.error( - `Transaction has ${transaction.confirmations} confirmations instead of ${TX_CONFIRMATION_TRESHOLD}`, + 'Number of confirmations for transaction is less than threshold', + { + nConfirmations, + threshold: TX_CONFIRMATION_TRESHOLD, + }, ); throw new ConflictError( ErrorPayment.TransactionHasNotEnoughAmountOfConfirmations, diff --git a/packages/apps/job-launcher/server/src/modules/payment/providers/payment-provider.abstract.ts b/packages/apps/job-launcher/server/src/modules/payment/providers/payment-provider.abstract.ts index 6adca84442..939a359b6e 100644 --- a/packages/apps/job-launcher/server/src/modules/payment/providers/payment-provider.abstract.ts +++ b/packages/apps/job-launcher/server/src/modules/payment/providers/payment-provider.abstract.ts @@ -1,3 +1,4 @@ +import { Injectable } from '@nestjs/common'; import { CardSetup, CustomerData, @@ -6,12 +7,9 @@ import { PaymentMethod, } from '../payment.interface'; import { BillingInfoDto } from '../payment.dto'; -import { Injectable, Logger } from '@nestjs/common'; @Injectable() export abstract class PaymentProvider { - protected readonly logger: Logger = new Logger(this.constructor.name); - /** * Create a new customer in the payment provider system * @param email Customer's email address diff --git a/packages/apps/job-launcher/server/src/modules/payment/providers/stripe/stripe.service.spec.ts b/packages/apps/job-launcher/server/src/modules/payment/providers/stripe/stripe.service.spec.ts index fed082f457..0d9c24098d 100644 --- a/packages/apps/job-launcher/server/src/modules/payment/providers/stripe/stripe.service.spec.ts +++ b/packages/apps/job-launcher/server/src/modules/payment/providers/stripe/stripe.service.spec.ts @@ -3,7 +3,6 @@ jest.mock('stripe'); import { faker } from '@faker-js/faker'; import { PaymentData } from '../../payment.interface'; import { Test, TestingModule } from '@nestjs/testing'; -import { Logger } from '@nestjs/common'; import { StripePaymentStatus, StripeService } from './stripe.service'; import { PaymentProviderConfigService } from '../../../../common/config/payment-provider-config.service'; import Stripe from 'stripe'; @@ -28,7 +27,6 @@ import { describe('StripeService', () => { let service: StripeService; let stripeMock: jest.Mocked; - let loggerSpy: jest.SpyInstance; const mockStripeConfigService = { secretKey: 'test_key', @@ -88,7 +86,6 @@ describe('StripeService', () => { } as unknown as jest.Mocked; (service as any).stripe = stripeMock; - loggerSpy = jest.spyOn(Logger.prototype, 'log'); }); afterEach(() => { @@ -121,7 +118,6 @@ describe('StripeService', () => { await expect(service.createCustomer(email)).rejects.toThrow( new ServerError(ErrorPayment.CustomerNotCreated), ); - expect(loggerSpy).toHaveBeenCalled(); }); }); diff --git a/packages/apps/job-launcher/server/src/modules/payment/providers/stripe/stripe.service.ts b/packages/apps/job-launcher/server/src/modules/payment/providers/stripe/stripe.service.ts index b40a39d655..894b73d0bc 100644 --- a/packages/apps/job-launcher/server/src/modules/payment/providers/stripe/stripe.service.ts +++ b/packages/apps/job-launcher/server/src/modules/payment/providers/stripe/stripe.service.ts @@ -14,6 +14,7 @@ import { } from '../../payment.interface'; import { PaymentProvider } from '../payment-provider.abstract'; import { AddressDto, BillingInfoDto } from '../../payment.dto'; +import logger from '../../../../logger'; export enum StripePaymentStatus { CANCELED = 'canceled', @@ -23,6 +24,7 @@ export enum StripePaymentStatus { @Injectable() export class StripeService extends PaymentProvider { + private readonly logger = logger.child({ context: StripeService.name }); private stripe: Stripe; constructor(private stripeConfigService: PaymentProviderConfigService) { @@ -43,7 +45,7 @@ export class StripeService extends PaymentProvider { const customer = await this.stripe.customers.create({ email }); return customer.id; } catch (error) { - this.logger.log(error.message, StripeService.name); + this.logger.error('Error while creating stripe customer', error); throw new ServerError(ErrorPayment.CustomerNotCreated); } } @@ -57,15 +59,17 @@ export class StripeService extends PaymentProvider { customer: customerId ?? undefined, }); } catch (error) { - this.logger.log(error.message, StripeService.name); + this.logger.error('Error while setting up card', { + customerId, + error, + }); throw new ServerError(ErrorPayment.CardNotAssigned); } if (!setupIntent?.client_secret) { - this.logger.log( - ErrorPayment.ClientSecretDoesNotExist, - StripeService.name, - ); + this.logger.error('ErrorPayment.ClientSecretDoesNotExist', { + customerId, + }); throw new ServerError(ErrorPayment.ClientSecretDoesNotExist); } @@ -335,7 +339,7 @@ export class StripeService extends PaymentProvider { ); return { - email: customer.email!, + email: customer.email as string, name: customer.name ?? undefined, address: customer.address ? { @@ -357,7 +361,7 @@ export class StripeService extends PaymentProvider { )) as Stripe.Customer; return { - email: customer.email!, + email: customer.email as string, name: customer.name ?? undefined, address: customer.address ? { diff --git a/packages/apps/job-launcher/server/src/modules/qualification/qualification.module.ts b/packages/apps/job-launcher/server/src/modules/qualification/qualification.module.ts index 934c00ee6b..c69913070f 100644 --- a/packages/apps/job-launcher/server/src/modules/qualification/qualification.module.ts +++ b/packages/apps/job-launcher/server/src/modules/qualification/qualification.module.ts @@ -1,4 +1,4 @@ -import { Logger, Module } from '@nestjs/common'; +import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { QualificationService } from './qualification.service'; import { QualificationController } from './qualification.controller'; @@ -7,7 +7,7 @@ import { Web3Module } from '../web3/web3.module'; @Module({ imports: [ConfigModule, HttpModule, Web3Module], - providers: [Logger, QualificationService], + providers: [QualificationService], controllers: [QualificationController], exports: [QualificationService], }) diff --git a/packages/apps/job-launcher/server/src/modules/qualification/qualification.service.ts b/packages/apps/job-launcher/server/src/modules/qualification/qualification.service.ts index 00837e962a..a4867f8f31 100644 --- a/packages/apps/job-launcher/server/src/modules/qualification/qualification.service.ts +++ b/packages/apps/job-launcher/server/src/modules/qualification/qualification.service.ts @@ -1,16 +1,19 @@ import { ChainId, KVStoreKeys, KVStoreUtils } from '@human-protocol/sdk'; import { HttpService } from '@nestjs/axios'; -import { Injectable, Logger } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { firstValueFrom } from 'rxjs'; import { Web3ConfigService } from '../../common/config/web3-config.service'; import { ErrorQualification, ErrorWeb3 } from '../../common/constants/errors'; import { ServerError } from '../../common/errors'; import { Web3Service } from '../web3/web3.service'; import { QualificationDto } from './qualification.dto'; +import logger from '../../logger'; @Injectable() export class QualificationService { - private readonly logger = new Logger(QualificationService.name); + private readonly logger = logger.child({ + context: QualificationService.name, + }); constructor( private httpService: HttpService, @@ -46,7 +49,8 @@ export class QualificationService { return data; } catch (error) { this.logger.error( - `Error fetching qualifications from reputation oracle: ${error}`, + 'Error fetching qualifications from reputation oracle', + error, ); throw new ServerError(ErrorQualification.FailedToFetchQualifications); } diff --git a/packages/apps/job-launcher/server/src/modules/rate/rate.service.ts b/packages/apps/job-launcher/server/src/modules/rate/rate.service.ts index 8c5b008e62..97008852f4 100644 --- a/packages/apps/job-launcher/server/src/modules/rate/rate.service.ts +++ b/packages/apps/job-launcher/server/src/modules/rate/rate.service.ts @@ -1,5 +1,5 @@ import { HttpService } from '@nestjs/axios'; -import { Injectable, Logger } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { firstValueFrom } from 'rxjs'; import { ServerConfigService } from '../../common/config/server-config.service'; import { COINGECKO_API_URL } from '../../common/constants'; @@ -7,10 +7,11 @@ import { ErrorCurrency } from '../../common/constants/errors'; import { CoingeckoTokenId } from '../../common/constants/payment'; import { EscrowFundToken } from '../../common/enums/job'; import { NotFoundError } from '../../common/errors'; +import logger from '../../logger'; @Injectable() export class RateService { - public readonly logger = new Logger(RateService.name); + private readonly logger = logger.child({ context: RateService.name }); private cache: Map; constructor( @@ -76,7 +77,11 @@ export class RateService { return finalRate; } catch (error) { - this.logger.error(error); + this.logger.error('Error while getting rate', { + from, + to, + error, + }); throw new NotFoundError(ErrorCurrency.PairNotFound); } } diff --git a/packages/apps/job-launcher/server/src/modules/routing-protocol/routing-protocol.service.ts b/packages/apps/job-launcher/server/src/modules/routing-protocol/routing-protocol.service.ts index f57657182b..f32b1f2160 100644 --- a/packages/apps/job-launcher/server/src/modules/routing-protocol/routing-protocol.service.ts +++ b/packages/apps/job-launcher/server/src/modules/routing-protocol/routing-protocol.service.ts @@ -1,5 +1,5 @@ import { ChainId, Role } from '@human-protocol/sdk'; -import { Injectable, Logger } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { NetworkConfigService } from '../../common/config/network-config.service'; import { Web3ConfigService } from '../../common/config/web3-config.service'; import { ErrorRoutingProtocol } from '../../common/constants/errors'; @@ -26,7 +26,6 @@ type OracleValue = { @Injectable() export class RoutingProtocolService { - public readonly logger = new Logger(RoutingProtocolService.name); private readonly chains: ChainId[]; private readonly reputationOracles: string[]; private readonly chainPriorityOrder: number[]; diff --git a/packages/apps/job-launcher/server/src/modules/sendgrid/sendgrid.service.ts b/packages/apps/job-launcher/server/src/modules/sendgrid/sendgrid.service.ts index 5a5c9bd71f..a00bc46c59 100644 --- a/packages/apps/job-launcher/server/src/modules/sendgrid/sendgrid.service.ts +++ b/packages/apps/job-launcher/server/src/modules/sendgrid/sendgrid.service.ts @@ -1,4 +1,4 @@ -import { Injectable, Logger } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { MailDataRequired, MailService } from '@sendgrid/mail'; import { SendgridConfigService } from '../../common/config/sendgrid-config.service'; import { @@ -7,10 +7,11 @@ import { } from '../../common/constants'; import { ErrorSendGrid } from '../../common/constants/errors'; import { ConflictError, ServerError } from '../../common/errors'; +import logger from '../../logger'; @Injectable() export class SendGridService { - private readonly logger = new Logger(SendGridService.name); + private readonly logger = logger.child({ context: SendGridService.name }); private readonly defaultFromEmail: string; private readonly defaultFromName: string; @@ -44,7 +45,7 @@ export class SendGridService { }: Partial): Promise { try { if (this.sendgridConfigService.apiKey === SENDGRID_API_KEY_DISABLED) { - this.logger.debug(personalizations); + this.logger.debug('Sending email in dev mode', { personalizations }); return; } @@ -54,10 +55,12 @@ export class SendGridService { personalizations, ...emailData, }); - this.logger.log('Email sent successfully'); return; } catch (error) { - this.logger.error(error, SendGridService.name); + this.logger.error('Error while sending email', { + error, + templateId, + }); throw new ServerError(ErrorSendGrid.EmailNotSent); } } diff --git a/packages/apps/job-launcher/server/src/modules/user/user.module.ts b/packages/apps/job-launcher/server/src/modules/user/user.module.ts index 63814b47ae..65c7b47395 100644 --- a/packages/apps/job-launcher/server/src/modules/user/user.module.ts +++ b/packages/apps/job-launcher/server/src/modules/user/user.module.ts @@ -1,4 +1,4 @@ -import { Logger, Module, forwardRef } from '@nestjs/common'; +import { Module, forwardRef } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { ConfigModule } from '@nestjs/config'; @@ -15,7 +15,7 @@ import { AuthModule } from '../auth/auth.module'; PaymentModule, forwardRef(() => AuthModule), ], - providers: [Logger, UserService, UserRepository], + providers: [UserService, UserRepository], exports: [UserService], }) export class UserModule {} diff --git a/packages/apps/job-launcher/server/src/modules/web3/web3.service.ts b/packages/apps/job-launcher/server/src/modules/web3/web3.service.ts index b05e971802..26979e3338 100644 --- a/packages/apps/job-launcher/server/src/modules/web3/web3.service.ts +++ b/packages/apps/job-launcher/server/src/modules/web3/web3.service.ts @@ -1,15 +1,16 @@ import { ChainId, OperatorUtils, Role } from '@human-protocol/sdk'; -import { Injectable, Logger } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { Wallet, ethers } from 'ethers'; import { NetworkConfigService } from '../../common/config/network-config.service'; import { Web3ConfigService } from '../../common/config/web3-config.service'; import { ErrorWeb3 } from '../../common/constants/errors'; import { ConflictError, ValidationError } from '../../common/errors'; import { AvailableOraclesDto, OracleDataDto } from './web3.dto'; +import logger from '../../logger'; @Injectable() export class Web3Service { - public readonly logger = new Logger(Web3Service.name); + private readonly logger = logger.child({ context: Web3Service.name }); private signers: { [key: number]: Wallet } = {}; public readonly signerAddress: string; @@ -95,7 +96,12 @@ export class Web3Service { return filteredOracles; } catch (error) { - this.logger.error(`Error processing chainId ${chainId}:`, error); + this.logger.error('Error processing chainId', { + chainId, + jobType, + address, + error, + }); } return []; } @@ -139,9 +145,10 @@ export class Web3Service { ); if (!operator || !operator.reputationNetworks) { - this.logger.error( - `Operator or reputation networks not found for chain ${chainId}.`, - ); + this.logger.error('Operator or reputation networks not found for chain', { + chainId, + jobType, + }); return []; } @@ -158,10 +165,12 @@ export class Web3Service { ? networkOperator.address : null; } catch (error) { - this.logger.error( - `Failed to fetch operator for address ${address} on chain ${chainId}:`, + this.logger.error('Failed to fetch operator for address', { + chainId, + address, + jobType, error, - ); + }); return null; } }), diff --git a/packages/apps/job-launcher/server/src/modules/webhook/webhook.module.ts b/packages/apps/job-launcher/server/src/modules/webhook/webhook.module.ts index dab2beb310..4d3427fc10 100644 --- a/packages/apps/job-launcher/server/src/modules/webhook/webhook.module.ts +++ b/packages/apps/job-launcher/server/src/modules/webhook/webhook.module.ts @@ -1,4 +1,4 @@ -import { Logger, Module } from '@nestjs/common'; +import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { ConfigModule } from '@nestjs/config'; @@ -21,7 +21,7 @@ import { JobRepository } from '../job/job.repository'; HttpModule, ], controllers: [WebhookController], - providers: [Logger, WebhookService, WebhookRepository, JobRepository], + providers: [WebhookService, WebhookRepository, JobRepository], exports: [WebhookService], }) export class WebhookModule {} diff --git a/packages/apps/job-launcher/server/src/modules/webhook/webhook.repository.ts b/packages/apps/job-launcher/server/src/modules/webhook/webhook.repository.ts index 1c5fe17804..3be1173071 100644 --- a/packages/apps/job-launcher/server/src/modules/webhook/webhook.repository.ts +++ b/packages/apps/job-launcher/server/src/modules/webhook/webhook.repository.ts @@ -1,4 +1,4 @@ -import { Injectable, Logger } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { BaseRepository } from '../../database/base.repository'; import { DataSource, In, LessThanOrEqual } from 'typeorm'; @@ -8,10 +8,9 @@ import { WebhookEntity } from './webhook.entity'; @Injectable() export class WebhookRepository extends BaseRepository { - private readonly logger = new Logger(WebhookRepository.name); constructor( - private dataSource: DataSource, - public readonly serverConfigService: ServerConfigService, + dataSource: DataSource, + readonly serverConfigService: ServerConfigService, ) { super(WebhookEntity, dataSource); } diff --git a/packages/apps/job-launcher/server/src/modules/webhook/webhook.service.ts b/packages/apps/job-launcher/server/src/modules/webhook/webhook.service.ts index 4bb967ca39..dd76cd0a9b 100644 --- a/packages/apps/job-launcher/server/src/modules/webhook/webhook.service.ts +++ b/packages/apps/job-launcher/server/src/modules/webhook/webhook.service.ts @@ -6,7 +6,7 @@ import { KVStoreUtils, } from '@human-protocol/sdk'; import { HttpService } from '@nestjs/axios'; -import { Inject, Injectable, Logger } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import { firstValueFrom } from 'rxjs'; import { ServerConfigService } from '../../common/config/server-config.service'; import { Web3ConfigService } from '../../common/config/web3-config.service'; @@ -23,10 +23,11 @@ import { Web3Service } from '../web3/web3.service'; import { WebhookDataDto } from './webhook.dto'; import { WebhookEntity } from './webhook.entity'; import { WebhookRepository } from './webhook.repository'; +import logger from '../../logger'; @Injectable() export class WebhookService { - private readonly logger = new Logger(WebhookService.name); + private readonly logger = logger.child({ context: WebhookService.name }); constructor( @Inject(Web3Service) @@ -85,6 +86,7 @@ export class WebhookService { } catch (error) { const formattedError = formatAxiosError(error); this.logger.error('Webhook not sent', { + webhookId: webhook.id, error: formattedError, }); throw new Error(formattedError.message); diff --git a/packages/apps/job-launcher/server/typeorm.config.ts b/packages/apps/job-launcher/server/typeorm.config.ts index 8f9702ab7b..d58d85e3e8 100644 --- a/packages/apps/job-launcher/server/typeorm.config.ts +++ b/packages/apps/job-launcher/server/typeorm.config.ts @@ -2,10 +2,13 @@ import { DataSource } from 'typeorm'; import { SnakeNamingStrategy } from 'typeorm-naming-strategies'; import * as dotenv from 'dotenv'; +import Environment from './src/common/utils/environment'; + dotenv.config({ - path: process.env.NODE_ENV - ? `.env.${process.env.NODE_ENV as string}` - : '.env', + /** + * First value wins if "override" option is not set + */ + path: [`.env.${Environment.name}`, '.env'], }); export default new DataSource({ diff --git a/packages/apps/reputation-oracle/server/src/database/migrations/1750766313641-AddReasonToAbuse.ts b/packages/apps/reputation-oracle/server/src/database/migrations/1750766313641-AddReasonToAbuse.ts index da01de6e2f..bbc84f71cd 100644 --- a/packages/apps/reputation-oracle/server/src/database/migrations/1750766313641-AddReasonToAbuse.ts +++ b/packages/apps/reputation-oracle/server/src/database/migrations/1750766313641-AddReasonToAbuse.ts @@ -4,7 +4,9 @@ export class AddReasonToAbuse1750766313641 implements MigrationInterface { name = 'AddReasonToAbuse1750766313641'; public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "hmt"."abuses" ADD "reason" text NOT NULL`); + await queryRunner.query( + `ALTER TABLE "hmt"."abuses" ADD "reason" text NOT NULL`, + ); } public async down(queryRunner: QueryRunner): Promise { diff --git a/yarn.lock b/yarn.lock index f4a4774389..a9334c71b9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4410,6 +4410,7 @@ __metadata: "@golevelup/ts-jest": "npm:^0.6.1" "@google-cloud/storage": "npm:^7.15.0" "@google-cloud/vision": "npm:^4.3.2" + "@human-protocol/logger": "workspace:*" "@human-protocol/sdk": "workspace:*" "@nestjs/axios": "npm:^3.1.2" "@nestjs/cli": "npm:^10.3.2"