mirror of
https://github.com/polaroi8d/cactoide.git
synced 2026-03-21 21:55:27 +00:00
feat: add pino logger for serverside
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
import type { Handle } from '@sveltejs/kit';
|
||||
import { generateUserId } from '$lib/generateUserId.js';
|
||||
import { ensureDatabaseConnection } from '$lib/database/healthCheck';
|
||||
import { logger } from '$lib/logger';
|
||||
|
||||
// Global flag to track if database health check has been performed
|
||||
let dbHealthCheckPerformed = false;
|
||||
@@ -18,7 +19,7 @@ export const handle: Handle = async ({ event, resolve }) => {
|
||||
});
|
||||
dbHealthCheckPerformed = true;
|
||||
} catch (error) {
|
||||
console.error('Database health check failed:', error);
|
||||
logger.error({ error }, 'Database health check failed');
|
||||
// The ensureDatabaseConnection function will exit the process
|
||||
// if the database is unavailable, so this catch is just for safety
|
||||
process.exit(1);
|
||||
@@ -33,11 +34,10 @@ export const handle: Handle = async ({ event, resolve }) => {
|
||||
const PATH = '/';
|
||||
|
||||
if (!cactoideUserId) {
|
||||
console.debug(`There is no cactoideUserId cookie, generating new one...`);
|
||||
logger.debug({ userId }, 'No cactoideUserId cookie found, generating new one');
|
||||
event.cookies.set('cactoideUserId', userId, { path: PATH, maxAge: MAX_AGE });
|
||||
} else {
|
||||
console.debug(`cactoideUserId: ${cactoideUserId}`);
|
||||
console.debug(`cactoideUserId cookie found, using existing one...`);
|
||||
logger.debug({ cactoideUserId }, 'cactoideUserId cookie found, using existing one');
|
||||
}
|
||||
|
||||
return resolve(event);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import postgres from 'postgres';
|
||||
import { env } from '$env/dynamic/private';
|
||||
import { logger } from '$lib/logger';
|
||||
|
||||
interface HealthCheckOptions {
|
||||
maxRetries?: number;
|
||||
@@ -29,7 +30,7 @@ export async function checkDatabaseHealth(
|
||||
} = options;
|
||||
|
||||
if (!env.DATABASE_URL) {
|
||||
console.error('DATABASE_URL environment variable is not set');
|
||||
logger.error('DATABASE_URL environment variable is not set');
|
||||
return {
|
||||
success: false,
|
||||
error: 'DATABASE_URL environment variable is not set',
|
||||
@@ -39,10 +40,10 @@ export async function checkDatabaseHealth(
|
||||
|
||||
let lastError: Error | null = null;
|
||||
|
||||
console.log(`Starting database health check (max retries: ${maxRetries})`);
|
||||
logger.info({ maxRetries }, 'Starting database health check');
|
||||
|
||||
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
||||
console.log(`Attempt ${attempt}/${maxRetries} - Testing database connection`);
|
||||
logger.debug({ attempt, maxRetries }, 'Testing database connection');
|
||||
|
||||
try {
|
||||
// Create a new connection for the health check
|
||||
@@ -57,7 +58,7 @@ export async function checkDatabaseHealth(
|
||||
await client`SELECT 1 as health_check`;
|
||||
await client.end();
|
||||
|
||||
console.log(`Database connection successful on attempt ${attempt}.`);
|
||||
logger.info({ attempt }, 'Database connection successful');
|
||||
|
||||
return {
|
||||
success: true,
|
||||
@@ -66,12 +67,12 @@ export async function checkDatabaseHealth(
|
||||
} catch (error) {
|
||||
lastError = error as Error;
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
||||
console.error(`Connection failed on attempt ${attempt}: ${errorMessage}`);
|
||||
logger.warn({ attempt, error: errorMessage }, 'Database connection failed');
|
||||
|
||||
// Don't wait after the last attempt
|
||||
if (attempt < maxRetries) {
|
||||
const delay = Math.min(baseDelay * Math.pow(2, attempt - 1), maxDelay);
|
||||
console.log(`Waiting ${delay}ms before retry...`);
|
||||
logger.debug({ delay }, 'Waiting before retry');
|
||||
await new Promise((resolve) => setTimeout(resolve, delay));
|
||||
}
|
||||
}
|
||||
@@ -79,7 +80,10 @@ export async function checkDatabaseHealth(
|
||||
|
||||
const finalError = lastError?.message || 'Unknown database connection error';
|
||||
|
||||
console.error(`All ${maxRetries} attempts failed. Final error: ${finalError}`);
|
||||
logger.error(
|
||||
{ attempts: maxRetries, error: finalError },
|
||||
'All database connection attempts failed'
|
||||
);
|
||||
|
||||
return {
|
||||
success: false,
|
||||
@@ -95,10 +99,10 @@ export async function ensureDatabaseConnection(options?: HealthCheckOptions): Pr
|
||||
const result = await checkDatabaseHealth(options);
|
||||
|
||||
if (!result.success) {
|
||||
console.error('Database connection failed after all retry attempts');
|
||||
console.error(`Error: ${result.error}`);
|
||||
console.error(`Attempts made: ${result.attempts}`);
|
||||
console.error('Exiting application...');
|
||||
logger.fatal(
|
||||
{ error: result.error, attempts: result.attempts },
|
||||
'Database connection failed after all retry attempts. Exiting application'
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
29
src/lib/logger.ts
Normal file
29
src/lib/logger.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import pino from 'pino';
|
||||
import { LOG_PRETTY, LOG_LEVEL } from '$env/static/private';
|
||||
|
||||
const USE_PRETTY_LOGS = LOG_PRETTY === 'true';
|
||||
|
||||
const transport = USE_PRETTY_LOGS
|
||||
? {
|
||||
target: 'pino-pretty',
|
||||
options: {
|
||||
colorize: true,
|
||||
translateTime: 'SYS:standard',
|
||||
ignore: 'pid,hostname'
|
||||
}
|
||||
}
|
||||
: undefined;
|
||||
|
||||
// Create the logger instance
|
||||
export const logger = pino({
|
||||
level: LOG_LEVEL,
|
||||
transport
|
||||
});
|
||||
|
||||
// Export a helper to create child loggers with context
|
||||
export function createChildLogger(bindings: Record<string, unknown>) {
|
||||
return logger.child(bindings);
|
||||
}
|
||||
|
||||
// Export types
|
||||
export type Logger = typeof logger;
|
||||
@@ -2,7 +2,11 @@ import { database } from '$lib/database/db';
|
||||
import { events, inviteTokens } from '$lib/database/schema';
|
||||
import { fail, redirect } from '@sveltejs/kit';
|
||||
import type { Actions } from './$types';
|
||||
<<<<<<< HEAD
|
||||
import { generateInviteToken, calculateTokenExpiration } from '$lib/inviteTokenHelpers.js';
|
||||
=======
|
||||
import { logger } from '$lib/logger';
|
||||
>>>>>>> 222c2ee (feat: add pino logger for serverside)
|
||||
|
||||
// Generate a random URL-friendly ID
|
||||
function generateEventId(): string {
|
||||
@@ -116,7 +120,7 @@ export const actions: Actions = {
|
||||
userId: userId!
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Unexpected error', error);
|
||||
logger.error({ error, eventId, userId }, 'Unexpected error creating event');
|
||||
throw error;
|
||||
});
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { database } from '$lib/database/db';
|
||||
import { desc, inArray } from 'drizzle-orm';
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { events } from '$lib/database/schema';
|
||||
import { logger } from '$lib/logger';
|
||||
|
||||
export const load: PageServerLoad = async () => {
|
||||
try {
|
||||
@@ -33,7 +34,7 @@ export const load: PageServerLoad = async () => {
|
||||
events: transformedEvents
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error loading public events:', error);
|
||||
logger.error({ error }, 'Error loading public events');
|
||||
|
||||
// Return empty array on error to prevent page crash
|
||||
return {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { events } from '$lib/database/schema';
|
||||
import { fail } from '@sveltejs/kit';
|
||||
import { eq, desc } from 'drizzle-orm';
|
||||
import type { Actions } from './$types';
|
||||
import { logger } from '$lib/logger';
|
||||
|
||||
export const load = async ({ cookies }) => {
|
||||
const userId = cookies.get('cactoideUserId');
|
||||
@@ -36,7 +37,7 @@ export const load = async ({ cookies }) => {
|
||||
|
||||
return { events: transformedEvents };
|
||||
} catch (error) {
|
||||
console.error('Error loading user events:', error);
|
||||
logger.error({ error, userId }, 'Error loading user events');
|
||||
return { events: [] };
|
||||
}
|
||||
};
|
||||
@@ -68,7 +69,7 @@ export const actions: Actions = {
|
||||
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Error deleting event:', error);
|
||||
logger.error({ error, eventId, userId }, 'Error deleting event');
|
||||
return fail(500, { error: 'Failed to delete event' });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { events, rsvps } from '$lib/database/schema';
|
||||
import { eq, asc } from 'drizzle-orm';
|
||||
import { error, fail } from '@sveltejs/kit';
|
||||
import type { PageServerLoad, Actions } from './$types';
|
||||
import { logger } from '$lib/logger';
|
||||
|
||||
export const load: PageServerLoad = async ({ params, cookies }) => {
|
||||
const eventId = params.id;
|
||||
@@ -70,7 +71,7 @@ export const load: PageServerLoad = async ({ params, cookies }) => {
|
||||
} catch (err) {
|
||||
if (err instanceof Response) throw err; // This is the 404 error
|
||||
|
||||
console.error('Error loading event:', err);
|
||||
logger.error({ error: err, eventId }, 'Error loading event');
|
||||
throw error(500, 'Failed to load event');
|
||||
}
|
||||
};
|
||||
@@ -145,7 +146,7 @@ export const actions: Actions = {
|
||||
|
||||
return { success: true, type: 'add' };
|
||||
} catch (err) {
|
||||
console.error('Error adding RSVP:', err);
|
||||
logger.error({ error: err, eventId, userId, name }, 'Error adding RSVP');
|
||||
return fail(500, { error: 'Failed to add RSVP' });
|
||||
}
|
||||
},
|
||||
@@ -163,7 +164,7 @@ export const actions: Actions = {
|
||||
await database.delete(rsvps).where(eq(rsvps.id, rsvpId));
|
||||
return { success: true, type: 'remove' };
|
||||
} catch (err) {
|
||||
console.error('Error removing RSVP:', err);
|
||||
logger.error({ error: err, rsvpId }, 'Error removing RSVP');
|
||||
return fail(500, { error: 'Failed to remove RSVP' });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { events, inviteTokens } from '$lib/database/schema';
|
||||
import { eq, and } from 'drizzle-orm';
|
||||
import { fail, redirect } from '@sveltejs/kit';
|
||||
import type { Actions, PageServerLoad } from './$types';
|
||||
import { logger } from '$lib/logger';
|
||||
|
||||
export const load: PageServerLoad = async ({ params, cookies }) => {
|
||||
const eventId = params.id;
|
||||
@@ -165,7 +166,7 @@ export const actions: Actions = {
|
||||
})
|
||||
.where(and(eq(events.id, eventId), eq(events.userId, userId)))
|
||||
.catch((error) => {
|
||||
console.error('Unexpected error updating event', error);
|
||||
logger.error({ error, eventId, userId }, 'Unexpected error updating event');
|
||||
throw error;
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user