From 36d48951c182da5ad1ad7f2d2c715c32bad48265 Mon Sep 17 00:00:00 2001 From: Zankaria Date: Fri, 4 Oct 2024 12:54:49 +0200 Subject: [PATCH] log-driver.php: split up log driver --- inc/Data/Driver/ErrorLogLogDriver.php | 28 ++++ inc/Data/Driver/FileLogDriver.php | 60 ++++++++ inc/Data/Driver/LogDriver.php | 22 +++ inc/Data/Driver/LogTrait.php | 26 ++++ inc/Data/Driver/StderrLogDriver.php | 27 ++++ inc/Data/Driver/SyslogLogDriver.php | 35 +++++ inc/Data/Driver/log-driver.php | 189 -------------------------- 7 files changed, 198 insertions(+), 189 deletions(-) create mode 100644 inc/Data/Driver/ErrorLogLogDriver.php create mode 100644 inc/Data/Driver/FileLogDriver.php create mode 100644 inc/Data/Driver/LogDriver.php create mode 100644 inc/Data/Driver/LogTrait.php create mode 100644 inc/Data/Driver/StderrLogDriver.php create mode 100644 inc/Data/Driver/SyslogLogDriver.php delete mode 100644 inc/Data/Driver/log-driver.php diff --git a/inc/Data/Driver/ErrorLogLogDriver.php b/inc/Data/Driver/ErrorLogLogDriver.php new file mode 100644 index 00000000..e2050606 --- /dev/null +++ b/inc/Data/Driver/ErrorLogLogDriver.php @@ -0,0 +1,28 @@ +name = $name; + $this->level = $level; + } + + public function log(int $level, string $message): void { + if ($level <= $this->level) { + $lv = $this->levelToString($level); + $line = "{$this->name} $lv: $message"; + \error_log($line, 0, null, null); + } + } +} diff --git a/inc/Data/Driver/FileLogDriver.php b/inc/Data/Driver/FileLogDriver.php new file mode 100644 index 00000000..18423cf1 --- /dev/null +++ b/inc/Data/Driver/FileLogDriver.php @@ -0,0 +1,60 @@ +fd = \fopen($file_path, 'a'); + if ($this->fd === false) { + throw new \RuntimeException("Unable to open log file at $file_path"); + } + + $this->name = $name; + $this->level = $level; + + // In some cases PHP does not run the destructor. + \register_shutdown_function([$this, 'close']); + } + + public function __destruct() { + $this->close(); + } + + public function log(int $level, string $message): void { + if ($level <= $this->level) { + $lv = $this->levelToString($level); + $line = "{$this->name} $lv: $message\n"; + \flock($this->fd, LOCK_EX); + \fwrite($this->fd, $line); + \flock($this->fd, LOCK_UN); + } + } + + public function close() { + \flock($this->fd, LOCK_UN); + \fclose($this->fd); + } +} diff --git a/inc/Data/Driver/LogDriver.php b/inc/Data/Driver/LogDriver.php new file mode 100644 index 00000000..fddc3f27 --- /dev/null +++ b/inc/Data/Driver/LogDriver.php @@ -0,0 +1,22 @@ +name = $name; + $this->level = $level; + } + + public function log(int $level, string $message): void { + if ($level <= $this->level) { + $lv = $this->levelToString($level); + \fwrite(\STDERR, "{$this->name} $lv: $message\n"); + } + } +} diff --git a/inc/Data/Driver/SyslogLogDriver.php b/inc/Data/Driver/SyslogLogDriver.php new file mode 100644 index 00000000..c0df5304 --- /dev/null +++ b/inc/Data/Driver/SyslogLogDriver.php @@ -0,0 +1,35 @@ +level = $level; + } + + public function log(int $level, string $message): void { + if ($level <= $this->level) { + if (isset($_SERVER['REMOTE_ADDR'], $_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI'])) { + // CGI + \syslog($level, "$message - client: {$_SERVER['REMOTE_ADDR']}, request: \"{$_SERVER['REQUEST_METHOD']} {$_SERVER['REQUEST_URI']}\""); + } else { + \syslog($level, $message); + } + } + } +} diff --git a/inc/Data/Driver/log-driver.php b/inc/Data/Driver/log-driver.php deleted file mode 100644 index 0026f009..00000000 --- a/inc/Data/Driver/log-driver.php +++ /dev/null @@ -1,189 +0,0 @@ -level = $level; - } - - public function log(int $level, string $message): void { - if ($level <= $this->level) { - if (isset($_SERVER['REMOTE_ADDR'], $_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI'])) { - // CGI - syslog($level, "$message - client: {$_SERVER['REMOTE_ADDR']}, request: \"{$_SERVER['REQUEST_METHOD']} {$_SERVER['REQUEST_URI']}\""); - } else { - syslog($level, $message); - } - } - } - }; - } - - /** - * Log via the php function error_log. - */ - public static function error_log(string $name, int $level): Log { - return new class($name, $level) implements Log { - private string $name; - private int $level; - - public function __construct(string $name, int $level) { - $this->name = $name; - $this->level = $level; - } - - public function log(int $level, string $message): void { - if ($level <= $this->level) { - $lv = LogDrivers::levelToString($level); - $line = "{$this->name} $lv: $message"; - error_log($line, 0, null, null); - } - } - }; - } - - /** - * Log to a file. - */ - public static function file(string $name, int $level, string $file_path): Log { - /* - * error_log is slow as hell in it's 3rd mode, so use fopen + file locking instead. - * https://grobmeier.solutions/performance-ofnonblocking-write-to-files-via-php-21082009.html - * - * Whatever file appending is atomic is contentious: - * - There are no POSIX guarantees: https://stackoverflow.com/a/7237901 - * - But linus suggested they are on linux, on some filesystems: https://web.archive.org/web/20151201111541/http://article.gmane.org/gmane.linux.kernel/43445 - * - But it doesn't seem to be always the case: https://www.notthewizard.com/2014/06/17/are-files-appends-really-atomic/ - * - * So we just use file locking to be sure. - */ - - $fd = fopen($file_path, 'a'); - if ($fd === false) { - throw new RuntimeException("Unable to open log file at $file_path"); - } - - $logger = new class($name, $level, $fd) implements Log { - private string $name; - private int $level; - private mixed $fd; - - public function __construct(string $name, int $level, mixed $fd) { - $this->name = $name; - $this->level = $level; - $this->fd = $fd; - } - - public function log(int $level, string $message): void { - if ($level <= $this->level) { - $lv = LogDrivers::levelToString($level); - $line = "{$this->name} $lv: $message\n"; - flock($this->fd, LOCK_EX); - fwrite($this->fd, $line); - flock($this->fd, LOCK_UN); - } - } - - public function close() { - fclose($this->fd); - } - }; - - // Close the file on shutdown. - register_shutdown_function([$logger, 'close']); - - return $logger; - } - - /** - * Log to php's standard error file stream. - */ - public static function stderr(string $name, int $level): Log { - return new class($name, $level) implements Log { - private $name; - private $level; - - public function __construct(string $name, int $level) { - $this->name = $name; - $this->level = $level; - } - - public function log(int $level, string $message): void { - if ($level <= $this->level) { - $lv = LogDrivers::levelToString($level); - fwrite(STDERR, "{$this->name} $lv: $message\n"); - } - } - }; - } - - /** - * No-op logging system. - */ - public static function none(): Log { - return new class() implements Log { - public function log($level, $message): void { - // No-op. - } - }; - } -} - -interface Log { - public const EMERG = LOG_EMERG; - public const ERROR = LOG_ERR; - public const WARNING = LOG_WARNING; - public const NOTICE = LOG_NOTICE; - public const INFO = LOG_INFO; - public const DEBUG = LOG_DEBUG; - - - /** - * Log a message if the level of relevancy is at least the minimum. - * - * @param int $level Message level. Use Log interface constants. - * @param string $message The message to log. - */ - public function log(int $level, string $message): void; -}