logger = new MonologLogger('whmcs-migrate'); $monologLevel = Level::fromName($level); // File handler — detailed format $fileFormatter = new LineFormatter( format: "[%datetime%] %level_name%: %message% %context%\n", dateFormat: 'Y-m-d H:i:s', allowInlineLineBreaks: true, ignoreEmptyContextAndExtra: true, ); $fileHandler = new StreamHandler($logDir . '/migration.log', $monologLevel); $fileHandler->setFormatter($fileFormatter); $this->logger->pushHandler($fileHandler); // Console handler — colorized $consoleFormatter = new LineFormatter( format: "%level_name%: %message% %context%\n", dateFormat: null, allowInlineLineBreaks: true, ignoreEmptyContextAndExtra: true, ); $consoleHandler = new StreamHandler('php://stdout', $monologLevel); $consoleHandler->setFormatter($consoleFormatter); $this->logger->pushHandler($consoleHandler); } public function info(string $message, array $context = []): void { $this->logger->info($message, $context); } public function warning(string $message, array $context = []): void { $this->logger->warning($message, $context); } public function error(string $message, array $context = []): void { $this->logger->error($message, $context); } public function debug(string $message, array $context = []): void { $this->logger->debug($message, $context); } /** * Log a visual section separator. */ public function section(string $title): void { $separator = str_repeat('=', 60); $this->info("\n{$separator}\n{$title}\n{$separator}"); } }