add additional logging to controller and mutations

This commit is contained in:
jeffvli
2026-02-13 11:05:40 -08:00
parent bca14176fb
commit 41c21b94c1
36 changed files with 395 additions and 54 deletions
@@ -18,6 +18,7 @@ import { AnimatedPage } from '/@/renderer/features/shared/components/animated-pa
import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-error-boundary';
import { AppRoute } from '/@/renderer/router/routes';
import { useAuthStoreActions, useCurrentServer } from '/@/renderer/store';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { Button } from '/@/shared/components/button/button';
import { Center } from '/@/shared/components/center/center';
import { Code } from '/@/shared/components/code/code';
@@ -136,6 +137,10 @@ const LoginRoute = () => {
);
if (!data) {
logFn.error('Login failed (no data returned)', {
category: LogCategory.SYSTEM,
meta: { serverName, serverType, serverUrl },
});
return toast.error({
message: t('error.authenticationFailed', { postProcess: 'sentenceCase' }),
});
@@ -159,6 +164,10 @@ const LoginRoute = () => {
addServer(serverItem);
setCurrentServer(serverItem);
logFn.info('Login successful', {
category: LogCategory.SYSTEM,
meta: { serverName, serverType, serverUrl, userId: data.userId },
});
toast.success({
message: t('form.addServer.success', { postProcess: 'sentenceCase' }),
});
@@ -175,6 +184,10 @@ const LoginRoute = () => {
}
}
} catch (err: any) {
logFn.error('Login failed', {
category: LogCategory.SYSTEM,
meta: { message: err?.message, serverName, serverType, serverUrl },
});
setIsLoading(false);
return toast.error({ message: err?.message });
}
@@ -6,6 +6,7 @@ import { queryKeys } from '/@/renderer/api/query-keys';
import { useRecentPlaylists } from '/@/renderer/features/playlists/hooks/use-recent-playlists';
import { MutationHookArgs } from '/@/renderer/lib/react-query';
import { useCurrentServerId } from '/@/renderer/store';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { AddToPlaylistArgs, AddToPlaylistResponse } from '/@/shared/types/domain-types';
export const useAddToPlaylist = (args: MutationHookArgs) => {
@@ -22,6 +23,17 @@ export const useAddToPlaylist = (args: MutationHookArgs) => {
apiClientProps: { serverId: args.apiClientProps.serverId },
});
},
onError: (error, variables) => {
logFn.error('Add to playlist failed', {
category: LogCategory.API,
meta: {
message: error?.message,
playlistId: variables.query.id,
serverId: variables.apiClientProps.serverId,
},
});
options?.onError?.(error);
},
onSuccess: (_data, variables, context) => {
const { apiClientProps } = variables;
const serverId = apiClientProps.serverId;
@@ -4,6 +4,7 @@ import { AxiosError } from 'axios';
import { api } from '/@/renderer/api';
import { queryKeys } from '/@/renderer/api/query-keys';
import { MutationHookArgs } from '/@/renderer/lib/react-query';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { CreatePlaylistArgs, CreatePlaylistResponse } from '/@/shared/types/domain-types';
export const useCreatePlaylist = (args: MutationHookArgs) => {
@@ -17,6 +18,16 @@ export const useCreatePlaylist = (args: MutationHookArgs) => {
apiClientProps: { serverId: args.apiClientProps.serverId },
});
},
onError: (error, variables) => {
logFn.error('Create playlist failed', {
category: LogCategory.API,
meta: {
message: error?.message,
serverId: variables.apiClientProps.serverId,
},
});
options?.onError?.(error);
},
onSuccess: (_args, variables) => {
queryClient.invalidateQueries({
exact: false,
@@ -9,6 +9,7 @@ import {
restorePlaylistQueryData,
} from '/@/renderer/features/playlists/mutations/playlist-optimistic-updates';
import { MutationHookArgs } from '/@/renderer/lib/react-query';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { DeletePlaylistArgs, DeletePlaylistResponse } from '/@/shared/types/domain-types';
export const useDeletePlaylist = (args: MutationHookArgs) => {
@@ -24,6 +25,14 @@ export const useDeletePlaylist = (args: MutationHookArgs) => {
});
},
onError: (_error, _variables, context) => {
logFn.error('Delete playlist failed', {
category: LogCategory.API,
meta: {
message: _error?.message,
playlistId: _variables.query.id,
serverId: _variables.apiClientProps.serverId,
},
});
if (context) {
restorePlaylistQueryData(queryClient, context);
}
@@ -4,6 +4,7 @@ import { AxiosError } from 'axios';
import { api } from '/@/renderer/api';
import { queryKeys } from '/@/renderer/api/query-keys';
import { MutationOptions } from '/@/renderer/lib/react-query';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { RemoveFromPlaylistArgs, RemoveFromPlaylistResponse } from '/@/shared/types/domain-types';
export const useRemoveFromPlaylist = (options?: MutationOptions) => {
@@ -16,6 +17,17 @@ export const useRemoveFromPlaylist = (options?: MutationOptions) => {
apiClientProps: { serverId: args.apiClientProps.serverId },
});
},
onError: (error, variables) => {
logFn.error('Remove from playlist failed', {
category: LogCategory.API,
meta: {
message: error?.message,
playlistId: variables.query.id,
serverId: variables.apiClientProps.serverId,
},
});
options?.onError?.(error);
},
onSuccess: (_data, variables) => {
const { apiClientProps } = variables;
const serverId = apiClientProps.serverId;
@@ -6,6 +6,7 @@ import { queryKeys } from '/@/renderer/api/query-keys';
import { useRecentPlaylists } from '/@/renderer/features/playlists/hooks/use-recent-playlists';
import { MutationHookArgs } from '/@/renderer/lib/react-query';
import { useCurrentServerId } from '/@/renderer/store';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { ReplacePlaylistArgs, ReplacePlaylistResponse } from '/@/shared/types/domain-types';
export const useReplacePlaylist = (args: MutationHookArgs) => {
@@ -22,6 +23,17 @@ export const useReplacePlaylist = (args: MutationHookArgs) => {
apiClientProps: { serverId: args.apiClientProps.serverId },
});
},
onError: (error, variables) => {
logFn.error('Replace playlist failed', {
category: LogCategory.API,
meta: {
message: error?.message,
playlistId: variables.query.id,
serverId: variables.apiClientProps.serverId,
},
});
options?.onError?.(error);
},
onSuccess: (_data, variables, context) => {
const { apiClientProps } = variables;
const serverId = apiClientProps.serverId;
@@ -4,6 +4,7 @@ import { AxiosError } from 'axios';
import { api } from '/@/renderer/api';
import { queryKeys } from '/@/renderer/api/query-keys';
import { MutationHookArgs } from '/@/renderer/lib/react-query';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { UpdatePlaylistArgs, UpdatePlaylistResponse } from '/@/shared/types/domain-types';
export const useUpdatePlaylist = (args: MutationHookArgs) => {
@@ -17,6 +18,17 @@ export const useUpdatePlaylist = (args: MutationHookArgs) => {
apiClientProps: { serverId: args.apiClientProps.serverId },
});
},
onError: (error, variables) => {
logFn.error('Update playlist failed', {
category: LogCategory.API,
meta: {
message: error?.message,
playlistId: variables.query?.id,
serverId: variables.apiClientProps.serverId,
},
});
options?.onError?.(error);
},
onSuccess: (_data, variables) => {
const { apiClientProps, query } = variables;
const serverId = apiClientProps.serverId;
@@ -48,9 +48,9 @@ export const EditRadioStationForm = ({ onCancel, station }: EditRadioStationForm
{
onError: (error) => {
logFn.error('An error occurred', {
category: LogCategory.OTHER,
meta: { error: error as Error },
});
category: LogCategory.OTHER,
meta: { error: error as Error },
});
toast.error({
message: (error as Error).message,
@@ -4,6 +4,7 @@ import { AxiosError } from 'axios';
import { api } from '/@/renderer/api';
import { queryKeys } from '/@/renderer/api/query-keys';
import { MutationHookArgs } from '/@/renderer/lib/react-query';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import {
CreateInternetRadioStationArgs,
CreateInternetRadioStationResponse,
@@ -25,6 +26,16 @@ export const useCreateRadioStation = (args: MutationHookArgs) => {
apiClientProps: { serverId: args.apiClientProps.serverId },
});
},
onError: (error, variables) => {
logFn.error('Create radio station failed', {
category: LogCategory.API,
meta: {
message: error?.message,
serverId: variables.apiClientProps.serverId,
},
});
options?.onError?.(error);
},
onSuccess: (_args, variables) => {
queryClient.invalidateQueries({
exact: false,
@@ -4,6 +4,7 @@ import { AxiosError } from 'axios';
import { api } from '/@/renderer/api';
import { queryKeys } from '/@/renderer/api/query-keys';
import { MutationHookArgs } from '/@/renderer/lib/react-query';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import {
DeleteInternetRadioStationArgs,
DeleteInternetRadioStationResponse,
@@ -25,6 +26,17 @@ export const useDeleteRadioStation = (args: MutationHookArgs) => {
apiClientProps: { serverId: args.apiClientProps.serverId },
});
},
onError: (error, variables) => {
logFn.error('Delete radio station failed', {
category: LogCategory.API,
meta: {
message: error?.message,
serverId: variables.apiClientProps.serverId,
stationId: variables.query?.id,
},
});
options?.onError?.(error);
},
onSuccess: (_args, variables) => {
queryClient.invalidateQueries({
exact: false,
@@ -4,6 +4,7 @@ import { AxiosError } from 'axios';
import { api } from '/@/renderer/api';
import { queryKeys } from '/@/renderer/api/query-keys';
import { MutationHookArgs } from '/@/renderer/lib/react-query';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import {
UpdateInternetRadioStationArgs,
UpdateInternetRadioStationResponse,
@@ -25,6 +26,17 @@ export const useUpdateRadioStation = (args: MutationHookArgs) => {
apiClientProps: { serverId: args.apiClientProps.serverId },
});
},
onError: (error, variables) => {
logFn.error('Update radio station failed', {
category: LogCategory.API,
meta: {
message: error?.message,
serverId: variables.apiClientProps.serverId,
stationId: variables.query?.id,
},
});
options?.onError?.(error);
},
onSuccess: (_args, variables) => {
queryClient.invalidateQueries({
exact: false,
@@ -14,6 +14,7 @@ import NavidromeIcon from '/@/renderer/features/servers/assets/navidrome.png';
import SubsonicIcon from '/@/renderer/features/servers/assets/opensubsonic.png';
import { IgnoreCorsSslSwitches } from '/@/renderer/features/servers/components/ignore-cors-ssl-switches';
import { useAuthStoreActions } from '/@/renderer/store';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { Checkbox } from '/@/shared/components/checkbox/checkbox';
import { Divider } from '/@/shared/components/divider/divider';
import { Group } from '/@/shared/components/group/group';
@@ -149,6 +150,10 @@ export const AddServerForm = ({ onCancel }: AddServerFormProps) => {
);
if (!data) {
logFn.error('Add server failed (no data returned)', {
category: LogCategory.SYSTEM,
meta: { name: values.name, serverType: values.type, url: values.url },
});
return toast.error({
message: t('error.authenticationFailed', { postProcess: 'sentenceCase' }),
});
@@ -189,6 +194,10 @@ export const AddServerForm = ({ onCancel }: AddServerFormProps) => {
setCurrentServer(serverItem);
closeAllModals();
logFn.info('Add server successful', {
category: LogCategory.SYSTEM,
meta: { name: values.name, serverId: serverItem.id, serverType: values.type, url: values.url },
});
toast.success({
message: t('form.addServer.success', { postProcess: 'sentenceCase' }),
});
@@ -205,6 +214,10 @@ export const AddServerForm = ({ onCancel }: AddServerFormProps) => {
}
}
} catch (err: any) {
logFn.error('Add server failed', {
category: LogCategory.SYSTEM,
meta: { message: err?.message, name: values.name, serverType: values.type, url: values.url },
});
setIsLoading(false);
return toast.error({ message: err?.message });
}
@@ -1,6 +1,7 @@
import { ErrorBoundary } from 'react-error-boundary';
import { useTranslation } from 'react-i18next';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { Box } from '/@/shared/components/box/box';
import { Button } from '/@/shared/components/button/button';
import { Center } from '/@/shared/components/center/center';
@@ -43,5 +44,22 @@ interface ComponentErrorBoundaryProps {
}
export const ComponentErrorBoundary = ({ children }: ComponentErrorBoundaryProps) => {
return <ErrorBoundary FallbackComponent={ComponentErrorFallback}>{children}</ErrorBoundary>;
return (
<ErrorBoundary
FallbackComponent={ComponentErrorFallback}
onError={(error, errorInfo) => {
logFn.error('Component error boundary caught an error', {
category: LogCategory.OTHER,
meta: {
componentStack: errorInfo?.componentStack,
message: error?.message,
name: error?.name,
stack: error?.stack,
},
});
}}
>
{children}
</ErrorBoundary>
);
};
@@ -2,6 +2,7 @@ import { ErrorBoundary } from 'react-error-boundary';
import { useTranslation } from 'react-i18next';
import { ServerSelector } from '/@/renderer/features/sidebar/components/server-selector';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { Box } from '/@/shared/components/box/box';
import { Button } from '/@/shared/components/button/button';
import { Center } from '/@/shared/components/center/center';
@@ -85,9 +86,15 @@ export const PageErrorBoundary = ({ children }: PageErrorBoundaryProps) => {
<ErrorBoundary
FallbackComponent={PageErrorFallback}
onError={(error, errorInfo) => {
if (process.env.NODE_ENV === 'development') {
console.error('Page error boundary caught an error:', error, errorInfo);
}
logFn.error('Page error boundary caught an error', {
category: LogCategory.OTHER,
meta: {
componentStack: errorInfo?.componentStack,
message: error?.message,
name: error?.name,
stack: error?.stack,
},
});
}}
onReset={() => {}}
>
@@ -2,6 +2,7 @@ import { ErrorBoundary } from 'react-error-boundary';
import { useTranslation } from 'react-i18next';
import { ServerSelector } from '/@/renderer/features/sidebar/components/server-selector';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { Box } from '/@/shared/components/box/box';
import { Button } from '/@/shared/components/button/button';
import { Center } from '/@/shared/components/center/center';
@@ -91,9 +92,15 @@ export const RouterErrorBoundary = ({ children }: RouterErrorBoundaryProps) => {
<ErrorBoundary
FallbackComponent={RouterErrorFallback}
onError={(error, errorInfo) => {
if (process.env.NODE_ENV === 'development') {
console.error('Root error boundary caught an error:', error, errorInfo);
}
logFn.error('Router error boundary caught an error', {
category: LogCategory.OTHER,
meta: {
componentStack: errorInfo?.componentStack,
message: error?.message,
name: error?.name,
stack: error?.stack,
},
});
}}
onReset={() => {}}
>
@@ -12,6 +12,7 @@ import {
restoreFavoriteQueryData,
} from '/@/renderer/features/shared/mutations/favorite-optimistic-updates';
import { MutationHookArgs } from '/@/renderer/lib/react-query';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { toast } from '/@/shared/components/toast/toast';
import { FavoriteArgs, FavoriteResponse, LibraryItem } from '/@/shared/types/domain-types';
@@ -33,6 +34,15 @@ export const useCreateFavorite = (args: MutationHookArgs) => {
},
mutationKey: createFavoriteMutationKey,
onError: (_error, variables, context) => {
logFn.error('Create favorite failed', {
category: LogCategory.API,
meta: {
id: variables.query.id,
message: _error?.message,
serverId: variables.apiClientProps.serverId,
type: variables.query.type,
},
});
if (context) {
restoreFavoriteQueryData(queryClient, context);
}
@@ -12,6 +12,7 @@ import {
restoreFavoriteQueryData,
} from '/@/renderer/features/shared/mutations/favorite-optimistic-updates';
import { MutationHookArgs } from '/@/renderer/lib/react-query';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { toast } from '/@/shared/components/toast/toast';
import { FavoriteArgs, FavoriteResponse, LibraryItem } from '/@/shared/types/domain-types';
@@ -33,6 +34,15 @@ export const useDeleteFavorite = (args: MutationHookArgs) => {
},
mutationKey: deleteFavoriteMutationKey,
onError: (_error, _variables, context) => {
logFn.error('Delete favorite failed', {
category: LogCategory.API,
meta: {
id: _variables.query.id,
message: _error?.message,
serverId: _variables.apiClientProps.serverId,
type: _variables.query.type,
},
});
if (context) {
restoreFavoriteQueryData(queryClient, context);
}
@@ -11,6 +11,7 @@ import {
restoreRatingQueryData,
} from '/@/renderer/features/shared/mutations/rating-optimistic-updates';
import { MutationHookArgs } from '/@/renderer/lib/react-query';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { toast } from '/@/shared/components/toast/toast';
import { LibraryItem, RatingResponse, SetRatingArgs } from '/@/shared/types/domain-types';
@@ -30,6 +31,16 @@ export const useSetRatingMutation = (args: MutationHookArgs) => {
},
mutationKey: setRatingMutationKey,
onError: (_error, _variables, context) => {
logFn.error('Set rating failed', {
category: LogCategory.API,
meta: {
id: _variables.query.id,
message: _error?.message,
rating: _variables.query.rating,
serverId: _variables.apiClientProps.serverId,
type: _variables.query.type,
},
});
if (context) {
restoreRatingQueryData(queryClient, context);
}
@@ -3,6 +3,7 @@ import { AxiosError } from 'axios';
import { api } from '/@/renderer/api';
import { MutationHookArgs } from '/@/renderer/lib/react-query';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { AnyLibraryItems, ShareItemArgs, ShareItemResponse } from '/@/shared/types/domain-types';
export const useShareItem = (args: MutationHookArgs) => {
@@ -20,6 +21,17 @@ export const useShareItem = (args: MutationHookArgs) => {
apiClientProps: { serverId: args.apiClientProps.serverId },
});
},
onError: (error, variables) => {
logFn.error('Share item failed', {
category: LogCategory.API,
meta: {
itemType: variables.body?.resourceType,
message: error?.message,
serverId: variables.apiClientProps.serverId,
},
});
options?.onError?.(error);
},
retry: false,
...options,
});