You've already forked Php-Template
chore: add deployment configurations and tests for logger and dispatcher (#17)
All checks were successful
🧪✨ Tests Workflow / 🛡️ 🔒 Library Audit (push) Successful in 1m40s
🧪✨ Tests Workflow / 📝 ✨ Code Lint (push) Successful in 1m36s
🧪✨ Tests Workflow / 🛡️ 🔒 License Check (push) Successful in 2m4s
🧪✨ Tests Workflow / 🐙 🔍 Code Sniffer (push) Successful in 2m24s
🧪✨ Tests Workflow / 🧪 ✨ Database Migrations (push) Successful in 2m46s
🧪✨ Tests Workflow / 🧪 ✅ Unit Tests (push) Successful in 1m27s
🏗️✨ Build Workflow / 🖥️ 🔨 Build (push) Successful in 16m7s
🏗️✨ Build Workflow / 🖥️ 🔨 Build Migrations (push) Successful in 1m29s
All checks were successful
🧪✨ Tests Workflow / 🛡️ 🔒 Library Audit (push) Successful in 1m40s
🧪✨ Tests Workflow / 📝 ✨ Code Lint (push) Successful in 1m36s
🧪✨ Tests Workflow / 🛡️ 🔒 License Check (push) Successful in 2m4s
🧪✨ Tests Workflow / 🐙 🔍 Code Sniffer (push) Successful in 2m24s
🧪✨ Tests Workflow / 🧪 ✨ Database Migrations (push) Successful in 2m46s
🧪✨ Tests Workflow / 🧪 ✅ Unit Tests (push) Successful in 1m27s
🏗️✨ Build Workflow / 🖥️ 🔨 Build (push) Successful in 16m7s
🏗️✨ Build Workflow / 🖥️ 🔨 Build Migrations (push) Successful in 1m29s
Reviewed-on: #17 Co-authored-by: Ron Rise <ron@siteworxpro.com> Co-committed-by: Ron Rise <ron@siteworxpro.com>
This commit was merged in pull request #17.
This commit is contained in:
10
.run/ Compose Deployment.run.xml
Normal file
10
.run/ Compose Deployment.run.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name=" Compose Deployment" type="docker-deploy" factoryName="docker-compose.yml" server-name="Docker">
|
||||||
|
<deployment type="docker-compose.yml">
|
||||||
|
<settings>
|
||||||
|
<option name="sourceFilePath" value="docker-compose.yml" />
|
||||||
|
</settings>
|
||||||
|
</deployment>
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
8
.run/All.run.xml
Normal file
8
.run/All.run.xml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="All" type="ComposerRunConfigurationType" factoryName="Composer Script">
|
||||||
|
<option name="commandLineParameters" value="" />
|
||||||
|
<option name="pathToComposerJson" value="$PROJECT_DIR$/composer.json" />
|
||||||
|
<option name="script" value="tests:all" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
8
.run/Lint_fix.run.xml
Normal file
8
.run/Lint_fix.run.xml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Lint:fix" type="ComposerRunConfigurationType" factoryName="Composer Script">
|
||||||
|
<option name="commandLineParameters" value="" />
|
||||||
|
<option name="pathToComposerJson" value="$PROJECT_DIR$/composer.json" />
|
||||||
|
<option name="script" value="tests:lint:fix" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
11
.run/Main.run.xml
Normal file
11
.run/Main.run.xml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Main" type="PHPUnitRunConfigurationType" factoryName="PHPUnit">
|
||||||
|
<CommandLine>
|
||||||
|
<PhpTestInterpreterSettings>
|
||||||
|
<option name="interpreterName" value="composer-runtime" />
|
||||||
|
</PhpTestInterpreterSettings>
|
||||||
|
</CommandLine>
|
||||||
|
<TestRunner configuration_file="$PROJECT_DIR$/phpunit.xml" scope="XML" use_alternative_configuration_file="true" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
@@ -83,7 +83,7 @@ services:
|
|||||||
postgres:
|
postgres:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
environment:
|
environment:
|
||||||
QUEUE_BROKER: kafka
|
QUEUE_BROKER: redis
|
||||||
PHP_IDE_CONFIG: serverName=localhost
|
PHP_IDE_CONFIG: serverName=localhost
|
||||||
WORKERS: 1
|
WORKERS: 1
|
||||||
DEBUG: 1
|
DEBUG: 1
|
||||||
|
|||||||
@@ -6,10 +6,12 @@ namespace Siteworxpro\App\Log;
|
|||||||
|
|
||||||
use Monolog\Formatter\JsonFormatter;
|
use Monolog\Formatter\JsonFormatter;
|
||||||
use Monolog\Handler\StreamHandler;
|
use Monolog\Handler\StreamHandler;
|
||||||
|
use Psr\Container\ContainerExceptionInterface;
|
||||||
|
use Psr\Container\NotFoundExceptionInterface;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Psr\Log\LogLevel;
|
use Psr\Log\LogLevel;
|
||||||
use RoadRunner\Logger\Logger as RRLogger;
|
use RoadRunner\Logger\Logger as RRLogger;
|
||||||
use Spiral\Goridge\RPC\RPC;
|
use Siteworxpro\App\Services\Facades\RoadRunnerLogger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logger implementation that conforms to PSR-3 (`Psr\Log\LoggerInterface`).
|
* Logger implementation that conforms to PSR-3 (`Psr\Log\LoggerInterface`).
|
||||||
@@ -30,9 +32,9 @@ class Logger implements LoggerInterface
|
|||||||
/**
|
/**
|
||||||
* RoadRunner RPC logger instance when running under RoadRunner.
|
* RoadRunner RPC logger instance when running under RoadRunner.
|
||||||
*
|
*
|
||||||
* @var RRLogger|null
|
* @var RRLogger | LoggerInterface | null
|
||||||
*/
|
*/
|
||||||
private ?RRLogger $rpcLogger = null;
|
private RRLogger | LoggerInterface | null $rpcLogger = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Monolog logger used as a fallback to write JSON-formatted logs to stdout.
|
* Monolog logger used as a fallback to write JSON-formatted logs to stdout.
|
||||||
@@ -66,21 +68,28 @@ class Logger implements LoggerInterface
|
|||||||
* @param string $level Minimum level to log (PSR-3 level string). Messages with
|
* @param string $level Minimum level to log (PSR-3 level string). Messages with
|
||||||
* a higher numeric value in `$levels` will be ignored.
|
* a higher numeric value in `$levels` will be ignored.
|
||||||
*
|
*
|
||||||
|
* @param resource | null $streamOutput Optional stream handler for Monolog.
|
||||||
|
*
|
||||||
* The default is `LogLevel::DEBUG` (log everything).
|
* The default is `LogLevel::DEBUG` (log everything).
|
||||||
*
|
*
|
||||||
* If `$_SERVER['RR_RPC']` is set, an RPC connection will be attempted at
|
* If `$_SERVER['RR_RPC']` is set, an RPC connection will be attempted at
|
||||||
* $_SERVER['RR_RPC'] and a RoadRunner RPC logger will be used.
|
* $_SERVER['RR_RPC'] and a RoadRunner RPC logger will be used.
|
||||||
|
*
|
||||||
|
* @throws ContainerExceptionInterface
|
||||||
|
* @throws NotFoundExceptionInterface
|
||||||
*/
|
*/
|
||||||
public function __construct(private readonly string $level = LogLevel::DEBUG)
|
public function __construct(
|
||||||
{
|
private readonly string $level = LogLevel::DEBUG,
|
||||||
|
$streamOutput = null,
|
||||||
|
) {
|
||||||
if (isset($_SERVER['RR_RPC'])) {
|
if (isset($_SERVER['RR_RPC'])) {
|
||||||
$rpc = RPC::create($_SERVER['RR_RPC']);
|
$this->rpcLogger = RoadRunnerLogger::getFacadeRoot();
|
||||||
$this->rpcLogger = new RRLogger($rpc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->monologLogger = new \Monolog\Logger('app_logger');
|
$this->monologLogger = new \Monolog\Logger('app_logger');
|
||||||
$formatter = new JsonFormatter();
|
$formatter = new JsonFormatter();
|
||||||
$this->monologLogger->pushHandler(new StreamHandler('php://stdout')->setFormatter($formatter));
|
$stream = $streamOutput ?? 'php://stdout';
|
||||||
|
$this->monologLogger->pushHandler(new StreamHandler($stream)->setFormatter($formatter));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -192,7 +201,7 @@ class Logger implements LoggerInterface
|
|||||||
*/
|
*/
|
||||||
public function log($level, \Stringable|string $message, array $context = []): void
|
public function log($level, \Stringable|string $message, array $context = []): void
|
||||||
{
|
{
|
||||||
if ($this->levels[$level] > $this->levels[$this->level]) {
|
if (isset($this->levels[$level]) && $this->levels[$level] > $this->levels[$this->level]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,7 +224,7 @@ class Logger implements LoggerInterface
|
|||||||
$this->rpcLogger->error((string)$message, $context);
|
$this->rpcLogger->error((string)$message, $context);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$this->rpcLogger->log((string)$message, $context);
|
$this->rpcLogger->log($level, (string)$message, $context);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
39
src/Services/Facades/RoadRunnerLogger.php
Normal file
39
src/Services/Facades/RoadRunnerLogger.php
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Siteworxpro\App\Services\Facades;
|
||||||
|
|
||||||
|
use Psr\Container\ContainerExceptionInterface;
|
||||||
|
use Psr\Container\NotFoundExceptionInterface;
|
||||||
|
use RoadRunner\Logger\Logger;
|
||||||
|
use Siteworxpro\App\Services\Facade;
|
||||||
|
use Spiral\Goridge\RPC\RPC;
|
||||||
|
|
||||||
|
class RoadRunnerLogger extends Facade
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @throws ContainerExceptionInterface
|
||||||
|
* @throws NotFoundExceptionInterface
|
||||||
|
*/
|
||||||
|
public static function getFacadeRoot(): mixed
|
||||||
|
{
|
||||||
|
$container = static::getFacadeContainer();
|
||||||
|
if ($container && $container->has(Logger::class) === false) {
|
||||||
|
$rpc = RPC::create($_SERVER['RR_RPC']);
|
||||||
|
$logger = new Logger($rpc);
|
||||||
|
$container->bind(static::getFacadeAccessor(), function () use ($logger) {
|
||||||
|
return $logger;
|
||||||
|
});
|
||||||
|
|
||||||
|
return $logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $container->get(Logger::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function getFacadeAccessor(): string
|
||||||
|
{
|
||||||
|
return Logger::class;
|
||||||
|
}
|
||||||
|
}
|
||||||
20
tests/Facades/DispatcherTest.php
Normal file
20
tests/Facades/DispatcherTest.php
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Siteworxpro\Tests\Facades;
|
||||||
|
|
||||||
|
use Siteworxpro\App\Services\Facades\Dispatcher;
|
||||||
|
|
||||||
|
class DispatcherTest extends AbstractFacade
|
||||||
|
{
|
||||||
|
protected function getFacadeClass(): string
|
||||||
|
{
|
||||||
|
return Dispatcher::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getConcrete(): string
|
||||||
|
{
|
||||||
|
return \Siteworxpro\App\Events\Dispatcher::class;
|
||||||
|
}
|
||||||
|
}
|
||||||
20
tests/Facades/LoggerTest.php
Normal file
20
tests/Facades/LoggerTest.php
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Siteworxpro\Tests\Facades;
|
||||||
|
|
||||||
|
use Siteworxpro\App\Services\Facades\Logger;
|
||||||
|
|
||||||
|
class LoggerTest extends AbstractFacade
|
||||||
|
{
|
||||||
|
protected function getFacadeClass(): string
|
||||||
|
{
|
||||||
|
return Logger::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getConcrete(): string
|
||||||
|
{
|
||||||
|
return \Siteworxpro\App\Log\Logger::class;
|
||||||
|
}
|
||||||
|
}
|
||||||
19
tests/Helpers/UlidTest.php
Normal file
19
tests/Helpers/UlidTest.php
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Siteworxpro\Tests\Helpers;
|
||||||
|
|
||||||
|
use Siteworxpro\App\Helpers\Env;
|
||||||
|
use Siteworxpro\App\Helpers\Ulid;
|
||||||
|
use Siteworxpro\Tests\Unit;
|
||||||
|
|
||||||
|
class UlidTest extends Unit
|
||||||
|
{
|
||||||
|
public function testGetString(): void
|
||||||
|
{
|
||||||
|
$ulid = Ulid::generate();
|
||||||
|
$this->assertIsString($ulid);
|
||||||
|
$this->assertEquals(16, strlen($ulid));
|
||||||
|
}
|
||||||
|
}
|
||||||
167
tests/Log/LoggerRpcTest.php
Normal file
167
tests/Log/LoggerRpcTest.php
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Siteworxpro\Tests\Log;
|
||||||
|
|
||||||
|
use Mockery;
|
||||||
|
use Psr\Container\ContainerExceptionInterface;
|
||||||
|
use Psr\Container\NotFoundExceptionInterface;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Psr\Log\LogLevel;
|
||||||
|
use Siteworxpro\App\Log\Logger;
|
||||||
|
use Siteworxpro\Tests\Unit;
|
||||||
|
|
||||||
|
class LoggerRpcTest extends Unit
|
||||||
|
{
|
||||||
|
protected function tearDown(): void
|
||||||
|
{
|
||||||
|
parent::tearDown();
|
||||||
|
unset($_SERVER['RR_RPC']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ContainerExceptionInterface
|
||||||
|
* @throws NotFoundExceptionInterface
|
||||||
|
* @throws \Throwable
|
||||||
|
*/
|
||||||
|
public function testLogsDebugMessageWhenLevelIsDebug(): void
|
||||||
|
{
|
||||||
|
$this->expectNotToPerformAssertions();
|
||||||
|
|
||||||
|
$_SERVER['RR_RPC'] = 'tcp://127.0.0.1:6001';
|
||||||
|
|
||||||
|
$mock = Mockery::mock(LoggerInterface::class);
|
||||||
|
$mock->expects('debug')
|
||||||
|
->with('message', ['key' => 'value'])
|
||||||
|
->once();
|
||||||
|
|
||||||
|
\Siteworxpro\App\Services\Facades\Logger::getFacadeContainer()
|
||||||
|
->bind(\RoadRunner\Logger\Logger::class, function () use ($mock) {
|
||||||
|
return $mock;
|
||||||
|
});
|
||||||
|
|
||||||
|
$inputBuffer = fopen('php://memory', 'r+');
|
||||||
|
$logger = new Logger(LogLevel::DEBUG, $inputBuffer);
|
||||||
|
$logger->debug('message', ['key' => 'value']);
|
||||||
|
|
||||||
|
$mock->shouldHaveReceived('debug');
|
||||||
|
|
||||||
|
Mockery::close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ContainerExceptionInterface
|
||||||
|
* @throws NotFoundExceptionInterface
|
||||||
|
*/
|
||||||
|
public function testLogsDebugMessageWhenLevelIsInfoNotice(): void
|
||||||
|
{
|
||||||
|
$this->expectNotToPerformAssertions();
|
||||||
|
|
||||||
|
$_SERVER['RR_RPC'] = 'tcp://127.0.0.1:6001';
|
||||||
|
|
||||||
|
$mock = Mockery::mock(LoggerInterface::class);
|
||||||
|
$mock->expects('info')
|
||||||
|
->with('message', ['key' => 'value'])
|
||||||
|
->times(2);
|
||||||
|
|
||||||
|
\Siteworxpro\App\Services\Facades\Logger::getFacadeContainer()
|
||||||
|
->bind(\RoadRunner\Logger\Logger::class, function () use ($mock) {
|
||||||
|
return $mock;
|
||||||
|
});
|
||||||
|
|
||||||
|
$inputBuffer = fopen('php://memory', 'r+');
|
||||||
|
$logger = new Logger(LogLevel::DEBUG, $inputBuffer);
|
||||||
|
$logger->info('message', ['key' => 'value']);
|
||||||
|
$logger->notice('message', ['key' => 'value']);
|
||||||
|
|
||||||
|
$mock->shouldHaveReceived('info')->times(2);
|
||||||
|
Mockery::close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ContainerExceptionInterface
|
||||||
|
* @throws NotFoundExceptionInterface
|
||||||
|
*/
|
||||||
|
public function testLogsDebugMessageWhenLevelIsInfoWarning(): void
|
||||||
|
{
|
||||||
|
$this->expectNotToPerformAssertions();
|
||||||
|
|
||||||
|
$_SERVER['RR_RPC'] = 'tcp://127.0.0.1:6001';
|
||||||
|
|
||||||
|
$mock = Mockery::mock(LoggerInterface::class);
|
||||||
|
$mock->expects('warning')
|
||||||
|
->with('message', ['key' => 'value'])
|
||||||
|
->times(1);
|
||||||
|
|
||||||
|
\Siteworxpro\App\Services\Facades\Logger::getFacadeContainer()
|
||||||
|
->bind(\RoadRunner\Logger\Logger::class, function () use ($mock) {
|
||||||
|
return $mock;
|
||||||
|
});
|
||||||
|
|
||||||
|
$inputBuffer = fopen('php://memory', 'r+');
|
||||||
|
$logger = new Logger(LogLevel::DEBUG, $inputBuffer);
|
||||||
|
$logger->warning('message', ['key' => 'value']);
|
||||||
|
|
||||||
|
$mock->shouldHaveReceived('warning');
|
||||||
|
Mockery::close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ContainerExceptionInterface
|
||||||
|
* @throws NotFoundExceptionInterface
|
||||||
|
*/
|
||||||
|
public function testLogsDebugMessageWhenLevelIsInfoError(): void
|
||||||
|
{
|
||||||
|
$this->expectNotToPerformAssertions();
|
||||||
|
|
||||||
|
$_SERVER['RR_RPC'] = 'tcp://127.0.0.1:6001';
|
||||||
|
|
||||||
|
$mock = Mockery::mock(LoggerInterface::class);
|
||||||
|
$mock->expects('error')
|
||||||
|
->with('message', ['key' => 'value'])
|
||||||
|
->times(4);
|
||||||
|
|
||||||
|
\Siteworxpro\App\Services\Facades\Logger::getFacadeContainer()
|
||||||
|
->bind(\RoadRunner\Logger\Logger::class, function () use ($mock) {
|
||||||
|
return $mock;
|
||||||
|
});
|
||||||
|
|
||||||
|
$inputBuffer = fopen('php://memory', 'r+');
|
||||||
|
$logger = new Logger(LogLevel::DEBUG, $inputBuffer);
|
||||||
|
$logger->error('message', ['key' => 'value']);
|
||||||
|
$logger->critical('message', ['key' => 'value']);
|
||||||
|
$logger->alert('message', ['key' => 'value']);
|
||||||
|
$logger->emergency('message', ['key' => 'value']);
|
||||||
|
|
||||||
|
$mock->shouldHaveReceived('error')->times(4);
|
||||||
|
Mockery::close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ContainerExceptionInterface
|
||||||
|
* @throws NotFoundExceptionInterface
|
||||||
|
*/
|
||||||
|
public function testLogsLog(): void
|
||||||
|
{
|
||||||
|
$this->expectNotToPerformAssertions();
|
||||||
|
|
||||||
|
$_SERVER['RR_RPC'] = 'tcp://127.0.0.1:6001';
|
||||||
|
|
||||||
|
$mock = Mockery::mock(LoggerInterface::class);
|
||||||
|
$mock->expects('log')
|
||||||
|
->with('notaloglevel', 'message', ['key' => 'value']);
|
||||||
|
|
||||||
|
\Siteworxpro\App\Services\Facades\Logger::getFacadeContainer()
|
||||||
|
->bind(\RoadRunner\Logger\Logger::class, function () use ($mock) {
|
||||||
|
return $mock;
|
||||||
|
});
|
||||||
|
|
||||||
|
$inputBuffer = fopen('php://memory', 'r+');
|
||||||
|
$logger = new Logger(LogLevel::DEBUG, $inputBuffer);
|
||||||
|
$logger->log('notaloglevel', 'message', ['key' => 'value']);
|
||||||
|
|
||||||
|
$mock->shouldHaveReceived('log')->times(1);
|
||||||
|
Mockery::close();
|
||||||
|
}
|
||||||
|
}
|
||||||
155
tests/Log/LoggerTest.php
Normal file
155
tests/Log/LoggerTest.php
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Siteworxpro\Tests\Log;
|
||||||
|
|
||||||
|
use Psr\Log\LogLevel;
|
||||||
|
use Siteworxpro\App\Log\Logger;
|
||||||
|
use Siteworxpro\Tests\Unit;
|
||||||
|
|
||||||
|
class LoggerTest extends Unit
|
||||||
|
{
|
||||||
|
private function getLoggerWithBuffer(string $logLevel): array
|
||||||
|
{
|
||||||
|
$inputBuffer = fopen('php://memory', 'r+');
|
||||||
|
return [new Logger($logLevel, $inputBuffer), $inputBuffer];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getContents($inputBuffer): string
|
||||||
|
{
|
||||||
|
return stream_get_contents($inputBuffer, -1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function testLogLevel(string $level): void
|
||||||
|
{
|
||||||
|
[$logger, $inputBuffer] = $this->getLoggerWithBuffer($level);
|
||||||
|
$logger->$level('message', ['key' => 'value']);
|
||||||
|
$output = $this->getContents($inputBuffer);
|
||||||
|
|
||||||
|
$this->assertNotEmpty($output);
|
||||||
|
$decoded = json_decode($output, true);
|
||||||
|
$this->assertEquals('message', $decoded['message']);
|
||||||
|
$this->assertEquals('value', $decoded['context']['key']);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function testLogLevelEmpty(string $configLevel, string $logLevel): void
|
||||||
|
{
|
||||||
|
[$logger, $inputBuffer] = $this->getLoggerWithBuffer($configLevel);
|
||||||
|
$logger->$logLevel('message', ['key' => 'value']);
|
||||||
|
$output = $this->getContents($inputBuffer);
|
||||||
|
|
||||||
|
$this->assertEmpty($output);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLogsDebugMessageWhenLevelIsDebug(): void
|
||||||
|
{
|
||||||
|
$this->testLogLevel(LogLevel::DEBUG);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLogsInfoMessageWhenLevelIsInfo(): void
|
||||||
|
{
|
||||||
|
$this->testLogLevel(LogLevel::INFO);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLogsWarningMessageWhenLevelIsWarning(): void
|
||||||
|
{
|
||||||
|
$this->testLogLevel(LogLevel::WARNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLogsErrorMessageWhenLevelIsError(): void
|
||||||
|
{
|
||||||
|
$this->testLogLevel(LogLevel::ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLogsCriticalMessageWhenLevelIsCritical(): void
|
||||||
|
{
|
||||||
|
$this->testLogLevel(LogLevel::CRITICAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLogsAlertMessageWhenLevelIsAlert(): void
|
||||||
|
{
|
||||||
|
$this->testLogLevel(LogLevel::ALERT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLogsEmergencyMessageWhenLevelIsEmergency(): void
|
||||||
|
{
|
||||||
|
$this->testLogLevel(LogLevel::EMERGENCY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLogsNoticeMessageWhenLevelIsNotice(): void
|
||||||
|
{
|
||||||
|
$this->testLogLevel(LogLevel::NOTICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDoesNotLogWhenMinimumLevelIsInfo(): void
|
||||||
|
{
|
||||||
|
$this->testLogLevelEmpty(LogLevel::INFO, LogLevel::DEBUG);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDoesNotLogWhenMinimumLevelIsWarning(): void
|
||||||
|
{
|
||||||
|
$this->testLogLevelEmpty(LogLevel::WARNING, LogLevel::INFO);
|
||||||
|
$this->testLogLevelEmpty(LogLevel::WARNING, LogLevel::DEBUG);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDoesNotLogWhenMinimumLevelIsError(): void
|
||||||
|
{
|
||||||
|
$this->testLogLevelEmpty(LogLevel::ERROR, LogLevel::DEBUG);
|
||||||
|
$this->testLogLevelEmpty(LogLevel::ERROR, LogLevel::INFO);
|
||||||
|
$this->testLogLevelEmpty(LogLevel::ERROR, LogLevel::WARNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDoesNotLogWhenMinimumLevelIsNotice(): void
|
||||||
|
{
|
||||||
|
$this->testLogLevelEmpty(LogLevel::NOTICE, LogLevel::DEBUG);
|
||||||
|
$this->testLogLevelEmpty(LogLevel::NOTICE, LogLevel::INFO);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLogsMessageWithEmptyContext(): void
|
||||||
|
{
|
||||||
|
[$logger, $buffer] = $this->getLoggerWithBuffer(LogLevel::INFO);
|
||||||
|
|
||||||
|
$logger->info('Message without context');
|
||||||
|
$output = $this->getContents($buffer);
|
||||||
|
|
||||||
|
$this->assertNotEmpty($output);
|
||||||
|
$decoded = json_decode($output, true);
|
||||||
|
$this->assertEquals('Message without context', $decoded['message']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLogsMessageWithComplexContext(): void
|
||||||
|
{
|
||||||
|
[$logger, $buffer] = $this->getLoggerWithBuffer(LogLevel::INFO);
|
||||||
|
|
||||||
|
$logger->info('Complex context', [
|
||||||
|
'user_id' => 123,
|
||||||
|
'nested' => ['key' => 'value'],
|
||||||
|
'array' => [1, 2, 3]
|
||||||
|
]);
|
||||||
|
$output = $this->getContents($buffer);
|
||||||
|
|
||||||
|
$this->assertNotEmpty($output);
|
||||||
|
$decoded = json_decode($output, true);
|
||||||
|
$this->assertEquals(123, $decoded['context']['user_id']);
|
||||||
|
$this->assertEquals('value', $decoded['context']['nested']['key']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLogsStringableMessage(): void
|
||||||
|
{
|
||||||
|
[$logger, $buffer] = $this->getLoggerWithBuffer(LogLevel::INFO);
|
||||||
|
|
||||||
|
$stringable = new class implements \Stringable {
|
||||||
|
public function __toString(): string
|
||||||
|
{
|
||||||
|
return 'Stringable message';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$logger->info($stringable);
|
||||||
|
$output = $this->getContents($buffer);
|
||||||
|
$this->assertNotEmpty($output);
|
||||||
|
$decoded = json_decode($output, true);
|
||||||
|
$this->assertEquals('Stringable message', $decoded['message']);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user