mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-04 06:52:47 +00:00
🗂️ feat: Allow Disabling File Log Transports (#13215)
Some checks are pending
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Waiting to run
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Waiting to run
GitNexus Index / index (push) Waiting to run
GitNexus Index / post-index (push) Blocked by required conditions
Some checks are pending
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Waiting to run
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Waiting to run
GitNexus Index / index (push) Waiting to run
GitNexus Index / post-index (push) Blocked by required conditions
* fix: allow disabling file log transports * fix: defer log directory setup when file logging disabled
This commit is contained in:
parent
8310e9a840
commit
799a080479
7 changed files with 182 additions and 68 deletions
|
|
@ -68,6 +68,8 @@ CONSOLE_JSON=false
|
|||
|
||||
DEBUG_LOGGING=true
|
||||
DEBUG_CONSOLE=false
|
||||
# Set to false to disable file-backed Winston transports.
|
||||
LOG_TO_FILE=true
|
||||
# Set to true to enable agent debug logging
|
||||
AGENT_DEBUG_LOGGING=false
|
||||
|
||||
|
|
|
|||
72
api/config/__tests__/logToFile.spec.js
Normal file
72
api/config/__tests__/logToFile.spec.js
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
const fs = require('fs');
|
||||
|
||||
const ORIGINAL_ENV = process.env;
|
||||
|
||||
const mockDataSchemas = () => {
|
||||
jest.doMock('@librechat/data-schemas', () => ({
|
||||
getTenantId: jest.fn(),
|
||||
getUserId: jest.fn(),
|
||||
getRequestId: jest.fn(),
|
||||
SYSTEM_TENANT_ID: 'system',
|
||||
}));
|
||||
};
|
||||
|
||||
const mockReadOnlyDockerLogDir = () => {
|
||||
const originalExistsSync = fs.existsSync;
|
||||
const originalMkdirSync = fs.mkdirSync;
|
||||
|
||||
jest.spyOn(process, 'cwd').mockReturnValue('/app');
|
||||
jest
|
||||
.spyOn(fs, 'existsSync')
|
||||
.mockImplementation((target) =>
|
||||
target === '/app/logs' ? false : originalExistsSync.call(fs, target),
|
||||
);
|
||||
|
||||
return jest.spyOn(fs, 'mkdirSync').mockImplementation((target, options) => {
|
||||
if (target === '/app/logs') {
|
||||
throw new Error('Attempted to create Docker log directory');
|
||||
}
|
||||
return originalMkdirSync.call(fs, target, options);
|
||||
});
|
||||
};
|
||||
|
||||
const prepareLoggerWithoutFileLogging = () => {
|
||||
jest.resetModules();
|
||||
jest.clearAllMocks();
|
||||
mockDataSchemas();
|
||||
|
||||
process.env = {
|
||||
...ORIGINAL_ENV,
|
||||
DEBUG_LOGGING: 'true',
|
||||
LOG_TO_FILE: 'false',
|
||||
};
|
||||
|
||||
return mockReadOnlyDockerLogDir();
|
||||
};
|
||||
|
||||
describe('LOG_TO_FILE', () => {
|
||||
afterEach(() => {
|
||||
process.env = ORIGINAL_ENV;
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('does not create the API log directory when winston file logging is disabled', () => {
|
||||
const mkdirSyncSpy = prepareLoggerWithoutFileLogging();
|
||||
|
||||
expect(() => require('../winston')).not.toThrow();
|
||||
|
||||
const winston = require('winston');
|
||||
expect(winston.transports.DailyRotateFile).not.toHaveBeenCalled();
|
||||
expect(mkdirSyncSpy).not.toHaveBeenCalledWith('/app/logs', expect.anything());
|
||||
});
|
||||
|
||||
it('does not create the API log directory when Meili file logging is disabled', () => {
|
||||
const mkdirSyncSpy = prepareLoggerWithoutFileLogging();
|
||||
|
||||
expect(() => require('../meiliLogger')).not.toThrow();
|
||||
|
||||
const winston = require('winston');
|
||||
expect(winston.transports.DailyRotateFile).not.toHaveBeenCalled();
|
||||
expect(mkdirSyncSpy).not.toHaveBeenCalledWith('/app/logs', expect.anything());
|
||||
});
|
||||
});
|
||||
|
|
@ -29,14 +29,16 @@ const getLogDir = () => {
|
|||
return path.join(__dirname, '..', 'logs');
|
||||
};
|
||||
|
||||
const logDir = getLogDir();
|
||||
|
||||
const { NODE_ENV, DEBUG_LOGGING = false } = process.env;
|
||||
const { NODE_ENV, DEBUG_LOGGING = false, LOG_TO_FILE = true } = process.env;
|
||||
|
||||
const useDebugLogging =
|
||||
(typeof DEBUG_LOGGING === 'string' && DEBUG_LOGGING?.toLowerCase() === 'true') ||
|
||||
DEBUG_LOGGING === true;
|
||||
|
||||
const useFileLogging =
|
||||
(typeof LOG_TO_FILE === 'string' && LOG_TO_FILE?.toLowerCase() !== 'false') ||
|
||||
LOG_TO_FILE === true;
|
||||
|
||||
const levels = {
|
||||
error: 0,
|
||||
warn: 1,
|
||||
|
|
@ -68,17 +70,23 @@ const fileFormat = winston.format.combine(
|
|||
);
|
||||
|
||||
const logLevel = useDebugLogging ? 'debug' : 'error';
|
||||
const transports = [
|
||||
new winston.transports.DailyRotateFile({
|
||||
level: logLevel,
|
||||
filename: `${logDir}/meiliSync-%DATE%.log`,
|
||||
datePattern: 'YYYY-MM-DD',
|
||||
zippedArchive: true,
|
||||
maxSize: '20m',
|
||||
maxFiles: '14d',
|
||||
format: fileFormat,
|
||||
}),
|
||||
];
|
||||
const transports = [];
|
||||
|
||||
if (useFileLogging) {
|
||||
const logDir = getLogDir();
|
||||
|
||||
transports.push(
|
||||
new winston.transports.DailyRotateFile({
|
||||
level: logLevel,
|
||||
filename: `${logDir}/meiliSync-%DATE%.log`,
|
||||
datePattern: 'YYYY-MM-DD',
|
||||
zippedArchive: true,
|
||||
maxSize: '20m',
|
||||
maxFiles: '14d',
|
||||
format: fileFormat,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const consoleFormat = winston.format.combine(
|
||||
winston.format.colorize({ all: true }),
|
||||
|
|
|
|||
|
|
@ -42,9 +42,13 @@ const getLogDir = () => {
|
|||
return path.join(__dirname, '..', 'logs');
|
||||
};
|
||||
|
||||
const logDir = getLogDir();
|
||||
|
||||
const { NODE_ENV, DEBUG_LOGGING = true, CONSOLE_JSON = false, DEBUG_CONSOLE = false } = process.env;
|
||||
const {
|
||||
NODE_ENV,
|
||||
DEBUG_LOGGING = true,
|
||||
CONSOLE_JSON = false,
|
||||
DEBUG_CONSOLE = false,
|
||||
LOG_TO_FILE = true,
|
||||
} = process.env;
|
||||
|
||||
const useConsoleJson =
|
||||
(typeof CONSOLE_JSON === 'string' && CONSOLE_JSON?.toLowerCase() === 'true') ||
|
||||
|
|
@ -58,6 +62,10 @@ const useDebugLogging =
|
|||
(typeof DEBUG_LOGGING === 'string' && DEBUG_LOGGING?.toLowerCase() === 'true') ||
|
||||
DEBUG_LOGGING === true;
|
||||
|
||||
const useFileLogging =
|
||||
(typeof LOG_TO_FILE === 'string' && LOG_TO_FILE?.toLowerCase() !== 'false') ||
|
||||
LOG_TO_FILE === true;
|
||||
|
||||
const levels = {
|
||||
error: 0,
|
||||
warn: 1,
|
||||
|
|
@ -129,30 +137,36 @@ const fileFormat = winston.format.combine(
|
|||
// redactErrors(),
|
||||
);
|
||||
|
||||
const transports = [
|
||||
new winston.transports.DailyRotateFile({
|
||||
level: 'error',
|
||||
filename: `${logDir}/error-%DATE%.log`,
|
||||
datePattern: 'YYYY-MM-DD',
|
||||
zippedArchive: true,
|
||||
maxSize: '20m',
|
||||
maxFiles: '14d',
|
||||
format: fileFormat,
|
||||
}),
|
||||
];
|
||||
const transports = [];
|
||||
|
||||
if (useFileLogging) {
|
||||
const logDir = getLogDir();
|
||||
|
||||
if (useDebugLogging) {
|
||||
transports.push(
|
||||
new winston.transports.DailyRotateFile({
|
||||
level: 'debug',
|
||||
filename: `${logDir}/debug-%DATE%.log`,
|
||||
level: 'error',
|
||||
filename: `${logDir}/error-%DATE%.log`,
|
||||
datePattern: 'YYYY-MM-DD',
|
||||
zippedArchive: true,
|
||||
maxSize: '20m',
|
||||
maxFiles: '14d',
|
||||
format: winston.format.combine(fileFormat, debugTraverse),
|
||||
format: fileFormat,
|
||||
}),
|
||||
);
|
||||
|
||||
if (useDebugLogging) {
|
||||
transports.push(
|
||||
new winston.transports.DailyRotateFile({
|
||||
level: 'debug',
|
||||
filename: `${logDir}/debug-%DATE%.log`,
|
||||
datePattern: 'YYYY-MM-DD',
|
||||
zippedArchive: true,
|
||||
maxSize: '20m',
|
||||
maxFiles: '14d',
|
||||
format: winston.format.combine(fileFormat, debugTraverse),
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const consoleFormat = winston.format.combine(
|
||||
|
|
|
|||
|
|
@ -1,12 +1,18 @@
|
|||
const winston = require('winston');
|
||||
|
||||
const useFileLogging =
|
||||
typeof process.env.LOG_TO_FILE !== 'string' || process.env.LOG_TO_FILE.toLowerCase() !== 'false';
|
||||
|
||||
const transports = [new winston.transports.Console()];
|
||||
|
||||
if (useFileLogging) {
|
||||
transports.push(new winston.transports.File({ filename: 'login-logs.log' }));
|
||||
}
|
||||
|
||||
const logger = winston.createLogger({
|
||||
level: 'info',
|
||||
format: winston.format.combine(winston.format.timestamp(), winston.format.json()),
|
||||
transports: [
|
||||
new winston.transports.Console(),
|
||||
new winston.transports.File({ filename: 'login-logs.log' }),
|
||||
],
|
||||
transports,
|
||||
});
|
||||
|
||||
module.exports = logger;
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@ import winston from 'winston';
|
|||
import 'winston-daily-rotate-file';
|
||||
import { getLogDirectory } from './utils';
|
||||
|
||||
const logDir = getLogDirectory();
|
||||
|
||||
const { NODE_ENV, DEBUG_LOGGING = 'false' } = process.env;
|
||||
const { NODE_ENV, DEBUG_LOGGING = 'false', LOG_TO_FILE } = process.env;
|
||||
|
||||
const useDebugLogging =
|
||||
(typeof DEBUG_LOGGING === 'string' && DEBUG_LOGGING.toLowerCase() === 'true') ||
|
||||
DEBUG_LOGGING === 'true';
|
||||
|
||||
const useFileLogging = typeof LOG_TO_FILE !== 'string' || LOG_TO_FILE.toLowerCase() !== 'false';
|
||||
|
||||
const levels: winston.config.AbstractConfigSetLevels = {
|
||||
error: 0,
|
||||
warn: 1,
|
||||
|
|
@ -41,17 +41,23 @@ const fileFormat = winston.format.combine(
|
|||
);
|
||||
|
||||
const logLevel = useDebugLogging ? 'debug' : 'error';
|
||||
const transports: winston.transport[] = [
|
||||
new winston.transports.DailyRotateFile({
|
||||
level: logLevel,
|
||||
filename: `${logDir}/meiliSync-%DATE%.log`,
|
||||
datePattern: 'YYYY-MM-DD',
|
||||
zippedArchive: true,
|
||||
maxSize: '20m',
|
||||
maxFiles: '14d',
|
||||
format: fileFormat,
|
||||
}),
|
||||
];
|
||||
const transports: winston.transport[] = [];
|
||||
|
||||
if (useFileLogging) {
|
||||
const logDir = getLogDirectory();
|
||||
|
||||
transports.push(
|
||||
new winston.transports.DailyRotateFile({
|
||||
level: logLevel,
|
||||
filename: `${logDir}/meiliSync-%DATE%.log`,
|
||||
datePattern: 'YYYY-MM-DD',
|
||||
zippedArchive: true,
|
||||
maxSize: '20m',
|
||||
maxFiles: '14d',
|
||||
format: fileFormat,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const consoleFormat = winston.format.combine(
|
||||
winston.format.colorize({ all: true }),
|
||||
|
|
|
|||
|
|
@ -4,9 +4,7 @@ import { redactFormat, redactMessage, debugTraverse, jsonTruncateFormat } from '
|
|||
import { getTenantId, getUserId, getRequestId, SYSTEM_TENANT_ID } from './tenantContext';
|
||||
import { getLogDirectory } from './utils';
|
||||
|
||||
const logDir = getLogDirectory();
|
||||
|
||||
const { NODE_ENV, DEBUG_LOGGING, CONSOLE_JSON, DEBUG_CONSOLE } = process.env;
|
||||
const { NODE_ENV, DEBUG_LOGGING, CONSOLE_JSON, DEBUG_CONSOLE, LOG_TO_FILE } = process.env;
|
||||
|
||||
const useConsoleJson = typeof CONSOLE_JSON === 'string' && CONSOLE_JSON.toLowerCase() === 'true';
|
||||
|
||||
|
|
@ -14,6 +12,8 @@ const useDebugConsole = typeof DEBUG_CONSOLE === 'string' && DEBUG_CONSOLE.toLow
|
|||
|
||||
const useDebugLogging = typeof DEBUG_LOGGING === 'string' && DEBUG_LOGGING.toLowerCase() === 'true';
|
||||
|
||||
const useFileLogging = typeof LOG_TO_FILE !== 'string' || LOG_TO_FILE.toLowerCase() !== 'false';
|
||||
|
||||
const levels: winston.config.AbstractConfigSetLevels = {
|
||||
error: 0,
|
||||
warn: 1,
|
||||
|
|
@ -88,30 +88,36 @@ const fileFormat = winston.format.combine(
|
|||
requestContextFormat(),
|
||||
);
|
||||
|
||||
const transports: winston.transport[] = [
|
||||
new winston.transports.DailyRotateFile({
|
||||
level: 'error',
|
||||
filename: `${logDir}/error-%DATE%.log`,
|
||||
datePattern: 'YYYY-MM-DD',
|
||||
zippedArchive: true,
|
||||
maxSize: '20m',
|
||||
maxFiles: '14d',
|
||||
format: winston.format.combine(fileFormat, winston.format.json()),
|
||||
}),
|
||||
];
|
||||
const transports: winston.transport[] = [];
|
||||
|
||||
if (useFileLogging) {
|
||||
const logDir = getLogDirectory();
|
||||
|
||||
if (useDebugLogging) {
|
||||
transports.push(
|
||||
new winston.transports.DailyRotateFile({
|
||||
level: 'debug',
|
||||
filename: `${logDir}/debug-%DATE%.log`,
|
||||
level: 'error',
|
||||
filename: `${logDir}/error-%DATE%.log`,
|
||||
datePattern: 'YYYY-MM-DD',
|
||||
zippedArchive: true,
|
||||
maxSize: '20m',
|
||||
maxFiles: '14d',
|
||||
format: winston.format.combine(fileFormat, debugTraverse),
|
||||
format: winston.format.combine(fileFormat, winston.format.json()),
|
||||
}),
|
||||
);
|
||||
|
||||
if (useDebugLogging) {
|
||||
transports.push(
|
||||
new winston.transports.DailyRotateFile({
|
||||
level: 'debug',
|
||||
filename: `${logDir}/debug-%DATE%.log`,
|
||||
datePattern: 'YYYY-MM-DD',
|
||||
zippedArchive: true,
|
||||
maxSize: '20m',
|
||||
maxFiles: '14d',
|
||||
format: winston.format.combine(fileFormat, debugTraverse),
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const consoleFormat = winston.format.combine(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue