const path = require('path'); const fs = require('fs'); const winston = require('winston'); const moment = require('moment'); // Application/event logger (distinct from the DB audit trail, which records user data changes). This // captures operational events — HTTP requests, and outbound integration activity (SMTP, webhook, Teams, // ServiceNow, Workday) — as JSON lines in data/logs/app.log (size-rotated), readable by the Application // Logs admin screen. A console transport keeps a readable line on stdout for local development. const DATA_DIR = process.env.DEPRECORE_DATA_DIR || path.join(process.cwd(), 'data'); const LOG_DIR = path.join(DATA_DIR, 'logs'); fs.mkdirSync(LOG_DIR, { recursive: true }); const LOG_FILE = path.join(LOG_DIR, 'app.log'); const logger = winston.createLogger({ level: process.env.DEPRECORE_LOG_LEVEL || 'info', format: winston.format.combine(winston.format.timestamp(), winston.format.json()), transports: [ new winston.transports.File({ filename: LOG_FILE, maxsize: 5 * 1024 * 1024, maxFiles: 5, tailable: true }), new winston.transports.Console({ format: winston.format.printf((info) => `${moment().format()} [${info.category || 'system'}] ${info.level}: ${info.message}`) }) ] }); // Structured event logger. `category` groups the event (http | smtp | webhook | teams | servicenow | // workday | system); `meta` is arbitrary structured detail. Never throws — logging must not break a flow. function logEvent(category, message, meta = {}, level = 'info') { try { logger.log({ level, category: category || 'system', message, ...meta }); } catch { // swallow — a logging failure should never affect the request it describes } } module.exports = { logger, logEvent, LOG_FILE, LOG_DIR };