mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-01-04 17:48:50 +01:00
refactor(api): Central Logging 📜 (#1348)
* WIP: initial logging changes add several transports in ~/config/winston omit messages in logs, truncate long strings add short blurb in dotenv for debug logging GoogleClient: using logger OpenAIClient: using logger, handleOpenAIErrors Adding typedef for payload message bumped winston and using winston-daily-rotate-file moved config for server paths to ~/config dir Added `DEBUG_LOGGING=true` to .env.example * WIP: Refactor logging statements in code * WIP: Refactor logging statements and import configurations * WIP: Refactor logging statements and import configurations * refactor: broadcast Redis initialization message with `info` not `debug` * refactor: complete Refactor logging statements and import configurations * chore: delete unused tools * fix: circular dependencies due to accessing logger * refactor(handleText): handle booleans and write tests * refactor: redact sensitive values, better formatting * chore: improve log formatting, avoid passing strings to 2nd arg * fix(ci): fix jest tests due to logger changes * refactor(getAvailablePluginsController): cache plugins as they are static and avoids async addOpenAPISpecs call every time * chore: update docs * chore: update docs * chore: create separate meiliSync logger, clean up logs to avoid being unnecessarily verbose * chore: spread objects where they are commonly logged to allow string truncation * chore: improve error log formatting
This commit is contained in:
parent
49571ac635
commit
ea1dd59ef4
115 changed files with 1271 additions and 1001 deletions
|
|
@ -1,6 +1,7 @@
|
|||
const mongoose = require('mongoose');
|
||||
const balanceSchema = require('./schema/balance');
|
||||
const { getMultiplier } = require('./tx');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
balanceSchema.statics.check = async function ({
|
||||
user,
|
||||
|
|
@ -9,25 +10,21 @@ balanceSchema.statics.check = async function ({
|
|||
valueKey,
|
||||
tokenType,
|
||||
amount,
|
||||
debug,
|
||||
}) {
|
||||
const multiplier = getMultiplier({ valueKey, tokenType, model, endpoint });
|
||||
const tokenCost = amount * multiplier;
|
||||
const { tokenCredits: balance } = (await this.findOne({ user }, 'tokenCredits').lean()) ?? {};
|
||||
|
||||
if (debug) {
|
||||
console.log('balance check', {
|
||||
user,
|
||||
model,
|
||||
endpoint,
|
||||
valueKey,
|
||||
tokenType,
|
||||
amount,
|
||||
debug,
|
||||
balance,
|
||||
multiplier,
|
||||
});
|
||||
}
|
||||
logger.debug('[Balance.check]', {
|
||||
user,
|
||||
model,
|
||||
endpoint,
|
||||
valueKey,
|
||||
tokenType,
|
||||
amount,
|
||||
balance,
|
||||
multiplier,
|
||||
});
|
||||
|
||||
if (!balance) {
|
||||
return {
|
||||
|
|
@ -37,9 +34,7 @@ balanceSchema.statics.check = async function ({
|
|||
};
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
console.log('balance check', { tokenCost });
|
||||
}
|
||||
logger.debug('[Balance.check]', { tokenCost });
|
||||
|
||||
return { canSpend: balance >= tokenCost, balance, tokenCost };
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
const mongoose = require('mongoose');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
const major = [0, 0];
|
||||
const minor = [0, 0];
|
||||
const patch = [0, 5];
|
||||
|
|
@ -69,7 +71,7 @@ module.exports = {
|
|||
try {
|
||||
return await Config.find(filter).lean();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
logger.error('Error getting configs', error);
|
||||
return { config: 'Error getting configs' };
|
||||
}
|
||||
},
|
||||
|
|
@ -77,7 +79,7 @@ module.exports = {
|
|||
try {
|
||||
return await Config.deleteMany(filter);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
logger.error('Error deleting configs', error);
|
||||
return { config: 'Error deleting configs' };
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
// const { Conversation } = require('./plugins');
|
||||
const Conversation = require('./schema/convoSchema');
|
||||
const { getMessages, deleteMessages } = require('./Message');
|
||||
const logger = require('~/config/winston');
|
||||
|
||||
const getConvo = async (user, conversationId) => {
|
||||
try {
|
||||
return await Conversation.findOne({ user, conversationId }).lean();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
logger.error('[getConvo] Error getting single conversation', error);
|
||||
return { message: 'Error getting single conversation' };
|
||||
}
|
||||
};
|
||||
|
|
@ -26,7 +26,7 @@ module.exports = {
|
|||
upsert: true,
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
logger.error('[saveConvo] Error saving conversation', error);
|
||||
return { message: 'Error saving conversation' };
|
||||
}
|
||||
},
|
||||
|
|
@ -41,7 +41,7 @@ module.exports = {
|
|||
.lean();
|
||||
return { conversations: convos, pages: totalPages, pageNumber, pageSize };
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
logger.error('[getConvosByPage] Error getting conversations', error);
|
||||
return { message: 'Error getting conversations' };
|
||||
}
|
||||
},
|
||||
|
|
@ -87,7 +87,7 @@ module.exports = {
|
|||
convoMap,
|
||||
};
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
logger.error('[getConvosQueried] Error getting conversations', error);
|
||||
return { message: 'Error fetching conversations' };
|
||||
}
|
||||
},
|
||||
|
|
@ -104,7 +104,7 @@ module.exports = {
|
|||
return convo?.title || 'New Chat';
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
logger.error('[getConvoTitle] Error getting conversation title', error);
|
||||
return { message: 'Error getting conversation title' };
|
||||
}
|
||||
},
|
||||
|
|
@ -123,7 +123,7 @@ module.exports = {
|
|||
* const user = 'someUserId';
|
||||
* const filter = { someField: 'someValue' };
|
||||
* const result = await deleteConvos(user, filter);
|
||||
* console.log(result); // { n: 5, ok: 1, deletedCount: 5, messages: { n: 10, ok: 1, deletedCount: 10 } }
|
||||
* logger.error(result); // { n: 5, ok: 1, deletedCount: 5, messages: { n: 10, ok: 1, deletedCount: 10 } }
|
||||
*/
|
||||
deleteConvos: async (user, filter) => {
|
||||
let toRemove = await Conversation.find({ ...filter, user }).select('conversationId');
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
const { z } = require('zod');
|
||||
const Message = require('./schema/messageSchema');
|
||||
const logger = require('~/config/winston');
|
||||
|
||||
const idSchema = z.string().uuid();
|
||||
|
||||
|
|
@ -67,7 +68,7 @@ module.exports = {
|
|||
tokenCount,
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(`Error saving message: ${err}`);
|
||||
logger.error('Error saving message:', err);
|
||||
throw new Error('Failed to save message.');
|
||||
}
|
||||
},
|
||||
|
|
@ -92,7 +93,7 @@ module.exports = {
|
|||
isEdited: true,
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(`Error updating message: ${err}`);
|
||||
logger.error('Error updating message:', err);
|
||||
throw new Error('Failed to update message.');
|
||||
}
|
||||
},
|
||||
|
|
@ -106,7 +107,7 @@ module.exports = {
|
|||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`Error deleting messages: ${err}`);
|
||||
logger.error('Error deleting messages:', err);
|
||||
throw new Error('Failed to delete messages.');
|
||||
}
|
||||
},
|
||||
|
|
@ -115,7 +116,7 @@ module.exports = {
|
|||
try {
|
||||
return await Message.find(filter).sort({ createdAt: 1 }).lean();
|
||||
} catch (err) {
|
||||
console.error(`Error getting messages: ${err}`);
|
||||
logger.error('Error getting messages:', err);
|
||||
throw new Error('Failed to get messages.');
|
||||
}
|
||||
},
|
||||
|
|
@ -124,7 +125,7 @@ module.exports = {
|
|||
try {
|
||||
return await Message.deleteMany(filter);
|
||||
} catch (err) {
|
||||
console.error(`Error deleting messages: ${err}`);
|
||||
logger.error('Error deleting messages:', err);
|
||||
throw new Error('Failed to delete messages.');
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
const Preset = require('./schema/presetSchema');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
const getPreset = async (user, presetId) => {
|
||||
try {
|
||||
return await Preset.findOne({ user, presetId }).lean();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
logger.error('[getPreset] Error getting single preset', error);
|
||||
return { message: 'Error getting single preset' };
|
||||
}
|
||||
};
|
||||
|
|
@ -30,7 +31,7 @@ module.exports = {
|
|||
|
||||
return presets;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
logger.error('[getPresets] Error getting presets', error);
|
||||
return { message: 'Error retrieving presets' };
|
||||
}
|
||||
},
|
||||
|
|
@ -62,7 +63,7 @@ module.exports = {
|
|||
setter.$set = update;
|
||||
return await Preset.findOneAndUpdate({ presetId, user }, setter, { new: true, upsert: true });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
logger.error('[savePreset] Error saving preset', error);
|
||||
return { message: 'Error saving preset' };
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
const mongoose = require('mongoose');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
const promptSchema = mongoose.Schema(
|
||||
{
|
||||
|
|
@ -28,7 +29,7 @@ module.exports = {
|
|||
});
|
||||
return { title, prompt };
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
logger.error('Error saving prompt', error);
|
||||
return { prompt: 'Error saving prompt' };
|
||||
}
|
||||
},
|
||||
|
|
@ -36,7 +37,7 @@ module.exports = {
|
|||
try {
|
||||
return await Prompt.find(filter).lean();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
logger.error('Error getting prompts', error);
|
||||
return { prompt: 'Error getting prompts' };
|
||||
}
|
||||
},
|
||||
|
|
@ -44,7 +45,7 @@ module.exports = {
|
|||
try {
|
||||
return await Prompt.deleteMany(filter);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
logger.error('Error deleting prompts', error);
|
||||
return { prompt: 'Error deleting prompts' };
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
const mongoose = require('mongoose');
|
||||
const crypto = require('crypto');
|
||||
const signPayload = require('../server/services/signPayload');
|
||||
const mongoose = require('mongoose');
|
||||
const signPayload = require('~/server/services/signPayload');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
const { REFRESH_TOKEN_EXPIRY } = process.env ?? {};
|
||||
const expires = eval(REFRESH_TOKEN_EXPIRY) ?? 1000 * 60 * 60 * 24 * 7;
|
||||
|
||||
|
|
@ -44,8 +46,8 @@ sessionSchema.methods.generateRefreshToken = async function () {
|
|||
|
||||
return refreshToken;
|
||||
} catch (error) {
|
||||
console.error(
|
||||
'Error generating refresh token. Have you set a JWT_REFRESH_SECRET in the .env file?\n\n',
|
||||
logger.error(
|
||||
'Error generating refresh token. Is a `JWT_REFRESH_SECRET` set in the .env file?\n\n',
|
||||
error,
|
||||
);
|
||||
throw error;
|
||||
|
|
@ -59,10 +61,12 @@ sessionSchema.statics.deleteAllUserSessions = async function (userId) {
|
|||
}
|
||||
const result = await this.deleteMany({ user: userId });
|
||||
if (result && result?.deletedCount > 0) {
|
||||
console.log(`Deleted ${result.deletedCount} sessions for user ${userId}.`);
|
||||
logger.debug(
|
||||
`[deleteAllUserSessions] Deleted ${result.deletedCount} sessions for user ${userId}.`,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('Error in deleting user sessions:', error);
|
||||
logger.error('[deleteAllUserSessions] Error in deleting user sessions:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ const { logViolation } = require('../cache');
|
|||
* @param {string} params.txData.user - The user ID or identifier.
|
||||
* @param {('prompt' | 'completion')} params.txData.tokenType - The type of token.
|
||||
* @param {number} params.txData.amount - The amount of tokens.
|
||||
* @param {boolean} params.txData.debug - Debug flag.
|
||||
* @param {string} params.txData.model - The model name or identifier.
|
||||
* @returns {Promise<boolean>} Returns true if the user can spend the amount, otherwise denies the request.
|
||||
* @throws {Error} Throws an error if there's an issue with the balance check.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
const _ = require('lodash');
|
||||
const mongoose = require('mongoose');
|
||||
const { MeiliSearch } = require('meilisearch');
|
||||
const { cleanUpPrimaryKeyValue } = require('../../lib/utils/misc');
|
||||
const _ = require('lodash');
|
||||
const { cleanUpPrimaryKeyValue } = require('~/lib/utils/misc');
|
||||
const logger = require('~/config/meiliLogger');
|
||||
|
||||
const searchEnabled = process.env.SEARCH && process.env.SEARCH.toLowerCase() === 'true';
|
||||
const meiliEnabled = process.env.MEILI_HOST && process.env.MEILI_MASTER_KEY && searchEnabled;
|
||||
|
||||
|
|
@ -64,8 +66,7 @@ const createMeiliMongooseModel = function ({ index, attributesToIndex }) {
|
|||
offset += batchSize;
|
||||
}
|
||||
|
||||
console.log('indexMap', indexMap.size);
|
||||
console.log('mongoMap', mongoMap.size);
|
||||
logger.debug('[syncWithMeili]', { indexMap: indexMap.size, mongoMap: mongoMap.size });
|
||||
|
||||
const updateOps = [];
|
||||
|
||||
|
|
@ -80,7 +81,11 @@ const createMeiliMongooseModel = function ({ index, attributesToIndex }) {
|
|||
(doc.text && doc.text !== mongoMap.get(id).text) ||
|
||||
(doc.title && doc.title !== mongoMap.get(id).title)
|
||||
) {
|
||||
console.log(`${id} had document discrepancy in ${doc.text ? 'text' : 'title'} field`);
|
||||
logger.debug(
|
||||
`[syncWithMeili] ${id} had document discrepancy in ${
|
||||
doc.text ? 'text' : 'title'
|
||||
} field`,
|
||||
);
|
||||
updateOps.push({
|
||||
updateOne: { filter: update, update: { $set: { _meiliIndex: true } } },
|
||||
});
|
||||
|
|
@ -116,15 +121,14 @@ const createMeiliMongooseModel = function ({ index, attributesToIndex }) {
|
|||
|
||||
if (updateOps.length > 0) {
|
||||
await this.collection.bulkWrite(updateOps);
|
||||
console.log(
|
||||
`[Meilisearch] Finished indexing ${
|
||||
logger.debug(
|
||||
`[syncWithMeili] Finished indexing ${
|
||||
primaryKey === 'messageId' ? 'messages' : 'conversations'
|
||||
}`,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('[Meilisearch] Error adding document to Meili');
|
||||
console.error(error);
|
||||
logger.error('[syncWithMeili] Error adding document to Meili', error);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -143,7 +147,7 @@ const createMeiliMongooseModel = function ({ index, attributesToIndex }) {
|
|||
const query = {};
|
||||
// query[primaryKey] = { $in: _.map(data.hits, primaryKey) };
|
||||
query[primaryKey] = _.map(data.hits, (hit) => cleanUpPrimaryKeyValue(hit[primaryKey]));
|
||||
// console.log('query', query);
|
||||
// logger.debug('query', query);
|
||||
const hitsFromMongoose = await this.find(
|
||||
query,
|
||||
_.reduce(
|
||||
|
|
@ -186,11 +190,11 @@ const createMeiliMongooseModel = function ({ index, attributesToIndex }) {
|
|||
async addObjectToMeili() {
|
||||
const object = this.preprocessObjectForIndex();
|
||||
try {
|
||||
// console.log('Adding document to Meili', object);
|
||||
// logger.debug('Adding document to Meili', object);
|
||||
await index.addDocuments([object]);
|
||||
} catch (error) {
|
||||
// console.log('Error adding document to Meili');
|
||||
// console.error(error);
|
||||
// logger.debug('Error adding document to Meili');
|
||||
// logger.error(error);
|
||||
}
|
||||
|
||||
await this.collection.updateMany({ _id: this._id }, { $set: { _meiliIndex: true } });
|
||||
|
|
@ -311,10 +315,10 @@ module.exports = function mongoMeili(schema, options) {
|
|||
return next();
|
||||
} catch (error) {
|
||||
if (meiliEnabled) {
|
||||
console.log(
|
||||
'[Meilisearch] There was an issue deleting conversation indexes upon deletion, next startup may be slow due to syncing',
|
||||
logger.error(
|
||||
'[MeiliMongooseModel.deleteMany] There was an issue deleting conversation indexes upon deletion, next startup may be slow due to syncing',
|
||||
error,
|
||||
);
|
||||
console.error(error);
|
||||
}
|
||||
return next();
|
||||
}
|
||||
|
|
@ -335,7 +339,11 @@ module.exports = function mongoMeili(schema, options) {
|
|||
try {
|
||||
meiliDoc = await client.index('convos').getDocument(doc.conversationId);
|
||||
} catch (error) {
|
||||
console.log('[Meilisearch] Convo not found and will index', doc.conversationId);
|
||||
logger.error(
|
||||
'[MeiliMongooseModel.findOneAndUpdate] Convo not found in MeiliSearch and will index ' +
|
||||
doc.conversationId,
|
||||
error,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
const mongoose = require('mongoose');
|
||||
const mongoMeili = require('../plugins/mongoMeili');
|
||||
const mongoMeili = require('~/models/plugins/mongoMeili');
|
||||
const messageSchema = mongoose.Schema(
|
||||
{
|
||||
messageId: {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
const Transaction = require('./Transaction');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
/**
|
||||
* Creates up to two transactions to record the spending of tokens.
|
||||
|
|
@ -30,7 +31,7 @@ const spendTokens = async (txData, tokenUsage) => {
|
|||
}
|
||||
|
||||
if (!completionTokens) {
|
||||
this.debug && console.dir({ prompt, completion }, { depth: null });
|
||||
logger.debug('[spendTokens] !completionTokens', { prompt, completion });
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -40,9 +41,9 @@ const spendTokens = async (txData, tokenUsage) => {
|
|||
rawAmount: -completionTokens,
|
||||
});
|
||||
|
||||
this.debug && console.dir({ prompt, completion }, { depth: null });
|
||||
logger.debug('[spendTokens] post-transaction', { prompt, completion });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
logger.error('[spendTokens]', err);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue