Skip to content

Commit

Permalink
Merge pull request #51 from sj-i/logger_wrapper
Browse files Browse the repository at this point in the history
Logger wrapper
  • Loading branch information
sj-i committed Aug 12, 2021
2 parents 7f35811 + 09587e8 commit e847fb5
Show file tree
Hide file tree
Showing 13 changed files with 530 additions and 0 deletions.
12 changes: 12 additions & 0 deletions config/di.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

declare(strict_types=1);

use DI\Container;
use Monolog\Formatter\JsonFormatter;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use Noodlehaus\Config;
Expand All @@ -26,6 +28,10 @@
use PhpProfiler\Lib\Elf\SymbolResolver\SymbolResolverCreatorInterface;
use PhpProfiler\Lib\File\CatFileReader;
use PhpProfiler\Lib\File\FileReaderInterface;
use PhpProfiler\Lib\Log\StateCollector\CallerStateCollector;
use PhpProfiler\Lib\Log\StateCollector\GroupedStateCollector;
use PhpProfiler\Lib\Log\StateCollector\ProcessStateCollector;
use PhpProfiler\Lib\Log\StateCollector\StateCollector;
use PhpProfiler\Lib\PhpInternals\ZendTypeReader;
use PhpProfiler\Lib\Process\MemoryReader\MemoryReader;
use PhpProfiler\Lib\Process\MemoryReader\MemoryReaderInterface;
Expand All @@ -50,6 +56,12 @@
ProcessSearcherInterface::class => autowire(ProcessSearcher::class),
Config::class => fn () => Config::load(__DIR__ . '/config.php'),
TemplatePathResolverInterface::class => autowire(TemplatePathResolver::class),
StateCollector::class => function (Container $container) {
$collectors = [];
$collectors[] = $container->make(ProcessStateCollector::class);
$collectors[] = $container->make(CallerStateCollector::class);
return new GroupedStateCollector(...$collectors);
},
LoggerInterface::class => function (Config $config) {
$logger = new Logger('default');
$logger->pushHandler(
Expand Down
8 changes: 8 additions & 0 deletions php-profiler
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ declare(strict_types=1);

use DI\ContainerBuilder;
use PhpProfiler\Command\CommandEnumerator;
use PhpProfiler\Lib\Log\Log;
use Psr\Log\LoggerInterface;
use PhpProfiler\Lib\Log\StateCollector\StateCollector;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;

Expand All @@ -22,6 +25,11 @@ require 'vendor/autoload.php';
$application = new Application();
$container = (new ContainerBuilder())->addDefinitions(__DIR__ . '/config/di.php')->build();

Log::initializeLogger(
$container->make(LoggerInterface::class),
$container->make(StateCollector::class),
);

/** @var iterable<class-string> $command_enumerator */
$command_enumerator = new CommandEnumerator(new GlobIterator(__DIR__. '/src/Command/*/*Command.php'));
foreach ($command_enumerator as $command_class) {
Expand Down
8 changes: 8 additions & 0 deletions src/Lib/Amphp/worker-entry.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
use DI\ContainerBuilder;
use PhpProfiler\Lib\Amphp\WorkerEntryPointInterface;
use PhpProfiler\Lib\Amphp\MessageProtocolInterface;
use PhpProfiler\Lib\Log\Log;
use PhpProfiler\Lib\Log\StateCollector\StateCollector;
use Psr\Log\LoggerInterface;

return function (Channel $channel) use ($argv): \Generator {
/**
Expand All @@ -24,6 +27,11 @@
*/
[, $entry_class, $protocol_class, $di_config] = $argv;
$container = (new ContainerBuilder())->addDefinitions($di_config)->build();
/** @var LoggerInterface $logger */
$logger = $container->make(LoggerInterface::class);
/** @var StateCollector $state_collector */
$state_collector = $container->make(StateCollector::class);
Log::initializeLogger($logger, $state_collector);
/** @var MessageProtocolInterface $protocol */
$protocol = $container->make($protocol_class, ['channel' => $channel]);
/** @var WorkerEntryPointInterface $entry_point */
Expand Down
109 changes: 109 additions & 0 deletions src/Lib/Log/Log.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?php

/**
* This file is part of the sj-i/php-profiler package.
*
* (c) sji <sji@sj-i.dev>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace PhpProfiler\Lib\Log;

use PhpProfiler\Lib\Log\StateCollector\NullStateCollector;
use PhpProfiler\Lib\Log\StateCollector\StateCollector;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use Psr\Log\NullLogger;

final class Log
{
public const LOG_LEVELS = [
LogLevel::EMERGENCY,
LogLevel::ALERT,
LogLevel::CRITICAL,
LogLevel::ERROR,
LogLevel::WARNING,
LogLevel::NOTICE,
LogLevel::INFO,
LogLevel::DEBUG,
];

private static ?LoggerInterface $logger = null;
private static ?StateCollector $state_collector = null;

public static function initializeLogger(
LoggerInterface $logger,
StateCollector $state_collector,
): void {
self::$logger = $logger;
self::$state_collector = $state_collector;
}

public static function getLogger(): LoggerInterface
{
if (!isset(self::$logger)) {
self::$logger = new NullLogger();
}
return self::$logger;
}

public static function getCollector(): StateCollector
{
if (!isset(self::$state_collector)) {
self::$state_collector = new NullStateCollector();
}
return self::$state_collector;
}

/**
* @param value-of<self::LOG_LEVELS> $level
*/
public static function log(string $level, string $message, array $context = []): void
{
self::getLogger()->log($level, $message, $context + self::getCollector()->collect());
}

public static function emergency(string $message, array $context = []): void
{
self::log(LogLevel::EMERGENCY, $message, $context);
}

public static function alert(string $message, array $context = []): void
{
self::log(LogLevel::ALERT, $message, $context);
}

public static function critical(string $message, array $context = []): void
{
self::log(LogLevel::CRITICAL, $message, $context);
}

public static function error(string $message, array $context = []): void
{
self::log(LogLevel::ERROR, $message, $context);
}

public static function warning(string $message, array $context = []): void
{
self::log(LogLevel::WARNING, $message, $context);
}

public static function notice(string $message, array $context = []): void
{
self::log(LogLevel::NOTICE, $message, $context);
}

public static function info(string $message, array $context = []): void
{
self::log(LogLevel::INFO, $message, $context);
}

public static function debug(string $message, array $context = []): void
{
self::log(LogLevel::DEBUG, $message, $context);
}
}
60 changes: 60 additions & 0 deletions src/Lib/Log/StateCollector/CallerStateCollector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

/**
* This file is part of the sj-i/php-profiler package.
*
* (c) sji <sji@sj-i.dev>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace PhpProfiler\Lib\Log\StateCollector;

use PhpProfiler\Lib\Log\Log;

use function debug_backtrace;

final class CallerStateCollector implements StateCollector
{
public function collect(): array
{
$backtrace = debug_backtrace(limit: 5);

$last_logger_frame = [];
$caller_frame = [];

foreach ($backtrace as $frame) {
if ($this->isLoggerFrame($frame)) {
$last_logger_frame = $frame;
} elseif ($last_logger_frame) {
$caller_frame = $frame;
break;
}
}

$result = [];
if ($last_logger_frame) {
$result['context'] = [
'file' => $last_logger_frame['file'],
'line' => $last_logger_frame['line'],
'class' => $caller_frame['class'] ?? '',
'function' => $caller_frame['function'] ?? '',
'args' => $caller_frame['args'] ?? '',
];
}
return $result;
}

private function isLoggerFrame(array $frame): bool
{
if ($frame['class'] === Log::class) {
if (in_array($frame['function'], ['log', ...Log::LOG_LEVELS], true)) {
return true;
}
}
return false;
}
}
37 changes: 37 additions & 0 deletions src/Lib/Log/StateCollector/GroupedStateCollector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

/**
* This file is part of the sj-i/php-profiler package.
*
* (c) sji <sji@sj-i.dev>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace PhpProfiler\Lib\Log\StateCollector;

final class GroupedStateCollector implements StateCollector
{
/** @var StateCollector[] */
private array $collectors;

/**
* @param StateCollector ...$collectors
*/
public function __construct(StateCollector ...$collectors)
{
$this->collectors = $collectors;
}

public function collect(): array
{
$result = [];
foreach ($this->collectors as $collector) {
$result += $collector->collect();
}
return $result;
}
}
22 changes: 22 additions & 0 deletions src/Lib/Log/StateCollector/NullStateCollector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

/**
* This file is part of the sj-i/php-profiler package.
*
* (c) sji <sji@sj-i.dev>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace PhpProfiler\Lib\Log\StateCollector;

final class NullStateCollector implements StateCollector
{
public function collect(): array
{
return [];
}
}
30 changes: 30 additions & 0 deletions src/Lib/Log/StateCollector/ProcessStateCollector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

/**
* This file is part of the sj-i/php-profiler package.
*
* (c) sji <sji@sj-i.dev>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace PhpProfiler\Lib\Log\StateCollector;

use function getmypid;
use function memory_get_peak_usage;
use function memory_get_usage;

final class ProcessStateCollector implements StateCollector
{
public function collect(): array
{
return [
'pid' => getmypid(),
'memory_usage' => memory_get_usage(),
'peak_memory_usage' => memory_get_peak_usage(),
];
}
}
19 changes: 19 additions & 0 deletions src/Lib/Log/StateCollector/StateCollector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

/**
* This file is part of the sj-i/php-profiler package.
*
* (c) sji <sji@sj-i.dev>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace PhpProfiler\Lib\Log\StateCollector;

interface StateCollector
{
public function collect(): array;
}
Loading

0 comments on commit e847fb5

Please sign in to comment.