refactor: migrate backend to pnpm monorepo with Hono module architecture
- Replace Bun with pnpm 9 + Turborepo + tsx; apps/api renamed to apps/backend - Split backend into http/, modules/, lib/ layers mirroring tai-specguard - Add use-case + Result pattern, Problem Details RFC 7807, basePath /api/v1 - Mount Better Auth at /api/v1/auth, keep session-auth whitelist - Split Prisma schema into prisma/models/*, generate into generated/ - Rework packages/shared into lib/ + schemas/ with pagination DTOs - Implement health, groups, students, payments, waitlist modules - Add vitest suite with prisma mocks (21 tests), biome lint - Point web client to /api/v1/auth and /api/v1/groups/from-organization
This commit is contained in:
72
apps/backend/src/logger.ts
Normal file
72
apps/backend/src/logger.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { AsyncLocalStorage } from 'node:async_hooks';
|
||||
import pino from 'pino';
|
||||
import pinoPretty from 'pino-pretty';
|
||||
|
||||
type LoggerEnvironment = {
|
||||
nodeEnv?: string;
|
||||
};
|
||||
|
||||
type RequestLogContext = {
|
||||
requestId: string;
|
||||
};
|
||||
|
||||
const requestLogContext = new AsyncLocalStorage<RequestLogContext>();
|
||||
|
||||
const prettyOptions = {
|
||||
colorize: true,
|
||||
translateTime: 'SYS:standard',
|
||||
ignore: 'pid,hostname',
|
||||
};
|
||||
|
||||
const getLoggerEnvironment = (): LoggerEnvironment => ({
|
||||
nodeEnv: process.env.NODE_ENV,
|
||||
});
|
||||
|
||||
const isDevelopmentEnvironment = (environment: LoggerEnvironment) =>
|
||||
environment.nodeEnv !== 'production';
|
||||
|
||||
const isTestEnvironment = (environment: LoggerEnvironment) => environment.nodeEnv === 'test';
|
||||
|
||||
export const runWithRequestLogContext = <T>(requestId: string, callback: () => T): T =>
|
||||
requestLogContext.run({ requestId }, callback);
|
||||
|
||||
const getRequestLogMetadata = () => {
|
||||
const context = requestLogContext.getStore();
|
||||
|
||||
if (!context) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return { requestId: context.requestId };
|
||||
};
|
||||
|
||||
export const createLoggerOptions = (environment: LoggerEnvironment): pino.LoggerOptions => ({
|
||||
enabled: !isTestEnvironment(environment),
|
||||
level: isDevelopmentEnvironment(environment) ? 'debug' : 'info',
|
||||
mixin: () => getRequestLogMetadata(),
|
||||
formatters: {
|
||||
level(label, number) {
|
||||
return {
|
||||
level: number,
|
||||
severity: label.toUpperCase(),
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const createLogger = (
|
||||
environment: LoggerEnvironment = getLoggerEnvironment(),
|
||||
) => {
|
||||
const options = createLoggerOptions(environment);
|
||||
if (isTestEnvironment(environment)) {
|
||||
return pino({ ...options, level: 'silent' });
|
||||
}
|
||||
|
||||
if (isDevelopmentEnvironment(environment)) {
|
||||
return pino(options, pinoPretty(prettyOptions));
|
||||
}
|
||||
|
||||
return pino(options);
|
||||
};
|
||||
|
||||
export const logger = createLogger();
|
||||
Reference in New Issue
Block a user