diff --git a/Dockerfile b/Dockerfile index b5e1b73819..1d40714e90 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,7 +30,7 @@ RUN \ # Allow mounting of these files, which have no default touch .env ; \ # Create directories for the volumes to inherit the correct permissions - mkdir -p /app/client/public/images /app/api/logs /app/uploads ; \ + mkdir -p /app/client/public/images /app/logs /app/uploads ; \ npm config set fetch-retry-maxtimeout 600000 ; \ npm config set fetch-retries 5 ; \ npm config set fetch-retry-mintimeout 15000 ; \ diff --git a/api/config/meiliLogger.js b/api/config/meiliLogger.js index c5e60ea157..398672da5c 100644 --- a/api/config/meiliLogger.js +++ b/api/config/meiliLogger.js @@ -1,8 +1,35 @@ const path = require('path'); +const fs = require('fs'); const winston = require('winston'); require('winston-daily-rotate-file'); -const logDir = path.join(__dirname, '..', 'logs'); +/** + * Determine the log directory. + * Priority: + * 1. LIBRECHAT_LOG_DIR environment variable (allows user override) + * 2. /app/logs if running in Docker (bind-mounted with correct permissions) + * 3. api/logs relative to this file (local development) + */ +const getLogDir = () => { + if (process.env.LIBRECHAT_LOG_DIR) { + return process.env.LIBRECHAT_LOG_DIR; + } + + // Check if running in Docker container (cwd is /app) + if (process.cwd() === '/app') { + const dockerLogDir = '/app/logs'; + // Ensure the directory exists + if (!fs.existsSync(dockerLogDir)) { + fs.mkdirSync(dockerLogDir, { recursive: true }); + } + return dockerLogDir; + } + + // Local development: use api/logs relative to this file + return path.join(__dirname, '..', 'logs'); +}; + +const logDir = getLogDir(); const { NODE_ENV, DEBUG_LOGGING = false } = process.env; diff --git a/api/config/winston.js b/api/config/winston.js index 12f6053723..93b84f7c46 100644 --- a/api/config/winston.js +++ b/api/config/winston.js @@ -1,9 +1,36 @@ const path = require('path'); +const fs = require('fs'); const winston = require('winston'); require('winston-daily-rotate-file'); const { redactFormat, redactMessage, debugTraverse, jsonTruncateFormat } = require('./parsers'); -const logDir = path.join(__dirname, '..', 'logs'); +/** + * Determine the log directory. + * Priority: + * 1. LIBRECHAT_LOG_DIR environment variable (allows user override) + * 2. /app/logs if running in Docker (bind-mounted with correct permissions) + * 3. api/logs relative to this file (local development) + */ +const getLogDir = () => { + if (process.env.LIBRECHAT_LOG_DIR) { + return process.env.LIBRECHAT_LOG_DIR; + } + + // Check if running in Docker container (cwd is /app) + if (process.cwd() === '/app') { + const dockerLogDir = '/app/logs'; + // Ensure the directory exists + if (!fs.existsSync(dockerLogDir)) { + fs.mkdirSync(dockerLogDir, { recursive: true }); + } + return dockerLogDir; + } + + // Local development: use api/logs relative to this file + return path.join(__dirname, '..', 'logs'); +}; + +const logDir = getLogDir(); const { NODE_ENV, DEBUG_LOGGING = true, CONSOLE_JSON = false, DEBUG_CONSOLE = false } = process.env;