logFile = rtrim($logDir, '/') . '/' . $channel . '.log'; $this->ensureWritablePath(); } public function emergency($message, array $context = []): void { $this->log('emergency', $message, $context); } public function alert($message, array $context = []): void { $this->log('alert', $message, $context); } public function critical($message, array $context = []): void { $this->log('critical', $message, $context); } public function error($message, array $context = []): void { $this->log('error', $message, $context); } public function warning($message, array $context = []): void { $this->log('warning', $message, $context); } public function notice($message, array $context = []): void { $this->log('notice', $message, $context); } public function info($message, array $context = []): void { $this->log('info', $message, $context); } public function debug($message, array $context = []): void { $this->log('debug', $message, $context); } public function log($level, $message, array $context = []): void { $this->ensureWritablePath(); $dt = \DateTimeImmutable::createFromFormat('U.u', sprintf('%.6F', microtime(true))); $timestamp = $dt?->format('Y-m-d H:i:s.u') ?? date('Y-m-d H:i:s'); $line = $timestamp . ' ' . $this->interpolate((string) $message, $context) . PHP_EOL; if (@file_put_contents($this->logFile, $line, FILE_APPEND | LOCK_EX) === false) { error_log(sprintf('Failed to write to log file: %s', $this->logFile)); } } private function ensureWritablePath(): void { $logDir = dirname($this->logFile); if (!is_dir($logDir)) { @mkdir($logDir, 0777, true); } if (is_dir($logDir)) { @chmod($logDir, 0777); } if (!file_exists($this->logFile)) { @touch($this->logFile); } clearstatcache(true, $this->logFile); if (file_exists($this->logFile)) { @chmod($this->logFile, 0666); } } private function interpolate(string $message, array $context): string { if (!str_contains($message, '{')) { return $message; } $replace = []; foreach ($context as $key => $val) { if (is_array($val) || (is_object($val) && !method_exists($val, '__toString'))) { continue; } $replace['{' . $key . '}'] = (string) $val; } return strtr($message, $replace); } }