95 lines
2.1 KiB
TypeScript
95 lines
2.1 KiB
TypeScript
|
|
/**
|
||
|
|
* Structured logging utility
|
||
|
|
*/
|
||
|
|
|
||
|
|
type LogLevel = 'debug' | 'info' | 'warn' | 'error'
|
||
|
|
|
||
|
|
interface LogEntry {
|
||
|
|
level: LogLevel
|
||
|
|
message: string
|
||
|
|
timestamp: string
|
||
|
|
context?: Record<string, unknown>
|
||
|
|
error?: Error
|
||
|
|
}
|
||
|
|
|
||
|
|
class Logger {
|
||
|
|
private logLevel: LogLevel
|
||
|
|
|
||
|
|
constructor() {
|
||
|
|
this.logLevel = (process.env.NODE_ENV === 'development' ? 'debug' : 'info') as LogLevel
|
||
|
|
}
|
||
|
|
|
||
|
|
private shouldLog(level: LogLevel): boolean {
|
||
|
|
const levels: LogLevel[] = ['debug', 'info', 'warn', 'error']
|
||
|
|
return levels.indexOf(level) >= levels.indexOf(this.logLevel)
|
||
|
|
}
|
||
|
|
|
||
|
|
private formatEntry(entry: LogEntry): string {
|
||
|
|
const { level, message, timestamp, context, error } = entry
|
||
|
|
const parts = [`[${timestamp}]`, `[${level.toUpperCase()}]`, message]
|
||
|
|
|
||
|
|
if (context && Object.keys(context).length > 0) {
|
||
|
|
parts.push(JSON.stringify(context))
|
||
|
|
}
|
||
|
|
|
||
|
|
if (error) {
|
||
|
|
parts.push(`\nError: ${error.message}`)
|
||
|
|
if (error.stack) {
|
||
|
|
parts.push(`\nStack: ${error.stack}`)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return parts.join(' ')
|
||
|
|
}
|
||
|
|
|
||
|
|
private log(level: LogLevel, message: string, context?: Record<string, unknown>, error?: Error) {
|
||
|
|
if (!this.shouldLog(level)) {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
const entry: LogEntry = {
|
||
|
|
level,
|
||
|
|
message,
|
||
|
|
timestamp: new Date().toISOString(),
|
||
|
|
context,
|
||
|
|
error,
|
||
|
|
}
|
||
|
|
|
||
|
|
const formatted = this.formatEntry(entry)
|
||
|
|
|
||
|
|
switch (level) {
|
||
|
|
case 'debug':
|
||
|
|
console.debug(formatted)
|
||
|
|
break
|
||
|
|
case 'info':
|
||
|
|
console.info(formatted)
|
||
|
|
break
|
||
|
|
case 'warn':
|
||
|
|
console.warn(formatted)
|
||
|
|
break
|
||
|
|
case 'error':
|
||
|
|
console.error(formatted)
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
debug(message: string, context?: Record<string, unknown>) {
|
||
|
|
this.log('debug', message, context)
|
||
|
|
}
|
||
|
|
|
||
|
|
info(message: string, context?: Record<string, unknown>) {
|
||
|
|
this.log('info', message, context)
|
||
|
|
}
|
||
|
|
|
||
|
|
warn(message: string, context?: Record<string, unknown>) {
|
||
|
|
this.log('warn', message, context)
|
||
|
|
}
|
||
|
|
|
||
|
|
error(message: string, error?: Error, context?: Record<string, unknown>) {
|
||
|
|
this.log('error', message, context, error)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export const logger = new Logger()
|
||
|
|
|