StdoutLogger.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * This file is part of Hyperf.
  5. *
  6. * @link https://www.hyperf.io
  7. * @document https://hyperf.wiki
  8. * @contact group@hyperf.io
  9. * @license https://github.com/hyperf/hyperf/blob/master/LICENSE
  10. */
  11. namespace Hyperf\Framework\Logger;
  12. use Hyperf\Contract\ConfigInterface;
  13. use Hyperf\Contract\StdoutLoggerInterface;
  14. use Psr\Log\LogLevel;
  15. use Stringable;
  16. use Symfony\Component\Console\Output\ConsoleOutput;
  17. use Symfony\Component\Console\Output\OutputInterface;
  18. use function sprintf;
  19. use function str_replace;
  20. /**
  21. * Default logger for logging server start and requests.
  22. * PSR-3 logger implementation that logs to STDOUT, using a newline after each
  23. * message. Priority is ignored.
  24. */
  25. class StdoutLogger implements StdoutLoggerInterface
  26. {
  27. private OutputInterface $output;
  28. private array $tags = [
  29. 'component',
  30. ];
  31. public function __construct(private ConfigInterface $config, ?OutputInterface $output = null)
  32. {
  33. $this->output = $output ?? new ConsoleOutput();
  34. }
  35. public function emergency($message, array $context = []): void
  36. {
  37. $this->log(LogLevel::EMERGENCY, $message, $context);
  38. }
  39. public function alert($message, array $context = []): void
  40. {
  41. $this->log(LogLevel::ALERT, $message, $context);
  42. }
  43. public function critical($message, array $context = []): void
  44. {
  45. $this->log(LogLevel::CRITICAL, $message, $context);
  46. }
  47. public function error($message, array $context = []): void
  48. {
  49. $this->log(LogLevel::ERROR, $message, $context);
  50. }
  51. public function warning($message, array $context = []): void
  52. {
  53. $this->log(LogLevel::WARNING, $message, $context);
  54. }
  55. public function notice($message, array $context = []): void
  56. {
  57. $this->log(LogLevel::NOTICE, $message, $context);
  58. }
  59. public function info($message, array $context = []): void
  60. {
  61. $this->log(LogLevel::INFO, $message, $context);
  62. }
  63. public function debug($message, array $context = []): void
  64. {
  65. $this->log(LogLevel::DEBUG, $message, $context);
  66. }
  67. public function log($level, $message, array $context = []): void
  68. {
  69. $config = $this->config->get(StdoutLoggerInterface::class, ['log_level' => []]);
  70. // Check if the log level is allowed
  71. if (! in_array($level, $config['log_level'], true)) {
  72. return;
  73. }
  74. $tags = array_intersect_key($context, array_flip($this->tags));
  75. $context = array_diff_key($context, $tags);
  76. // Handle objects that are not Stringable
  77. foreach ($context as $key => $value) {
  78. if (is_object($value) && ! $value instanceof Stringable) {
  79. $context[$key] = '<OBJECT> ' . $value::class;
  80. }
  81. }
  82. $search = array_map(fn ($key) => sprintf('{%s}', $key), array_keys($context));
  83. $message = str_replace($search, $context, $this->getMessage((string) $message, $level, $tags));
  84. $this->output->writeln($message);
  85. }
  86. protected function getMessage(string $message, string $level = LogLevel::INFO, array $tags = [])
  87. {
  88. $tag = match ($level) {
  89. LogLevel::EMERGENCY, LogLevel::ALERT, LogLevel::CRITICAL => 'error',
  90. LogLevel::ERROR => 'fg=red',
  91. LogLevel::WARNING, LogLevel::NOTICE => 'comment',
  92. default => 'info',
  93. };
  94. $template = sprintf('<%s>[%s]</>', $tag, strtoupper($level));
  95. $implodedTags = '';
  96. foreach ($tags as $value) {
  97. $implodedTags .= (' [' . $value . ']');
  98. }
  99. return sprintf($template . $implodedTags . ' %s', $message);
  100. }
  101. }