mirror of
https://github.com/zhamao-robot/zhamao-logger.git
synced 2026-07-02 14:25:40 +08:00
refactor console logger
This commit is contained in:
@@ -12,24 +12,41 @@ class ConsoleLogger extends AbstractLogger
|
|||||||
{
|
{
|
||||||
public const VERSION = '1.0.0-alpha';
|
public const VERSION = '1.0.0-alpha';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日志输出格式
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
public static $format = '[%date%] [%level%] %process%%body%';
|
public static $format = '[%date%] [%level%] %process%%body%';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日志输出日期格式
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
public static $date_format = 'Y-m-d H:i:s';
|
public static $date_format = 'Y-m-d H:i:s';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string[][] 颜色表
|
* 颜色表
|
||||||
|
*
|
||||||
|
* @var array{int, array{string}}
|
||||||
*/
|
*/
|
||||||
protected static $styles = [
|
protected static $styles = [
|
||||||
LogLevel::EMERGENCY => ['blink', 'white', 'bg_bright_red'],
|
['blink', 'white', 'bg_bright_red'], // emergency
|
||||||
LogLevel::ALERT => ['white', 'bg_bright_red'],
|
['white', 'bg_bright_red'], // alert
|
||||||
LogLevel::CRITICAL => ['underline', 'red'],
|
['underline', 'red'], // critical
|
||||||
LogLevel::ERROR => ['red'],
|
['red'], // error
|
||||||
LogLevel::WARNING => ['bright_yellow'],
|
['bright_yellow'], // warning
|
||||||
LogLevel::NOTICE => ['cyan'],
|
['cyan'], // notice
|
||||||
LogLevel::INFO => ['green'],
|
['green'], // info
|
||||||
LogLevel::DEBUG => ['gray'],
|
['gray'], // debug
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 等级表
|
||||||
|
*
|
||||||
|
* @var array{int, int}
|
||||||
|
*/
|
||||||
protected static $levels = [
|
protected static $levels = [
|
||||||
LogLevel::EMERGENCY, // 0
|
LogLevel::EMERGENCY, // 0
|
||||||
LogLevel::ALERT, // 1
|
LogLevel::ALERT, // 1
|
||||||
@@ -41,31 +58,44 @@ class ConsoleLogger extends AbstractLogger
|
|||||||
LogLevel::DEBUG, // 7
|
LogLevel::DEBUG, // 7
|
||||||
];
|
];
|
||||||
|
|
||||||
protected static $logLevel;
|
/**
|
||||||
|
* 当前日志等级
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected static $log_level;
|
||||||
|
|
||||||
protected $exceptionHandler;
|
/**
|
||||||
|
* 创建一个 ConsoleLogger 实例
|
||||||
public function __construct($logLevel = LogLevel::INFO)
|
*
|
||||||
|
* @param string $level 日志等级
|
||||||
|
*/
|
||||||
|
public function __construct(string $level = LogLevel::INFO)
|
||||||
{
|
{
|
||||||
self::$logLevel = array_flip(self::$levels)[$logLevel];
|
self::$log_level = $this->castLogLevel($level);
|
||||||
//ExceptionHandler::getInstance();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string[][]
|
* 获取当前样式表
|
||||||
|
*
|
||||||
|
* @return array{int, array{string}}
|
||||||
*/
|
*/
|
||||||
public static function getStyles(): array
|
public static function getStyles(): array
|
||||||
{
|
{
|
||||||
return self::$styles;
|
return self::$styles;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function colorize($string, $level): string
|
/**
|
||||||
|
* 获取版本号
|
||||||
|
*/
|
||||||
|
public static function getVersion(): string
|
||||||
{
|
{
|
||||||
$string = $this->stringify($string);
|
return self::VERSION;
|
||||||
$styles = self::$styles[$level] ?? [];
|
|
||||||
return ConsoleColor::apply($styles, $string)->__toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打印执行栈
|
||||||
|
*/
|
||||||
public function trace(): void
|
public function trace(): void
|
||||||
{
|
{
|
||||||
$log = "Stack trace:\n";
|
$log = "Stack trace:\n";
|
||||||
@@ -84,82 +114,107 @@ class ConsoleLogger extends AbstractLogger
|
|||||||
}
|
}
|
||||||
$log .= "{$t['function']}()\n";
|
$log .= "{$t['function']}()\n";
|
||||||
}
|
}
|
||||||
$log = $this->colorize($log, LogLevel::DEBUG);
|
$log = $this->colorize($log, $this->castLogLevel(LogLevel::DEBUG));
|
||||||
echo $log;
|
echo $log;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTrace(): string
|
/**
|
||||||
|
* 根据日志等级将样式应用至指定字符串
|
||||||
|
*
|
||||||
|
* @param mixed $string 日志内容
|
||||||
|
* @param int $level 日志等级
|
||||||
|
*/
|
||||||
|
public function colorize($string, int $level): string
|
||||||
{
|
{
|
||||||
// if (self::$info_level !== null && self::$info_level == 4) {
|
$string = $this->stringify($string);
|
||||||
// $trace = debug_backtrace()[2] ?? ['file' => '', 'function' => ''];
|
$styles = self::$styles[$level] ?? [];
|
||||||
// $trace = '[' . ($trace['class'] ?? '') . ':' . ($trace['function'] ?? '') . '] ';
|
return ConsoleColor::apply($styles, $string)->__toString();
|
||||||
// }
|
|
||||||
// return $trace ?? '';
|
|
||||||
return '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// $trace = debug_backtrace()[1] ?? ['file' => '', 'function' => ''];
|
/**
|
||||||
// $trace = '[' . ($trace['class'] ?? '') . ':' . ($trace['function'] ?? '') . '] ';
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
public function log($level, $message, array $context = []): void
|
public function log($level, $message, array $context = []): void
|
||||||
{
|
{
|
||||||
if (!in_array($level, self::$levels, true)) {
|
$level = $this->castLogLevel($level);
|
||||||
throw new InvalidArgumentException();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (array_flip(self::$levels)[$level] > self::$logLevel) {
|
if (!$this->shouldLog($level)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$output = str_replace(
|
$output = str_replace(
|
||||||
['%date%', '%level%', '%body%'],
|
['%date%', '%level%', '%body%'],
|
||||||
[date(self::$date_format), strtoupper(substr($level, 0, 4)), $message],
|
[date(self::$date_format), strtoupper(substr(self::$levels[$level], 0, 4)), $message],
|
||||||
self::$format
|
self::$format
|
||||||
);
|
);
|
||||||
$output = $this->interpolate($output, $context);
|
$output = $this->interpolate($output, $context);
|
||||||
echo $this->colorize($output, $level) . "\n";
|
echo $this->colorize($output, $level) . "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getVersion(): string
|
/**
|
||||||
|
* 转换日志等级
|
||||||
|
*/
|
||||||
|
private function castLogLevel(string $level): int
|
||||||
{
|
{
|
||||||
return self::VERSION;
|
if (in_array($level, self::$levels, true)) {
|
||||||
|
return array_flip(self::$levels)[$level];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidArgumentException('无效的日志等级');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function stringify($item)
|
/**
|
||||||
|
* 将日志内容转换为字符串
|
||||||
|
*
|
||||||
|
* @param mixed $item 日志内容
|
||||||
|
*/
|
||||||
|
private function stringify($item): string
|
||||||
{
|
{
|
||||||
if (is_object($item) && method_exists($item, '__toString')) {
|
switch (true) {
|
||||||
return $item;
|
case is_callable($item):
|
||||||
|
if (is_array($item)) {
|
||||||
|
if (is_object($item[0])) {
|
||||||
|
return get_class($item[0]) . '@' . $item[1];
|
||||||
|
}
|
||||||
|
return $item[0] . '::' . $item[1];
|
||||||
|
}
|
||||||
|
return 'closure';
|
||||||
|
case is_string($item):
|
||||||
|
return $item;
|
||||||
|
case is_array($item):
|
||||||
|
return 'array' . json_encode($item, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_LINE_TERMINATORS);
|
||||||
|
case is_object($item):
|
||||||
|
return get_class($item);
|
||||||
|
case is_resource($item):
|
||||||
|
return 'resource(' . get_resource_type($item) . ')';
|
||||||
|
case is_null($item):
|
||||||
|
return 'null';
|
||||||
|
case is_bool($item):
|
||||||
|
return $item ? 'true' : 'false';
|
||||||
|
case is_float($item):
|
||||||
|
case is_int($item):
|
||||||
|
return (string) $item;
|
||||||
|
default:
|
||||||
|
return 'unknown';
|
||||||
}
|
}
|
||||||
if (is_string($item) || is_numeric($item)) {
|
|
||||||
return $item;
|
|
||||||
}
|
|
||||||
if (is_callable($item)) {
|
|
||||||
return '{Closure}';
|
|
||||||
}
|
|
||||||
if (is_bool($item)) {
|
|
||||||
return $item ? '*True*' : '*False*';
|
|
||||||
}
|
|
||||||
if (is_array($item)) {
|
|
||||||
return json_encode(
|
|
||||||
$item,
|
|
||||||
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_LINE_TERMINATORS
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (is_resource($item)) {
|
|
||||||
return '{Resource}';
|
|
||||||
}
|
|
||||||
if (is_null($item)) {
|
|
||||||
return 'NULL';
|
|
||||||
}
|
|
||||||
return '{Not Stringable Object:' . get_class($item) . '}';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function interpolate($message, array $context = [])
|
/**
|
||||||
|
* 判断是否应该记录该等级日志
|
||||||
|
*/
|
||||||
|
private function shouldLog(int $level): bool
|
||||||
{
|
{
|
||||||
if (is_array($message)) {
|
return $level <= self::$log_level;
|
||||||
return $message;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插入变量到日志内容中
|
||||||
|
*
|
||||||
|
* @param string $message 日志内容
|
||||||
|
* @param array $context 变量列表
|
||||||
|
*/
|
||||||
|
private function interpolate(string $message, array $context = []): string
|
||||||
|
{
|
||||||
$replace = [];
|
$replace = [];
|
||||||
foreach ($context as $key => $value) {
|
foreach ($context as $key => $value) {
|
||||||
$replace['{' . $key . '}'] = $this->stringify($value);
|
$replace['{' . $key . '}'] = $this->stringify($value);
|
||||||
|
|||||||
Reference in New Issue
Block a user