Add Docker hygiene, deployment manifests, and daily log digest
Prevents Docker disk bloat by adding log rotation (10MB max, 3 files) to all container creation and update paths, auto-pruning dangling images after deploy/remove/update, and a daily maintenance module that cleans build cache and warns on disk thresholds. Saves a deployment manifest in services.json at deploy time so users can restore all their apps after a Docker purge. Adds restore-all and restore-single endpoints that recreate containers, Caddy config, and DNS records from the saved manifests. Adds an hourly log collector and daily digest generator that summarizes errors, warnings, and events across all services into a single human-readable report with guidance on where to investigate. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -50,6 +50,8 @@ const backupManager = require('./backup-manager');
|
||||
const healthChecker = require('./health-checker');
|
||||
const updateManager = require('./update-manager');
|
||||
const selfUpdater = require('./self-updater');
|
||||
const dockerMaintenance = require('./docker-maintenance');
|
||||
const logDigest = require('./log-digest');
|
||||
const StateManager = require('./state-manager');
|
||||
const auditLogger = require('./audit-logger');
|
||||
const portLockManager = require('./port-lock-manager');
|
||||
@@ -1161,7 +1163,7 @@ Object.assign(ctx, {
|
||||
app, siteConfig, servicesStateManager, configStateManager,
|
||||
credentialManager, authManager, licenseManager,
|
||||
healthChecker, updateManager, backupManager, resourceMonitor,
|
||||
auditLogger, portLockManager, selfUpdater,
|
||||
auditLogger, portLockManager, selfUpdater, dockerMaintenance, logDigest,
|
||||
APP_TEMPLATES, TEMPLATE_CATEGORIES, DIFFICULTY_LEVELS, RECIPE_TEMPLATES, RECIPE_CATEGORIES,
|
||||
asyncHandler, errorResponse, ok, fetchT, log, logError, safeErrorMessage,
|
||||
buildDomain, buildServiceUrl, getServiceById, readConfig, saveConfig, addServiceToConfig,
|
||||
@@ -1885,6 +1887,39 @@ const server = app.listen(PORT, '0.0.0.0', () => {
|
||||
log.error('server', 'Self-updater failed to start', { error: error.message });
|
||||
}
|
||||
|
||||
try {
|
||||
dockerMaintenance.start();
|
||||
log.info('server', 'Docker maintenance started');
|
||||
dockerMaintenance.on('maintenance-complete', (result) => {
|
||||
const saved = Math.round(result.spaceReclaimed.total / 1024 / 1024);
|
||||
if (saved > 0 || result.warnings.length > 0) {
|
||||
log.info('maintenance', 'Docker maintenance completed', {
|
||||
spaceReclaimedMB: saved,
|
||||
pruned: result.pruned,
|
||||
warnings: result.warnings.length
|
||||
});
|
||||
}
|
||||
if (result.warnings.length > 0) {
|
||||
for (const w of result.warnings) log.warn('maintenance', w);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
log.error('server', 'Docker maintenance failed to start', { error: error.message });
|
||||
}
|
||||
|
||||
try {
|
||||
logDigest.start(platformPaths.digestDir);
|
||||
log.info('server', 'Log digest started', { digestDir: platformPaths.digestDir });
|
||||
logDigest.on('digest-generated', ({ date }) => {
|
||||
log.info('digest', `Daily digest generated for ${date}`);
|
||||
if (typeof ctx.notification?.send === 'function') {
|
||||
ctx.notification.send('system.digest', 'Daily Log Digest', `Log digest for ${date} is ready. View it in the DashCaddy dashboard.`, 'info');
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
log.error('server', 'Log digest failed to start', { error: error.message });
|
||||
}
|
||||
|
||||
// Tailscale API sync (if OAuth configured)
|
||||
if (tailscaleConfig.oauthConfigured) {
|
||||
startTailscaleSyncTimer();
|
||||
@@ -1900,6 +1935,8 @@ function shutdown(signal) {
|
||||
log.info('shutdown', `${signal} received, draining connections...`);
|
||||
resourceMonitor.stop();
|
||||
backupManager.stop();
|
||||
dockerMaintenance.stop();
|
||||
logDigest.stop();
|
||||
healthChecker.stop();
|
||||
updateManager.stop();
|
||||
selfUpdater.stop();
|
||||
|
||||
Reference in New Issue
Block a user