From 1bc41bb2bc8720dc05b3d7610b03b787921819df Mon Sep 17 00:00:00 2001 From: Hermes Date: Mon, 10 Aug 2026 21:16:22 -0700 Subject: [PATCH] [grade=A] P2-5: fix 4 test handle leaks in log-digest.js + sweep remaining console calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause: setTimeout in start() (line 74) created an initial-collection timer that was never stored in an instance property, so stop() could not clear it. Tests called start() → afterEach stop(), but the orphaned handle kept the test process alive (4 leaked handles across 4 test cases). Fix: store as this._initialTimeout, clear in stop() alongside digestTimeout. Also replaced 3 remaining console.error calls in log-digest.js with structured log.error tagged 'logdigest' (was missed in P1-8 sweep). 1539/1539 tests pass. 0 open handles (--detectOpenHandles clean). --- dashcaddy-api/src/security/log-digest.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/dashcaddy-api/src/security/log-digest.js b/dashcaddy-api/src/security/log-digest.js index b3cbe3b..8dd6ee4 100644 --- a/dashcaddy-api/src/security/log-digest.js +++ b/dashcaddy-api/src/security/log-digest.js @@ -11,6 +11,7 @@ const fs = require('fs'); const fsp = require('fs').promises; const path = require('path'); const { DOCKER } = require('../utilities/constants'); +const { log } = require('../utils/logging'); const docker = new Docker(); @@ -63,7 +64,7 @@ class LogDigest extends EventEmitter { // Collect logs every hour this.collectInterval = setInterval(() => { this._collectHourlyLogs().catch(e => - console.error('[LogDigest] Hourly collection failed:', e.message) + log.error('logdigest', e, { phase: 'hourlyCollect' }) ); }, DOCKER.DIGEST.COLLECT_INTERVAL); @@ -71,7 +72,7 @@ class LogDigest extends EventEmitter { this._scheduleDailyDigest(); // Run initial collection after 2 minutes - setTimeout(() => { + this._initialTimeout = setTimeout(() => { if (this.running) { this._collectHourlyLogs().catch(() => {}); } @@ -89,6 +90,10 @@ class LogDigest extends EventEmitter { clearTimeout(this.digestTimeout); this.digestTimeout = null; } + if (this._initialTimeout) { + clearTimeout(this._initialTimeout); + this._initialTimeout = null; + } } /** @@ -195,7 +200,7 @@ class LogDigest extends EventEmitter { hourSummary.services[appId] = serviceSummary; } } catch (e) { - console.error('[LogDigest] Container enumeration failed:', e.message); + log.error('logdigest', e, { phase: 'enumerateContainers' }); } // Add to ring buffer @@ -258,7 +263,7 @@ class LogDigest extends EventEmitter { const delay = next.getTime() - now.getTime(); this.digestTimeout = setTimeout(() => { this.generateDailyDigest().catch(e => - console.error('[LogDigest] Daily digest generation failed:', e.message) + log.error('logdigest', e, { phase: 'dailyDigest' }) ); // Reschedule for tomorrow if (this.running) this._scheduleDailyDigest();