From ade60c21bd93d4c68e05bc76eb1be604ce6877da Mon Sep 17 00:00:00 2001 From: George Oastler Date: Fri, 26 Jun 2026 00:44:45 +0100 Subject: [PATCH] refactor(logger): bind repeated log context with child loggers Use Logger.with to bind context once rather than repeating the same data block in every log call across mongo, redis-client, env startup cleanup, and provider IP validation. --- .changeset/logger-with-child-loggers.md | 8 +++++ .../.gradle/8.7/fileHashes/fileHashes.bin | Bin 77515 -> 79265 bytes .../.gradle/8.7/fileHashes/fileHashes.lock | Bin 17 -> 17 bytes .../android-webview/.gradle/file-system.probe | Bin 8 -> 8 bytes packages/database/src/base/mongo.ts | 15 ++------- packages/env/src/provider.ts | 8 ++--- packages/provider/src/util.ts | 29 ++++++------------ packages/redis-client/src/redisClient.ts | 20 +++++------- 8 files changed, 33 insertions(+), 47 deletions(-) create mode 100644 .changeset/logger-with-child-loggers.md diff --git a/.changeset/logger-with-child-loggers.md b/.changeset/logger-with-child-loggers.md new file mode 100644 index 0000000000..b4f1e46bdd --- /dev/null +++ b/.changeset/logger-with-child-loggers.md @@ -0,0 +1,8 @@ +--- +"@prosopo/database": patch +"@prosopo/env": patch +"@prosopo/redis-client": patch +"@prosopo/provider": patch +--- + +Bind repeated log context once with `Logger.with` instead of re-attaching the same data on every log call (mongo `mongoUrl`, redis `url`/`name`, provider startup-cleanup `failedFuncName`, and IP validation `challengeIp`/`providedIp`). diff --git a/demos/android-webview/.gradle/8.7/fileHashes/fileHashes.bin b/demos/android-webview/.gradle/8.7/fileHashes/fileHashes.bin index 3bce0826de2a31206ab198ad640de45bb4736cbf..dd7e4c03e1f2975d598450b819dd24933f6fc1f6 100644 GIT binary patch delta 1280 zcmX|;dq`7J9LGI#T4HvtEHZD}oKaam=H^BXSx-W5KIW#2q(-gmVNwx2s7zx}R)k3% zdYYAGSiveeNtr=d2*r@FCpWV>EvQyjYUNn3ljq)Z{<-(}`F(%i-|w8Cr(0R?SKcs8 z043Nsp%lQG*Bp12oehNiKOmzVAB(*WxI<6-`@>>iY^OARI$k(28o-pxVyAikXbSc3 za9&(7fa^1x9IvJXDb%*(y7+nkR|&m=%(zSn(>%zicERLH+=IC#4V397W4D@E##Cko z+Q&O3=*P_o#Y!0I8J&K#d6xwD%iPo;zL7^UF^VHICsIJ;ru-7Q{F)YA! zDGA}6x1%^1I3diJr17X(-;>lAy4W)$s@f?`zxP)NJ9m-w`wNC8vMTEj7 zN5-8T_&CBsfEHobTVE)w5p89kQcg+ApJ>A@E4uoAIX7+J{r6d_sWWII!;8U(1At5I zJ|M14TGc_R(TrUm$?n3ttnu#bPZXy8#+`mmC{zewLznKRWUNIMW)n{Q@({pN@awVU zALk_F80`D%RKS=L<$yiw1cm8Kk!jEbMSEkFP`R8kLnAI7JP2UrZ0nYzk49JsFh-&e zLp_`$uDaD$b|#A|buGB<`xOQ3yt`89U*nZ5tC4d!fm_$NS3GXfm?<=FLOX|jFu!Q- zGxvh$lw}Cm8fXF2az~Aw+%W081l{tUw-(IY9rSr4B-d{k1P6d3(b=TA5p}C>3`k2v zgGHLK+NQ?y11LJ5N1Jj~QdDD0mHygnJi2a``MpIvYPHCbC!0r+tR|T#9r<#u!p@`5 zO!=EAqYC9*d@hgbisZl*~HhkPcCvML^+4eZy{54*<__Zhes8xb2XXY z%R2uh6Pwu!Imipuu=%f(`Eyv^Qd0NGE_?b&?lJ4`C3h=lp0&jDAbZ(*3y&<>a-C{% RYV^oHM|K`kd69h6{s9F5=Xn4C delta 247 zcmVjcZ)1h6z10amj$7-<2swi&Mhvwa&00kfVQPyw?B9+&}>wjX%2Mj!|Q zvt}Vs1hdX1I03UBCtwD%mMs?slf^UGv&}Rq0<#V`kpc!FApii7Q=*;H`tSGwvkLN90+XIVNVD4XXaSQRLKl;9 x_Q11A_n`ulc0`bqs`_BFHbn>llPdhEleR{{v%>u;0RkXtu_34rx19_DE+TOLYmxu} diff --git a/demos/android-webview/.gradle/8.7/fileHashes/fileHashes.lock b/demos/android-webview/.gradle/8.7/fileHashes/fileHashes.lock index ae4ac8b7bdc671c484e9a5b6a4d10f2b5a10e263..f277520c1094d0e43d9d783812190dfcd463c38d 100644 GIT binary patch literal 17 VcmZSX%Win8`$g~@0~oMq0RT881h@bI literal 17 VcmZSX%Win8`$g~@0~j#>2LL$t1&jay diff --git a/demos/android-webview/.gradle/file-system.probe b/demos/android-webview/.gradle/file-system.probe index a64bc332e7f9914fb0125087916a857a8fbbf68d..bc0da9252c94e9e27cd33a6d8d489548f9ec3478 100644 GIT binary patch literal 8 PcmZQzV4U}No%l=u3F!j+ literal 8 PcmZQzV4TIU?e=v52fqUZ diff --git a/packages/database/src/base/mongo.ts b/packages/database/src/base/mongo.ts index 8f28d77f98..03a22c33ee 100644 --- a/packages/database/src/base/mongo.ts +++ b/packages/database/src/base/mongo.ts @@ -55,7 +55,9 @@ export class MongoDatabase implements IDatabase { this._url = parsedUrl.toString(); this.safeURL = this.url.replace(/\w+:\w+/, ""); this.dbname = dbname || parsedUrl.pathname.replace("/", ""); - this.logger = logger || getLogger("info", "database:mongo"); + this.logger = (logger || getLogger("info", "database:mongo")).with({ + mongoUrl: this.safeURL, + }); } get url(): string { @@ -77,14 +79,12 @@ export class MongoDatabase implements IDatabase { */ async connect(): Promise { this.logger.debug(() => ({ - data: { mongoUrl: this.safeURL }, msg: "Connecting to database", })); try { // Already connected if (this.connected) { this.logger.debug(() => ({ - data: { mongoUrl: this.safeURL }, msg: "Database connection already open", })); return; @@ -93,7 +93,6 @@ export class MongoDatabase implements IDatabase { // If a connection is in progress, await it if (this.connecting) { this.logger.debug(() => ({ - data: { mongoUrl: this.safeURL }, msg: "Database connection in progress, waiting for it to finish", })); return this.connecting; @@ -116,7 +115,6 @@ export class MongoDatabase implements IDatabase { const onConnected = () => { this.logger.debug(() => ({ - data: { mongoUrl: this.safeURL }, msg: "Database connection opened", })); this.connected = true; @@ -128,7 +126,6 @@ export class MongoDatabase implements IDatabase { const onError = (err: unknown) => { this.logger.error(() => ({ err, - data: { mongoUrl: this.safeURL }, msg: "Database error", })); this.connected = false; @@ -143,7 +140,6 @@ export class MongoDatabase implements IDatabase { connection.on("disconnected", () => { this.connected = false; this.logger.debug(() => ({ - data: { mongoUrl: this.safeURL }, msg: "Database disconnected", })); }); @@ -151,7 +147,6 @@ export class MongoDatabase implements IDatabase { connection.on("reconnected", () => { this.connected = true; this.logger.debug(() => ({ - data: { mongoUrl: this.safeURL }, msg: "Database reconnected", })); }); @@ -159,7 +154,6 @@ export class MongoDatabase implements IDatabase { connection.on("close", () => { this.connected = false; this.logger.debug(() => ({ - data: { mongoUrl: this.safeURL }, msg: "Database connection closed", })); }); @@ -167,7 +161,6 @@ export class MongoDatabase implements IDatabase { connection.on("fullsetup", () => { this.connected = true; this.logger.debug(() => ({ - data: { mongoUrl: this.safeURL }, msg: "Database connection is fully setup", })); }); @@ -177,7 +170,6 @@ export class MongoDatabase implements IDatabase { } catch (e) { this.logger.error(() => ({ err: e, - data: { mongoUrl: this.safeURL }, msg: "Database connection error", })); throw e; @@ -187,7 +179,6 @@ export class MongoDatabase implements IDatabase { /** Close connection to the database */ async close(): Promise { this.logger.debug(() => ({ - data: { mongoUrl: this.safeURL }, msg: "Closing connection", })); await this.connection?.close(); diff --git a/packages/env/src/provider.ts b/packages/env/src/provider.ts index e64274bc1d..6df8b195af 100644 --- a/packages/env/src/provider.ts +++ b/packages/env/src/provider.ts @@ -31,13 +31,14 @@ export class ProviderEnvironment extends Environment { return; } + const errorLog = this.logger.with({ failedFuncName: this.cleanup.name }); + this.db ?.cleanupScheduledTaskStatus(ScheduledTaskStatus.Running) .catch((err) => { - this.logger.error(() => ({ + errorLog.error(() => ({ msg: "Failed to cleanup running scheduled tasks", err, - data: { failedFuncName: this.cleanup.name }, })); }); @@ -49,10 +50,9 @@ export class ProviderEnvironment extends Environment { const redisConnection = this.getDb().getRedisConnection(); const writeQueue = new RedisWriteQueue(redisConnection, this.logger); writeQueue.clearAllSessionRecords().catch((err) => { - this.logger.error(() => ({ + errorLog.error(() => ({ msg: "Failed to clear Redis session records at startup", err, - data: { failedFuncName: this.cleanup.name }, })); }); } catch (err) { diff --git a/packages/provider/src/util.ts b/packages/provider/src/util.ts index a738d27ebd..b292e7e70e 100644 --- a/packages/provider/src/util.ts +++ b/packages/provider/src/util.ts @@ -374,6 +374,10 @@ export const deepValidateIpAddress = async ( distanceKm?: number; shouldFlag?: boolean; }> => { + const log = logger.with({ + challengeIp: challengeIpAddress.address, + providedIp: ip, + }); if ( ipValidationRules?.forceConsistentIp === true && dnsPeerIp && @@ -398,12 +402,8 @@ export const deepValidateIpAddress = async ( } // IP mismatch - continue to distance checking if not forcing consistent IPs if (ipValidationRules?.forceConsistentIp === true) { - logger.info(() => ({ + log.info(() => ({ msg: "IP validation failed - forceConsistentIp is true", - data: { - challengeIp: challengeIpAddress.address, - providedIp: ip, - }, })); return { isValid: false, @@ -421,12 +421,10 @@ export const deepValidateIpAddress = async ( const comparison = await compareIPs(challengeIpString, ip, ipInfoService); if ("error" in comparison) { - logger.error(() => ({ + log.error(() => ({ msg: "Failed to get IP distance comparison", data: { error: comparison.error, - challengeIp: challengeIpString, - providedIp: ip, }, })); // If we can't do distance comparison and IPs don't match exactly, be strict @@ -444,22 +442,18 @@ export const deepValidateIpAddress = async ( // If no validation rules provided, use legacy logic (1000km threshold) if (!ipValidationRules) { - logger.info(() => ({ + log.info(() => ({ msg: "No IP validation rules provided, using legacy logic", data: { - challengeIp: challengeIpString, - providedIp: ip, distanceKm: distanceKm, }, })); // Legacy distance > 1000km -> fail and log if (distanceKm !== undefined && distanceKm > 1000) { const errorMessage = `IP addresses are too far apart: ${distanceKm.toFixed(2)}km (>1000km limit)`; - logger.info(() => ({ + log.info(() => ({ msg: "IP validation failed - distance too great", data: { - challengeIp: challengeIpString, - providedIp: ip, distanceKm: distanceKm, comparison: comparison.comparison, }, @@ -472,11 +466,9 @@ export const deepValidateIpAddress = async ( } // Legacy distance <= 1000km -> allow flag - logger.info(() => ({ + log.info(() => ({ msg: "IP addresses differ but within acceptable distance", data: { - challengeIp: challengeIpString, - providedIp: ip, distanceKm: distanceKm, comparison: comparison.comparison, }, @@ -517,10 +509,9 @@ export const deepValidateIpAddress = async ( }; } } catch (error) { - logger.error(() => ({ + log.error(() => ({ msg: "Error during IP distance validation", err: error, - data: { challengeIp: challengeIpAddress.address, providedIp: ip }, })); // Something weird going on -> allow but flag return { diff --git a/packages/redis-client/src/redisClient.ts b/packages/redis-client/src/redisClient.ts index 9418404344..a8a92368f1 100644 --- a/packages/redis-client/src/redisClient.ts +++ b/packages/redis-client/src/redisClient.ts @@ -54,21 +54,19 @@ export const connectToRedis = (options: RedisOptions): RedisConnection => { } }); - options.logger.info(() => ({ + const log = options.logger.with({ url: options.url }); + + log.info(() => ({ msg: "Connecting to Redis", - data: { - url: options.url, - }, })); const clientPromise = masterClient.connect().then(async (connectedClient) => { isReady = true; timestamps.connectedAt = Date.now(); - options.logger.info(() => ({ + log.info(() => ({ msg: "Redis connected", data: { - url: options.url, awaitingTimeMs: timestamps.connectedAt - timestamps.initializedAt, }, })); @@ -98,14 +96,13 @@ export const setupRedisIndex = ( let isReady = false; + const log = logger.with({ name: index.name }); + const clientPromise = connection.getClient().then(async (client) => { timestamps.initializedAt = Date.now(); - logger.info(() => ({ + log.info(() => ({ msg: "Setting up Redis index", - data: { - name: index.name, - }, })); await createRedisIndex(client, index); @@ -113,10 +110,9 @@ export const setupRedisIndex = ( isReady = true; timestamps.setupAt = Date.now(); - logger.info(() => ({ + log.info(() => ({ msg: "Index setup", data: { - name: index.name, awaitingTimeMs: timestamps.setupAt - timestamps.initializedAt, }, }));