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:
@@ -138,6 +138,65 @@ module.exports = function(ctx) {
|
||||
});
|
||||
}, 'logs-stream'));
|
||||
|
||||
// Get latest daily digest
|
||||
router.get('/logs/digest/latest', ctx.asyncHandler(async (req, res) => {
|
||||
const digest = await ctx.logDigest.getLatestDigest();
|
||||
if (!digest) {
|
||||
return res.json({ success: true, digest: null, message: 'No digest available yet. First digest is generated at midnight.' });
|
||||
}
|
||||
res.json({ success: true, digest });
|
||||
}, 'logs-digest-latest'));
|
||||
|
||||
// Get live digest data (today's accumulated stats)
|
||||
router.get('/logs/digest/live', ctx.asyncHandler(async (req, res) => {
|
||||
const live = ctx.logDigest.getLiveData();
|
||||
res.json({ success: true, ...live });
|
||||
}, 'logs-digest-live'));
|
||||
|
||||
// List available digest dates
|
||||
router.get('/logs/digest/history', ctx.asyncHandler(async (req, res) => {
|
||||
const dates = await ctx.logDigest.listDigests();
|
||||
res.json({ success: true, dates });
|
||||
}, 'logs-digest-history'));
|
||||
|
||||
// Generate digest on demand (for today or a specific date)
|
||||
router.post('/logs/digest/generate', ctx.asyncHandler(async (req, res) => {
|
||||
const date = req.body.date || new Date().toISOString().slice(0, 10);
|
||||
const digest = await ctx.logDigest.generateDailyDigest(date);
|
||||
res.json({ success: true, digest });
|
||||
}, 'logs-digest-generate'));
|
||||
|
||||
// Get digest for a specific date (JSON)
|
||||
router.get('/logs/digest/:date', ctx.asyncHandler(async (req, res) => {
|
||||
const { date } = req.params;
|
||||
if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
|
||||
return ctx.errorResponse(res, 400, 'Invalid date format. Use YYYY-MM-DD.');
|
||||
}
|
||||
const format = req.query.format || 'json';
|
||||
if (format === 'text') {
|
||||
const text = await ctx.logDigest.getDigestText(date);
|
||||
if (!text) return ctx.errorResponse(res, 404, `No digest found for ${date}`);
|
||||
res.setHeader('Content-Type', 'text/plain');
|
||||
return res.send(text);
|
||||
}
|
||||
const digest = await ctx.logDigest.getDigestByDate(date);
|
||||
if (!digest) return ctx.errorResponse(res, 404, `No digest found for ${date}`);
|
||||
res.json({ success: true, digest });
|
||||
}, 'logs-digest-date'));
|
||||
|
||||
// Get Docker disk usage snapshot
|
||||
router.get('/logs/docker-disk', ctx.asyncHandler(async (req, res) => {
|
||||
const diskUsage = await ctx.dockerMaintenance.getDiskUsage();
|
||||
const status = ctx.dockerMaintenance.getStatus();
|
||||
res.json({ success: true, diskUsage, maintenance: status });
|
||||
}, 'logs-docker-disk'));
|
||||
|
||||
// Trigger Docker maintenance manually
|
||||
router.post('/logs/docker-maintenance', ctx.asyncHandler(async (req, res) => {
|
||||
const result = await ctx.dockerMaintenance.runMaintenance();
|
||||
res.json({ success: true, result });
|
||||
}, 'logs-docker-maintenance'));
|
||||
|
||||
// Get logs from a file path (for native applications)
|
||||
router.get('/logs/file', ctx.asyncHandler(async (req, res) => {
|
||||
const { path: logPath, tail = 100 } = req.query;
|
||||
|
||||
Reference in New Issue
Block a user