/**
* Structured logging utility that integrates with Apify logging
* Replaces console.* calls with structured, contextual logging
*/
import { log } from 'apify';
export type LogLevel = 'debug' | 'info' | 'warning' | 'error';
export interface LogContext {
[key: string]: unknown;
}
class Logger {
private logLevel: LogLevel;
constructor() {
// Determine log level from environment
const envLevel = (process.env.LOG_LEVEL || 'info').toLowerCase() as LogLevel;
const levels: LogLevel[] = ['debug', 'info', 'warning', 'error'];
this.logLevel = levels.includes(envLevel) ? envLevel : 'info';
}
private shouldLog(level: LogLevel): boolean {
const levels: LogLevel[] = ['debug', 'info', 'warning', 'error'];
return levels.indexOf(level) >= levels.indexOf(this.logLevel);
}
/**
* Log debug information (only in development)
*/
debug(message: string, context?: LogContext): void {
if (this.shouldLog('debug')) {
log.debug(message, context || {});
}
}
/**
* Log informational messages
*/
info(message: string, context?: LogContext): void {
if (this.shouldLog('info')) {
log.info(message, context || {});
}
}
/**
* Log warning messages
*/
warning(message: string, errorOrContext?: unknown, context?: LogContext): void {
if (this.shouldLog('warning')) {
let finalContext: LogContext = {};
// If second parameter is an error, extract error info
if (errorOrContext instanceof Error) {
finalContext = {
error: {
message: errorOrContext.message,
stack: errorOrContext.stack,
name: errorOrContext.name,
},
...context,
};
} else if (errorOrContext && typeof errorOrContext === 'object') {
// If it's a context object
finalContext = { ...errorOrContext as LogContext, ...context };
} else if (context) {
finalContext = context;
}
log.warning(message, finalContext);
}
}
/**
* Log error messages with optional error object
*/
error(message: string, error?: unknown, context?: LogContext): void {
if (this.shouldLog('error')) {
const errorContext: LogContext = {
...context,
error: error instanceof Error
? {
message: error.message,
stack: error.stack,
name: error.name,
}
: String(error),
};
log.error(message, errorContext);
}
}
/**
* Log security-related events
*/
security(message: string, context?: LogContext): void {
log.warning(`[SECURITY] ${message}`, {
...context,
timestamp: new Date().toISOString(),
});
}
}
// Export singleton instance
export const logger = new Logger();