diff --git a/src/config/entities/__tests__/configuration.ts b/src/config/entities/__tests__/configuration.ts index ce800413db..8d7fbed034 100644 --- a/src/config/entities/__tests__/configuration.ts +++ b/src/config/entities/__tests__/configuration.ts @@ -114,6 +114,7 @@ export default (): ReturnType => ({ swapsDecoding: true, twapsDecoding: true, debugLogs: false, + configHooksDebugLogs: false, imitationMapping: false, auth: false, confirmationView: false, diff --git a/src/config/entities/configuration.ts b/src/config/entities/configuration.ts index 317142a06c..4387f1f26f 100644 --- a/src/config/entities/configuration.ts +++ b/src/config/entities/configuration.ts @@ -170,6 +170,8 @@ export default () => ({ swapsDecoding: process.env.FF_SWAPS_DECODING?.toLowerCase() === 'true', twapsDecoding: process.env.FF_TWAPS_DECODING?.toLowerCase() === 'true', debugLogs: process.env.FF_DEBUG_LOGS?.toLowerCase() === 'true', + configHooksDebugLogs: + process.env.FF_CONFIG_HOOKS_DEBUG_LOGS?.toLowerCase() === 'true', imitationMapping: process.env.FF_IMITATION_MAPPING?.toLowerCase() === 'true', auth: process.env.FF_AUTH?.toLowerCase() === 'true', diff --git a/src/datasources/cache/cache.first.data.source.spec.ts b/src/datasources/cache/cache.first.data.source.spec.ts index 2066ff10b2..32492c5477 100644 --- a/src/datasources/cache/cache.first.data.source.spec.ts +++ b/src/datasources/cache/cache.first.data.source.spec.ts @@ -33,6 +33,7 @@ describe('CacheFirstDataSource', () => { fakeCacheService = new FakeCacheService(); fakeConfigurationService = new FakeConfigurationService(); fakeConfigurationService.set('features.debugLogs', true); + fakeConfigurationService.set('features.configHooksDebugLogs', false); cacheFirstDataSource = new CacheFirstDataSource( fakeCacheService, mockNetworkService, diff --git a/src/datasources/cache/cache.first.data.source.ts b/src/datasources/cache/cache.first.data.source.ts index dd0c5822d0..cafe562f39 100644 --- a/src/datasources/cache/cache.first.data.source.ts +++ b/src/datasources/cache/cache.first.data.source.ts @@ -35,6 +35,7 @@ import { Safe } from '@/domain/safe/entities/safe.entity'; @Injectable() export class CacheFirstDataSource { private readonly areDebugLogsEnabled: boolean; + private readonly areConfigHooksDebugLogsEnabled: boolean; constructor( @Inject(CacheService) private readonly cacheService: ICacheService, @@ -45,6 +46,10 @@ export class CacheFirstDataSource { ) { this.areDebugLogsEnabled = this.configurationService.getOrThrow('features.debugLogs'); + this.areConfigHooksDebugLogsEnabled = + this.configurationService.getOrThrow( + 'features.configHooksDebugLogs', + ); } /** @@ -149,6 +154,13 @@ export class CacheFirstDataSource { data as Safe, ); } + + if ( + this.areConfigHooksDebugLogsEnabled && + args.cacheDir.key.includes('chain') + ) { + this.logChainUpdateCacheWrite(startTimeMs, args.cacheDir, data); + } } return data; } @@ -267,4 +279,24 @@ export class CacheFirstDataSource { safe, }); } + + /** + * Logs the chain/chains retrieved. + * NOTE: this is a debugging-only function. + * TODO: remove this function after debugging. + */ + private logChainUpdateCacheWrite( + requestStartTime: number, + cacheDir: CacheDir, + data: unknown, + ): void { + this.loggingService.info({ + type: 'cache_write', + cacheKey: cacheDir.key, + cacheField: cacheDir.field, + cacheWriteTime: new Date(), + requestStartTime: new Date(requestStartTime), + data, + }); + } } diff --git a/src/datasources/config-api/config-api.service.spec.ts b/src/datasources/config-api/config-api.service.spec.ts index 7020a732ec..b25b1bc998 100644 --- a/src/datasources/config-api/config-api.service.spec.ts +++ b/src/datasources/config-api/config-api.service.spec.ts @@ -7,6 +7,7 @@ import { HttpErrorFactory } from '@/datasources/errors/http-error-factory'; import { chainBuilder } from '@/domain/chains/entities/__tests__/chain.builder'; import { DataSourceError } from '@/domain/errors/data-source.error'; import { safeAppBuilder } from '@/domain/safe-apps/entities/__tests__/safe-app.builder'; +import { ILoggingService } from '@/logging/logging.interface'; import { faker } from '@faker-js/faker'; const dataSource = { @@ -25,6 +26,10 @@ const httpErrorFactory = { } as jest.MockedObjectDeep; const mockHttpErrorFactory = jest.mocked(httpErrorFactory); +const mockLoggingService = { + info: jest.fn(), +} as jest.MockedObjectDeep; + describe('ConfigApi', () => { const baseUri = faker.internet.url({ appendSlash: false }); const expirationTimeInSeconds = faker.number.int(); @@ -43,6 +48,7 @@ describe('ConfigApi', () => { 'expirationTimeInSeconds.notFound.default', notFoundExpirationTimeInSeconds, ); + fakeConfigurationService.set('features.configHooksDebugLogs', false); }); beforeEach(() => { @@ -52,6 +58,7 @@ describe('ConfigApi', () => { mockCacheService, fakeConfigurationService, mockHttpErrorFactory, + mockLoggingService, ); }); @@ -65,6 +72,7 @@ describe('ConfigApi', () => { mockCacheService, fakeConfigurationService, mockHttpErrorFactory, + mockLoggingService, ), ).toThrow(); }); diff --git a/src/datasources/config-api/config-api.service.ts b/src/datasources/config-api/config-api.service.ts index e9c0dacbf0..56e47cc5dd 100644 --- a/src/datasources/config-api/config-api.service.ts +++ b/src/datasources/config-api/config-api.service.ts @@ -1,4 +1,3 @@ -import { Inject, Injectable } from '@nestjs/common'; import { IConfigurationService } from '@/config/configuration.service.interface'; import { CacheFirstDataSource } from '@/datasources/cache/cache.first.data.source'; import { CacheRouter } from '@/datasources/cache/cache.router'; @@ -11,12 +10,15 @@ import { Chain } from '@/domain/chains/entities/chain.entity'; import { Page } from '@/domain/entities/page.entity'; import { IConfigApi } from '@/domain/interfaces/config-api.interface'; import { SafeApp } from '@/domain/safe-apps/entities/safe-app.entity'; +import { ILoggingService, LoggingService } from '@/logging/logging.interface'; +import { Inject, Injectable } from '@nestjs/common'; @Injectable() export class ConfigApi implements IConfigApi { private readonly baseUri: string; private readonly defaultExpirationTimeInSeconds: number; private readonly defaultNotFoundExpirationTimeSeconds: number; + private readonly areConfigHooksDebugLogsEnabled: boolean; constructor( private readonly dataSource: CacheFirstDataSource, @@ -24,6 +26,7 @@ export class ConfigApi implements IConfigApi { @Inject(IConfigurationService) private readonly configurationService: IConfigurationService, private readonly httpErrorFactory: HttpErrorFactory, + @Inject(LoggingService) private readonly loggingService: ILoggingService, ) { this.baseUri = this.configurationService.getOrThrow('safeConfig.baseUri'); @@ -35,6 +38,10 @@ export class ConfigApi implements IConfigApi { this.configurationService.getOrThrow( 'expirationTimeInSeconds.notFound.default', ); + this.areConfigHooksDebugLogsEnabled = + this.configurationService.getOrThrow( + 'features.configHooksDebugLogs', + ); } async getChains(args: { @@ -76,6 +83,10 @@ export class ConfigApi implements IConfigApi { async clearChain(chainId: string): Promise { const chainCacheKey = CacheRouter.getChainCacheKey(chainId); const chainsCacheKey = CacheRouter.getChainsCacheKey(); + if (this.areConfigHooksDebugLogsEnabled) { + this.loggingService.info(`Clearing chain ${chainId}: ${chainCacheKey}`); + this.loggingService.info(`Clearing chains: ${chainsCacheKey}`); + } await Promise.all([ this.cacheService.deleteByKey(chainCacheKey), this.cacheService.deleteByKey(chainsCacheKey),