name[0]); $color = match ($level) { LogLevel::ERROR => Color::RED, LogLevel::INFO, LogLevel::DEBUG => Color::WHITE, LogLevel::WARNING => Color::YELLOW }; $buf .= wrap($letter.wrap('='.wrap($num, bold: true)), fg: $color).' '; $buf .= wrap($exec_time, fg: Color::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 .= $message."\n"; if (in_array($level, [LogLevel::ERROR, LogLevel::WARNING])) $buf .= backtrace(2)."\n"; // TODO test $set_perm = !file_exists(self::$logFile); $f = fopen(self::$logFile, 'a'); if (!$f) { fprintf(STDERR, __METHOD__.': failed to open file "'.self::$logFile.'" for writing'); return; } fwrite($f, $buf); fclose($f); if ($set_perm) setperm(self::$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()); } 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); } } function backtrace(int $shift = 0): string { $bt = debug_backtrace(); $lines = []; foreach ($bt as $i => $t) { if ($i < $shift) continue; if (!isset($t['file'])) { $lines[] = 'from ?'; } else { $lines[] = 'from '.$t['file'].':'.$t['line']; } } return implode("\n", $lines); }