mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-09-22 06:00:56 +02:00
⚙️ refactor: Enhance Logging, Navigation And Error Handling (#5910)
* refactor: Ensure Axios Errors are less Verbose if No Response * refactor: Improve error handling in logAxiosError function * fix: Prevent ModelSelect from rendering for Agent Endpoints * refactor: Enhance logging functions with type parameter for better clarity * refactor: Update buildDefaultConvo function to use optional endpoint parameter since we pass a default value for undefined * refactor: Replace console logs with logger warnings and errors in useNavigateToConvo hook, and handle removed endpoint edge case * chore: import order
This commit is contained in:
parent
93dd365fda
commit
a65647a7de
5 changed files with 57 additions and 56 deletions
|
@ -5,40 +5,32 @@ const { logger } = require('~/config');
|
||||||
*
|
*
|
||||||
* @param {Object} options - The options object.
|
* @param {Object} options - The options object.
|
||||||
* @param {string} options.message - The custom message to be logged.
|
* @param {string} options.message - The custom message to be logged.
|
||||||
* @param {Error} options.error - The Axios error object.
|
* @param {import('axios').AxiosError} options.error - The Axios error object.
|
||||||
*/
|
*/
|
||||||
const logAxiosError = ({ message, error }) => {
|
const logAxiosError = ({ message, error }) => {
|
||||||
const timedOutMessage = 'Cannot read properties of undefined (reading \'status\')';
|
try {
|
||||||
if (error.response) {
|
if (error.response?.status) {
|
||||||
logger.error(
|
const { status, headers, data } = error.response;
|
||||||
`${message} The request was made and the server responded with a status code that falls out of the range of 2xx: ${
|
logger.error(`${message} The server responded with status ${status}: ${error.message}`, {
|
||||||
error.message ? error.message : ''
|
status,
|
||||||
}. Error response data:\n`,
|
headers,
|
||||||
{
|
data,
|
||||||
headers: error.response?.headers,
|
});
|
||||||
status: error.response?.status,
|
} else if (error.request) {
|
||||||
data: error.response?.data,
|
const { method, url } = error.config || {};
|
||||||
},
|
logger.error(
|
||||||
);
|
`${message} No response received for ${method ? method.toUpperCase() : ''} ${url || ''}: ${error.message}`,
|
||||||
} else if (error.request) {
|
{ requestInfo: { method, url } },
|
||||||
logger.error(
|
);
|
||||||
`${message} The request was made but no response was received: ${
|
} else if (error?.message?.includes('Cannot read properties of undefined (reading \'status\')')) {
|
||||||
error.message ? error.message : ''
|
logger.error(
|
||||||
}. Error Request:\n`,
|
`${message} It appears the request timed out or was unsuccessful: ${error.message}`,
|
||||||
{
|
);
|
||||||
request: error.request,
|
} else {
|
||||||
},
|
logger.error(`${message} An error occurred while setting up the request: ${error.message}`);
|
||||||
);
|
}
|
||||||
} else if (error?.message?.includes(timedOutMessage)) {
|
} catch (err) {
|
||||||
logger.error(
|
logger.error(`Error in logAxiosError: ${err.message}`);
|
||||||
`${message}\nThe request either timed out or was unsuccessful. Error message:\n`,
|
|
||||||
error,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
logger.error(
|
|
||||||
`${message}\nSomething happened in setting up the request. Error message:\n`,
|
|
||||||
error,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
import { useRecoilState } from 'recoil';
|
import { useRecoilState } from 'recoil';
|
||||||
import { Settings2 } from 'lucide-react';
|
import { Settings2 } from 'lucide-react';
|
||||||
import { Root, Anchor } from '@radix-ui/react-popover';
|
|
||||||
import { useState, useEffect, useMemo } from 'react';
|
import { useState, useEffect, useMemo } from 'react';
|
||||||
import { tConvoUpdateSchema, EModelEndpoint, isParamEndpoint } from 'librechat-data-provider';
|
import { Root, Anchor } from '@radix-ui/react-popover';
|
||||||
|
import {
|
||||||
|
EModelEndpoint,
|
||||||
|
isParamEndpoint,
|
||||||
|
isAgentsEndpoint,
|
||||||
|
tConvoUpdateSchema,
|
||||||
|
} from 'librechat-data-provider';
|
||||||
import type { TPreset, TInterfaceConfig } from 'librechat-data-provider';
|
import type { TPreset, TInterfaceConfig } from 'librechat-data-provider';
|
||||||
import { EndpointSettings, SaveAsPresetDialog, AlternativeSettings } from '~/components/Endpoints';
|
import { EndpointSettings, SaveAsPresetDialog, AlternativeSettings } from '~/components/Endpoints';
|
||||||
import { PluginStoreDialog, TooltipAnchor } from '~/components';
|
import { PluginStoreDialog, TooltipAnchor } from '~/components';
|
||||||
|
@ -42,7 +47,6 @@ export default function HeaderOptions({
|
||||||
if (endpoint && noSettings[endpoint]) {
|
if (endpoint && noSettings[endpoint]) {
|
||||||
setShowPopover(false);
|
setShowPopover(false);
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [endpoint, noSettings]);
|
}, [endpoint, noSettings]);
|
||||||
|
|
||||||
const saveAsPreset = () => {
|
const saveAsPreset = () => {
|
||||||
|
@ -67,7 +71,7 @@ export default function HeaderOptions({
|
||||||
<div className="my-auto lg:max-w-2xl xl:max-w-3xl">
|
<div className="my-auto lg:max-w-2xl xl:max-w-3xl">
|
||||||
<span className="flex w-full flex-col items-center justify-center gap-0 md:order-none md:m-auto md:gap-2">
|
<span className="flex w-full flex-col items-center justify-center gap-0 md:order-none md:m-auto md:gap-2">
|
||||||
<div className="z-[61] flex w-full items-center justify-center gap-2">
|
<div className="z-[61] flex w-full items-center justify-center gap-2">
|
||||||
{interfaceConfig?.modelSelect === true && (
|
{interfaceConfig?.modelSelect === true && !isAgentsEndpoint(endpoint) && (
|
||||||
<ModelSelect
|
<ModelSelect
|
||||||
conversation={conversation}
|
conversation={conversation}
|
||||||
setOption={setOption}
|
setOption={setOption}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { useNavigate } from 'react-router-dom';
|
||||||
import { useQueryClient } from '@tanstack/react-query';
|
import { useQueryClient } from '@tanstack/react-query';
|
||||||
import { QueryKeys, EModelEndpoint, LocalStorageKeys, Constants } from 'librechat-data-provider';
|
import { QueryKeys, EModelEndpoint, LocalStorageKeys, Constants } from 'librechat-data-provider';
|
||||||
import type { TConversation, TEndpointsConfig, TModelsConfig } from 'librechat-data-provider';
|
import type { TConversation, TEndpointsConfig, TModelsConfig } from 'librechat-data-provider';
|
||||||
import { buildDefaultConvo, getDefaultEndpoint, getEndpointField } from '~/utils';
|
import { buildDefaultConvo, getDefaultEndpoint, getEndpointField, logger } from '~/utils';
|
||||||
import store from '~/store';
|
import store from '~/store';
|
||||||
|
|
||||||
const useNavigateToConvo = (index = 0) => {
|
const useNavigateToConvo = (index = 0) => {
|
||||||
|
@ -20,7 +20,7 @@ const useNavigateToConvo = (index = 0) => {
|
||||||
invalidateMessages = false,
|
invalidateMessages = false,
|
||||||
) => {
|
) => {
|
||||||
if (!conversation) {
|
if (!conversation) {
|
||||||
console.log('Conversation not provided');
|
logger.warn('conversation', 'Conversation not provided to `navigateToConvo`');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
hasSetConversation.current = true;
|
hasSetConversation.current = true;
|
||||||
|
@ -34,10 +34,10 @@ const useNavigateToConvo = (index = 0) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
let convo = { ...conversation };
|
let convo = { ...conversation };
|
||||||
if (!convo.endpoint) {
|
const endpointsConfig = queryClient.getQueryData<TEndpointsConfig>([QueryKeys.endpoints]);
|
||||||
/* undefined endpoint edge case */
|
if (!convo.endpoint || !endpointsConfig?.[convo.endpoint]) {
|
||||||
|
/* undefined/removed endpoint edge case */
|
||||||
const modelsConfig = queryClient.getQueryData<TModelsConfig>([QueryKeys.models]);
|
const modelsConfig = queryClient.getQueryData<TModelsConfig>([QueryKeys.models]);
|
||||||
const endpointsConfig = queryClient.getQueryData<TEndpointsConfig>([QueryKeys.endpoints]);
|
|
||||||
const defaultEndpoint = getDefaultEndpoint({
|
const defaultEndpoint = getDefaultEndpoint({
|
||||||
convoSetup: conversation,
|
convoSetup: conversation,
|
||||||
endpointsConfig,
|
endpointsConfig,
|
||||||
|
@ -51,10 +51,10 @@ const useNavigateToConvo = (index = 0) => {
|
||||||
const models = modelsConfig?.[defaultEndpoint ?? ''] ?? [];
|
const models = modelsConfig?.[defaultEndpoint ?? ''] ?? [];
|
||||||
|
|
||||||
convo = buildDefaultConvo({
|
convo = buildDefaultConvo({
|
||||||
|
models,
|
||||||
conversation,
|
conversation,
|
||||||
endpoint: defaultEndpoint,
|
endpoint: defaultEndpoint,
|
||||||
lastConversationSetup: conversation,
|
lastConversationSetup: conversation,
|
||||||
models,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
clearAllConversations(true);
|
clearAllConversations(true);
|
||||||
|
@ -68,7 +68,7 @@ const useNavigateToConvo = (index = 0) => {
|
||||||
invalidateMessages?: boolean,
|
invalidateMessages?: boolean,
|
||||||
) => {
|
) => {
|
||||||
if (!conversation) {
|
if (!conversation) {
|
||||||
console.log('Conversation not provided');
|
logger.warn('conversation', 'Conversation not provided to `navigateToConvo`');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// set conversation to the new conversation
|
// set conversation to the new conversation
|
||||||
|
@ -78,7 +78,7 @@ const useNavigateToConvo = (index = 0) => {
|
||||||
lastSelectedTools =
|
lastSelectedTools =
|
||||||
JSON.parse(localStorage.getItem(LocalStorageKeys.LAST_TOOLS) ?? '') ?? [];
|
JSON.parse(localStorage.getItem(LocalStorageKeys.LAST_TOOLS) ?? '') ?? [];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// console.error(e);
|
logger.error('conversation', 'Error parsing last selected tools', e);
|
||||||
}
|
}
|
||||||
const hasTools = (conversation.tools?.length ?? 0) > 0;
|
const hasTools = (conversation.tools?.length ?? 0) > 0;
|
||||||
navigateToConvo(
|
navigateToConvo(
|
||||||
|
|
|
@ -8,14 +8,14 @@ import type { TConversation } from 'librechat-data-provider';
|
||||||
import { getLocalStorageItems } from './localStorage';
|
import { getLocalStorageItems } from './localStorage';
|
||||||
|
|
||||||
const buildDefaultConvo = ({
|
const buildDefaultConvo = ({
|
||||||
|
models,
|
||||||
conversation,
|
conversation,
|
||||||
endpoint = null,
|
endpoint = null,
|
||||||
models,
|
|
||||||
lastConversationSetup,
|
lastConversationSetup,
|
||||||
}: {
|
}: {
|
||||||
conversation: TConversation;
|
|
||||||
endpoint: EModelEndpoint | null;
|
|
||||||
models: string[];
|
models: string[];
|
||||||
|
conversation: TConversation;
|
||||||
|
endpoint?: EModelEndpoint | null;
|
||||||
lastConversationSetup: TConversation | null;
|
lastConversationSetup: TConversation | null;
|
||||||
}): TConversation => {
|
}): TConversation => {
|
||||||
const { lastSelectedModel, lastSelectedTools } = getLocalStorageItems();
|
const { lastSelectedModel, lastSelectedTools } = getLocalStorageItems();
|
||||||
|
@ -33,7 +33,7 @@ const buildDefaultConvo = ({
|
||||||
const model = lastConversationSetup?.model ?? lastSelectedModel?.[endpoint] ?? '';
|
const model = lastConversationSetup?.model ?? lastSelectedModel?.[endpoint] ?? '';
|
||||||
const secondaryModel: string | null =
|
const secondaryModel: string | null =
|
||||||
endpoint === EModelEndpoint.gptPlugins
|
endpoint === EModelEndpoint.gptPlugins
|
||||||
? lastConversationSetup?.agentOptions?.model ?? lastSelectedModel?.secondaryModel ?? null
|
? (lastConversationSetup?.agentOptions?.model ?? lastSelectedModel?.secondaryModel ?? null)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
let possibleModels: string[], secondaryModels: string[];
|
let possibleModels: string[], secondaryModels: string[];
|
||||||
|
|
|
@ -4,12 +4,17 @@ const loggerFilter = import.meta.env.VITE_LOGGER_FILTER || '';
|
||||||
|
|
||||||
type LogFunction = (...args: unknown[]) => void;
|
type LogFunction = (...args: unknown[]) => void;
|
||||||
|
|
||||||
const createLogFunction = (consoleMethod: LogFunction): LogFunction => {
|
const createLogFunction = (
|
||||||
|
consoleMethod: LogFunction,
|
||||||
|
type?: 'log' | 'warn' | 'error' | 'info' | 'debug' | 'dir',
|
||||||
|
): LogFunction => {
|
||||||
return (...args: unknown[]) => {
|
return (...args: unknown[]) => {
|
||||||
if (isDevelopment || isLoggerEnabled) {
|
if (isDevelopment || isLoggerEnabled) {
|
||||||
const tag = typeof args[0] === 'string' ? args[0] : '';
|
const tag = typeof args[0] === 'string' ? args[0] : '';
|
||||||
if (shouldLog(tag)) {
|
if (shouldLog(tag)) {
|
||||||
if (tag && args.length > 1) {
|
if (tag && typeof args[1] === 'string' && type === 'error') {
|
||||||
|
consoleMethod(`[${tag}] ${args[1]}`, ...args.slice(2));
|
||||||
|
} else if (tag && args.length > 1) {
|
||||||
consoleMethod(`[${tag}]`, ...args.slice(1));
|
consoleMethod(`[${tag}]`, ...args.slice(1));
|
||||||
} else {
|
} else {
|
||||||
consoleMethod(...args);
|
consoleMethod(...args);
|
||||||
|
@ -20,12 +25,12 @@ const createLogFunction = (consoleMethod: LogFunction): LogFunction => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const logger = {
|
const logger = {
|
||||||
log: createLogFunction(console.log),
|
log: createLogFunction(console.log, 'log'),
|
||||||
warn: createLogFunction(console.warn),
|
dir: createLogFunction(console.dir, 'dir'),
|
||||||
error: createLogFunction(console.error),
|
warn: createLogFunction(console.warn, 'warn'),
|
||||||
info: createLogFunction(console.info),
|
info: createLogFunction(console.info, 'info'),
|
||||||
debug: createLogFunction(console.debug),
|
error: createLogFunction(console.error, 'error'),
|
||||||
dir: createLogFunction(console.dir),
|
debug: createLogFunction(console.debug, 'debug'),
|
||||||
};
|
};
|
||||||
|
|
||||||
function shouldLog(tag: string): boolean {
|
function shouldLog(tag: string): boolean {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue