feat: implement error handling and logging in server hooks to capture and notify on 404 and 500 errors, enhancing server reliability and monitoring

This commit is contained in:
2025-12-08 11:52:27 -03:00
parent e1f1af7530
commit fdfbd8b051
31 changed files with 7305 additions and 932 deletions

View File

@@ -1,9 +1,91 @@
import type { Handle } from '@sveltejs/kit';
import type { Handle, HandleServerError } from '@sveltejs/kit';
import { createAuth } from '@sgse-app/backend/convex/auth';
import { getToken } from '@mmailaender/convex-better-auth-svelte/sveltekit';
import { getToken, createConvexHttpClient } from '@mmailaender/convex-better-auth-svelte/sveltekit';
import { api } from '@sgse-app/backend/convex/_generated/api';
export const handle: Handle = async ({ event, resolve }) => {
event.locals.token = await getToken(createAuth, event.cookies);
return resolve(event);
};
export const handleError: HandleServerError = async ({ error, event, status, message }) => {
// Notificar erros 404 e 500+ (erros internos do servidor)
if (status === 404 || status === 500 || status >= 500) {
// Evitar loop infinito: não registrar erros relacionados à própria página de erros
const urlPath = event.url.pathname;
if (urlPath.includes('/ti/erros-servidor')) {
console.warn(
`⚠️ Erro na página de erros do servidor (${status}): Não será registrado para evitar loop.`
);
} else {
try {
// Obter token do usuário (se autenticado)
const token = event.locals.token;
// Criar cliente Convex para chamar a action
const client = createConvexHttpClient({
token: token || undefined
});
// Extrair informações do erro
const errorMessage = error instanceof Error ? error.message : String(error);
const errorStack = error instanceof Error ? error.stack : undefined;
const url = event.url.toString();
const method = event.request.method;
const ipAddress = event.getClientAddress();
const userAgent = event.request.headers.get('user-agent') || undefined;
// Log para debug
console.log(`📝 Registrando erro ${status} no servidor:`, {
url,
method,
mensagem: errorMessage.substring(0, 100)
});
// Chamar action para registrar e notificar erro
// Aguardar a promise mas não bloquear a resposta se falhar
try {
// Usar Promise.race com timeout para evitar bloquear a resposta
const actionPromise = client.action(api.errosServidor.registrarErroServidor, {
statusCode: status,
mensagem: errorMessage,
stack: errorStack,
url,
method,
ipAddress,
userAgent,
usuarioId: undefined // Pode ser implementado depois para obter do token
});
// Timeout de 3 segundos
const timeoutPromise = new Promise<never>((_, reject) => {
setTimeout(() => reject(new Error('Timeout ao registrar erro')), 3000);
});
const resultado = await Promise.race([actionPromise, timeoutPromise]);
console.log(`✅ Erro ${status} registrado com sucesso:`, resultado);
} catch (actionError) {
// Log do erro de notificação, mas não falhar a resposta
console.error(
`❌ Erro ao registrar notificação de erro ${status}:`,
actionError instanceof Error ? actionError.message : actionError
);
}
} catch (err) {
// Se falhar ao criar cliente ou chamar action, apenas logar
// Não queremos que falhas na notificação quebrem a resposta de erro
console.error(
`❌ Erro ao tentar notificar equipe técnica sobre erro ${status}:`,
err instanceof Error ? err.message : err
);
}
}
}
// Retornar mensagem de erro padrão
return {
message: message || 'Erro interno do servidor',
status
};
};