feat: Add centralized logging system with @link-stack/logger package

- Create new @link-stack/logger package wrapping Pino for structured logging
- Replace all console.log/error/warn statements across the monorepo
- Configure environment-aware logging (pretty-print in dev, JSON in prod)
- Add automatic redaction of sensitive fields (passwords, tokens, etc.)
- Remove dead commented-out logger file from bridge-worker
- Follow Pino's standard argument order (context object first, message second)
- Support log levels via LOG_LEVEL environment variable
- Export TypeScript types for better IDE support

This provides consistent, structured logging across all applications
and packages, making debugging easier and production logs more parseable.
This commit is contained in:
Darren Clarke 2025-08-20 11:37:39 +02:00
parent 5b89bfce7c
commit c1feaa4cb1
42 changed files with 3824 additions and 2422 deletions

View file

@ -0,0 +1,56 @@
import type { LoggerOptions } from 'pino';
export const getLogLevel = (): string => {
return process.env.LOG_LEVEL || (process.env.NODE_ENV === 'production' ? 'info' : 'debug');
};
export const getPinoConfig = (): LoggerOptions => {
const isDevelopment = process.env.NODE_ENV !== 'production';
const baseConfig: LoggerOptions = {
level: getLogLevel(),
formatters: {
level: (label) => {
return { level: label.toUpperCase() };
},
},
timestamp: () => `,"timestamp":"${new Date(Date.now()).toISOString()}"`,
redact: {
paths: [
'password',
'token',
'secret',
'api_key',
'apiKey',
'authorization',
'cookie',
'*.password',
'*.token',
'*.secret',
'*.api_key',
'*.apiKey',
],
censor: '[REDACTED]',
},
};
if (isDevelopment) {
// In development, use pretty printing for better readability
return {
...baseConfig,
transport: {
target: 'pino-pretty',
options: {
colorize: true,
translateTime: 'SYS:standard',
ignore: 'pid,hostname',
singleLine: false,
messageFormat: '{msg}',
},
},
};
}
// In production, use JSON for structured logging
return baseConfig;
};

View file

@ -0,0 +1,35 @@
import pino, { Logger as PinoLogger } from 'pino';
import { getPinoConfig } from './config';
export type Logger = PinoLogger;
// Create the default logger instance
export const logger: Logger = pino(getPinoConfig());
// Factory function to create child loggers with context
export const createLogger = (name: string, context?: Record<string, any>): Logger => {
return logger.child({ name, ...context });
};
// Export log levels for consistency
export const LogLevel = {
TRACE: 'trace',
DEBUG: 'debug',
INFO: 'info',
WARN: 'warn',
ERROR: 'error',
FATAL: 'fatal',
} as const;
export type LogLevelType = typeof LogLevel[keyof typeof LogLevel];
// Utility to check if a log level is enabled
export const isLogLevelEnabled = (level: LogLevelType): boolean => {
return logger.isLevelEnabled(level);
};
// Re-export pino types that might be useful
export type { LoggerOptions, DestinationStream } from 'pino';
// Default export for convenience
export default logger;