summaryrefslogtreecommitdiff
path: root/engine/logging.php
diff options
context:
space:
mode:
Diffstat (limited to 'engine/logging.php')
-rw-r--r--engine/logging.php271
1 files changed, 174 insertions, 97 deletions
diff --git a/engine/logging.php b/engine/logging.php
index 24803cf..d3fcc78 100644
--- a/engine/logging.php
+++ b/engine/logging.php
@@ -1,96 +1,122 @@
<?php
-require_once 'engine/ansi.php';
-use \ansi\Color;
-use function \ansi\wrap;
-
-enum LogLevel {
- case ERROR;
- case WARNING;
- case INFO;
- case DEBUG;
-}
-
-function logDebug(...$args): void { logging::logCustom(LogLevel::DEBUG, ...$args); }
-function logInfo(...$args): void { logging::logCustom(LogLevel::INFO, ...$args); }
-function logWarning(...$args): void { logging::logCustom(LogLevel::WARNING, ...$args); }
-function logError(...$args): void { logging::logCustom(LogLevel::ERROR, ...$args); }
+require_once 'lib/ansi.php';
-class logging {
+enum LogLevel: int {
+ case ERROR = 10;
+ case WARNING = 5;
+ case INFO = 3;
+ case DEBUG = 2;
+}
- // private static $instance = null;
+function logDebug(...$args): void { global $__logger; $__logger->log(LogLevel::DEBUG, ...$args); }
+function logInfo(...$args): void { global $__logger; $__logger->log(LogLevel::INFO, ...$args); }
+function logWarning(...$args): void { global $__logger; $__logger->log(LogLevel::WARNING, ...$args); }
+function logError(...$args): void { global $__logger; $__logger->log(LogLevel::ERROR, ...$args); }
- protected static ?string $logFile = null;
- protected static bool $enabled = false;
- protected static int $counter = 0;
+abstract class Logger {
+ protected bool $enabled = false;
+ protected int $counter = 0;
+ protected int $recursionLevel = 0;
/** @var ?callable $filter */
- protected static $filter = null;
+ protected $filter = null;
- public static function setLogFile(string $log_file): void {
- self::$logFile = $log_file;
+ function setErrorFilter(callable $filter): void {
+ $this->filter = $filter;
}
- public static function setErrorFilter(callable $filter): void {
- self::$filter = $filter;
+ function disable(): void {
+ $this->enabled = false;
}
- public static function disable(): void {
- self::$enabled = false;
+ function enable(): void {
+ static $error_handler_set = false;
+ $this->enabled = true;
- restore_error_handler();
- register_shutdown_function(function() {});
- }
+ if ($error_handler_set)
+ return;
- public static function enable(): void {
- self::$enabled = true;
+ $self = $this;
- set_error_handler(function($no, $str, $file, $line) {
- if (is_callable(self::$filter) && !(self::$filter)($no, $file, $line, $str))
+ set_error_handler(function($no, $str, $file, $line) use ($self) {
+ if (!$self->enabled)
return;
- self::write(LogLevel::ERROR, $str,
+ if (is_callable($self->filter) && !($self->filter)($no, $file, $line, $str))
+ return;
+
+ static::write(LogLevel::ERROR, $str,
errno: $no,
errfile: $file,
errline: $line);
});
- register_shutdown_function(function() {
- if (!($error = error_get_last()))
+ register_shutdown_function(function () use ($self) {
+ if (!$self->enabled || !($error = error_get_last()))
return;
- if (is_callable(self::$filter)
- && !(self::$filter)($error['type'], $error['file'], $error['line'], $error['message'])) {
+ if (is_callable($self->filter)
+ && !($self->filter)($error['type'], $error['file'], $error['line'], $error['message'])) {
return;
}
- self::write(LogLevel::ERROR, $error['message'],
+ static::write(LogLevel::ERROR, $error['message'],
errno: $error['type'],
- errfile: $error['file'],
+ errfile: $error['file'],
errline: $error['line']);
});
+
+ $error_handler_set = true;
}
- public static function logCustom(LogLevel $level, ...$args): void {
- global $config;
- if (!$config['is_dev'] && $level == LogLevel::DEBUG)
+ function log(LogLevel $level, ...$args): void {
+ if (!is_dev() && $level == LogLevel::DEBUG)
return;
- self::write($level, self::strVars($args));
+ $this->write($level, strVars($args));
}
- protected static function write(LogLevel $level,
- string $message,
- ?int $errno = null,
- ?string $errfile = null,
- ?string $errline = null): void {
+ protected function canReport(): bool {
+ return $this->recursionLevel < 3;
+ }
+
+ protected function write(LogLevel $level,
+ string $message,
+ ?int $errno = null,
+ ?string $errfile = null,
+ ?string $errline = null): void {
+ $this->recursionLevel++;
+
+ if ($this->canReport())
+ $this->writer($level, $this->counter++, $message, $errno, $errfile, $errline);
+
+ $this->recursionLevel--;
+ }
+
+ abstract protected function writer(LogLevel $level,
+ int $num,
+ string $message,
+ ?int $errno = null,
+ ?string $errfile = null,
+ ?string $errline = null): void;
+}
+
+class FileLogger extends Logger {
+
+ function __construct(protected string $logFile) {}
- // TODO test
- if (is_null(self::$logFile)) {
+ protected function writer(LogLevel $level,
+ int $num,
+ string $message,
+ ?int $errno = null,
+ ?string $errfile = null,
+ ?string $errline = null): void
+ {
+ if (is_null($this->logFile)) {
fprintf(STDERR, __METHOD__.': logfile is not set');
return;
}
- $num = self::$counter++;
$time = time();
// TODO rewrite using sprintf
@@ -98,47 +124,56 @@ class logging {
if (strlen($exec_time) < 6)
$exec_time .= str_repeat('0', 6 - strlen($exec_time));
- // $bt = backtrace(2);
-
- $title = PHP_SAPI == 'cli' ? 'cli' : $_SERVER['REQUEST_URI'];
+ $title = is_cli() ? 'cli' : $_SERVER['REQUEST_URI'];
$date = date('d/m/y H:i:s', $time);
$buf = '';
if ($num == 0) {
- $buf .= wrap(" $title ",
- fg: Color::WHITE,
- bg: Color::MAGENTA,
- fg_bright: true,
- bold: true);
- $buf .= wrap(" $date ", fg: Color::WHITE, bg: Color::BLUE, fg_bright: true);
+ $buf .= ansi(" $title ",
+ fg: AnsiColor::WHITE,
+ bg: AnsiColor::MAGENTA,
+ bold: true,
+ fg_bright: true);
+ $buf .= ansi(" $date ", fg: AnsiColor::WHITE, bg: AnsiColor::BLUE, fg_bright: true);
$buf .= "\n";
}
$letter = strtoupper($level->name[0]);
$color = match ($level) {
- LogLevel::ERROR => Color::RED,
- LogLevel::INFO, LogLevel::DEBUG => Color::WHITE,
- LogLevel::WARNING => Color::YELLOW
+ LogLevel::ERROR => AnsiColor::RED,
+ LogLevel::INFO => AnsiColor::GREEN,
+ LogLevel::DEBUG => AnsiColor::WHITE,
+ LogLevel::WARNING => AnsiColor::YELLOW
};
- $buf .= wrap($letter.wrap('='.wrap($num, bold: true)), fg: $color).' ';
- $buf .= wrap($exec_time, fg: Color::CYAN).' ';
+ $buf .= ansi($letter.ansi('='.ansi($num, bold: true)), fg: $color).' ';
+ $buf .= ansi($exec_time, fg: AnsiColor::CYAN).' ';
if (!is_null($errno)) {
- $buf .= wrap($errfile, fg: Color::GREEN);
- $buf .= wrap(':', fg: Color::WHITE);
- $buf .= wrap($errline, fg: Color::GREEN, fg_bright: true);
- $buf .= ' ('.self::getPhpErrorName($errno).') ';
+ $buf .= ansi($errfile, fg: AnsiColor::GREEN);
+ $buf .= ansi(':', fg: AnsiColor::WHITE);
+ $buf .= ansi($errline, fg: AnsiColor::GREEN, fg_bright: true);
+ $buf .= ' ('.getPHPErrorName($errno).') ';
}
$buf .= $message."\n";
if (in_array($level, [LogLevel::ERROR, LogLevel::WARNING]))
- $buf .= backtrace(2)."\n";
+ $buf .= backtrace_as_string(2)."\n";
+
+ $set_perm = false;
+ if (!file_exists($this->logFile)) {
+ $set_perm = true;
+ $dir = dirname($this->logFile);
+ echo "dir: $dir\n";
+
+ if (!file_exists($dir)) {
+ mkdir($dir);
+ setperm($dir);
+ }
+ }
- // TODO test
- $set_perm = !file_exists(self::$logFile);
- $f = fopen(self::$logFile, 'a');
+ $f = fopen($this->logFile, 'a');
if (!$f) {
- fprintf(STDERR, __METHOD__.': failed to open file "'.self::$logFile.'" for writing');
+ fprintf(STDERR, __METHOD__.': failed to open file \''.$this->logFile.'\' for writing');
return;
}
@@ -146,34 +181,76 @@ class logging {
fclose($f);
if ($set_perm)
- setperm(self::$logFile);
+ setperm($this->logFile);
}
- protected static function getPhpErrorName(int $errno): string {
- static $errors = null;
- if (is_null($errors))
- $errors = array_flip(array_slice(get_defined_constants(true)['Core'], 0, 15, true));
- return $errors[$errno];
- }
+}
- protected static function strVarDump($var, bool $print_r = false): string {
- ob_start();
- $print_r ? print_r($var) : var_dump($var);
- return trim(ob_get_clean());
- }
+class DatabaseLogger extends Logger {
+ protected function writer(LogLevel $level,
+ int $num,
+ string $message,
+ ?int $errno = null,
+ ?string $errfile = null,
+ ?string $errline = null): void
+ {
+ $db = DB();
+
+ $data = [
+ 'ts' => time(),
+ 'num' => $num,
+ 'time' => exectime(),
+ 'errno' => $errno,
+ 'file' => $errfile,
+ 'line' => $errline,
+ 'text' => $message,
+ 'level' => $level->value,
+ 'stacktrace' => backtrace_as_string(2),
+ 'is_cli' => intval(is_cli()),
+ 'user_id' => 0,
+ ];
+
+ if (is_cli()) {
+ $data += [
+ 'ip' => '',
+ 'ua' => '',
+ 'url' => '',
+ ];
+ } else {
+ $data += [
+ 'ip' => ip2ulong($_SERVER['REMOTE_ADDR']),
+ 'ua' => $_SERVER['HTTP_USER_AGENT'] ?? '',
+ 'url' => $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']
+ ];
+ }
- protected static function strVars(array $args): string {
- $args = array_map(fn($a) => match (gettype($a)) {
- 'string' => $a,
- 'array', 'object' => self::strVarDump($a, true),
- default => self::strVarDump($a)
- }, $args);
- return implode(' ', $args);
+ $db->insert('backend_errors', $data);
}
+}
+
+function getPHPErrorName(int $errno): string {
+ static $errors = null;
+ if (is_null($errors))
+ $errors = array_flip(array_slice(get_defined_constants(true)['Core'], 0, 15, true));
+ return $errors[$errno];
+}
+
+function strVarDump($var, bool $print_r = false): string {
+ ob_start();
+ $print_r ? print_r($var) : var_dump($var);
+ return trim(ob_get_clean());
+}
+function strVars(array $args): string {
+ $args = array_map(fn($a) => match (gettype($a)) {
+ 'string' => $a,
+ 'array', 'object' => strVarDump($a, true),
+ default => strVarDump($a)
+ }, $args);
+ return implode(' ', $args);
}
-function backtrace(int $shift = 0): string {
+function backtrace_as_string(int $shift = 0): string {
$bt = debug_backtrace();
$lines = [];
foreach ($bt as $i => $t) {
@@ -187,4 +264,4 @@ function backtrace(int $shift = 0): string {
}
}
return implode("\n", $lines);
-}
+} \ No newline at end of file