/
home
/
sjslayjy
/
public_html
/
theweavenest
/
vendor
/
monolog
/
monolog
/
tests
/
Monolog
/
Upload File
HOME
<?php declare(strict_types=1); /* * This file is part of the Monolog package. * * (c) Jordi Boggiano <j.boggiano@seld.be> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Monolog; use Monolog\Handler\HandlerInterface; use Monolog\Processor\WebProcessor; use Monolog\Handler\TestHandler; class LoggerTest extends \PHPUnit\Framework\TestCase { /** * @covers Monolog\Logger::getName */ public function testGetName() { $logger = new Logger('foo'); $this->assertEquals('foo', $logger->getName()); } /** * @covers Monolog\Logger::getLevelName */ public function testGetLevelName() { $this->assertEquals('ERROR', Logger::getLevelName(Logger::ERROR)); } /** * @covers Monolog\Logger::withName */ public function testWithName() { $first = new Logger('first', [$handler = new TestHandler()]); $second = $first->withName('second'); $this->assertSame('first', $first->getName()); $this->assertSame('second', $second->getName()); $this->assertSame($handler, $second->popHandler()); } /** * @covers Monolog\Logger::toMonologLevel */ public function testConvertPSR3ToMonologLevel() { $this->assertEquals(Logger::toMonologLevel('debug'), 100); $this->assertEquals(Logger::toMonologLevel('info'), 200); $this->assertEquals(Logger::toMonologLevel('notice'), 250); $this->assertEquals(Logger::toMonologLevel('warning'), 300); $this->assertEquals(Logger::toMonologLevel('error'), 400); $this->assertEquals(Logger::toMonologLevel('critical'), 500); $this->assertEquals(Logger::toMonologLevel('alert'), 550); $this->assertEquals(Logger::toMonologLevel('emergency'), 600); } /** * @covers Monolog\Logger::addRecord * @covers Monolog\Logger::log */ public function testConvertRFC5424ToMonologLevelInAddRecordAndLog() { $logger = new Logger('test'); $handler = new TestHandler; $logger->pushHandler($handler); foreach ([ 7 => 100, 6 => 200, 5 => 250, 4 => 300, 3 => 400, 2 => 500, 1 => 550, 0 => 600, ] as $rfc5424Level => $monologLevel) { $handler->reset(); $logger->addRecord($rfc5424Level, 'test'); $logger->log($rfc5424Level, 'test'); $records = $handler->getRecords(); self::assertCount(2, $records); self::assertSame($monologLevel, $records[0]['level']); self::assertSame($monologLevel, $records[1]['level']); } } /** * @covers Monolog\Logger::getLevelName */ public function testGetLevelNameThrows() { $this->expectException(\InvalidArgumentException::class); Logger::getLevelName(5); } /** * @covers Monolog\Logger::__construct */ public function testChannel() { $logger = new Logger('foo'); $handler = new TestHandler; $logger->pushHandler($handler); $logger->warning('test'); list($record) = $handler->getRecords(); $this->assertEquals('foo', $record['channel']); } /** * @covers Monolog\Logger::addRecord */ public function testLogPreventsCircularLogging() { $logger = new Logger(__METHOD__); $loggingHandler = new LoggingHandler($logger); $testHandler = new TestHandler(); $logger->pushHandler($loggingHandler); $logger->pushHandler($testHandler); $logger->addRecord(Logger::ALERT, 'test'); $records = $testHandler->getRecords(); $this->assertCount(3, $records); $this->assertSame('ALERT', $records[0]['level_name']); $this->assertSame('DEBUG', $records[1]['level_name']); $this->assertSame('WARNING', $records[2]['level_name']); } /** * @covers Monolog\Logger::addRecord */ public function testLog() { $logger = new Logger(__METHOD__); $handler = $this->prophesize('Monolog\Handler\NullHandler'); $handler->handle(\Prophecy\Argument::any())->shouldBeCalled(); $handler->isHandling(['level' => 300])->willReturn(true); $logger->pushHandler($handler->reveal()); $this->assertTrue($logger->addRecord(Logger::WARNING, 'test')); } /** * @covers Monolog\Logger::addRecord */ public function testLogNotHandled() { $logger = new Logger(__METHOD__); $handler = $this->prophesize('Monolog\Handler\NullHandler'); $handler->handle()->shouldNotBeCalled(); $handler->isHandling(['level' => 300])->willReturn(false); $logger->pushHandler($handler->reveal()); $this->assertFalse($logger->addRecord(Logger::WARNING, 'test')); } public function testHandlersInCtor() { $handler1 = new TestHandler; $handler2 = new TestHandler; $logger = new Logger(__METHOD__, [$handler1, $handler2]); $this->assertEquals($handler1, $logger->popHandler()); $this->assertEquals($handler2, $logger->popHandler()); } public function testProcessorsInCtor() { $processor1 = new WebProcessor; $processor2 = new WebProcessor; $logger = new Logger(__METHOD__, [], [$processor1, $processor2]); $this->assertEquals($processor1, $logger->popProcessor()); $this->assertEquals($processor2, $logger->popProcessor()); } /** * @covers Monolog\Logger::pushHandler * @covers Monolog\Logger::popHandler */ public function testPushPopHandler() { $logger = new Logger(__METHOD__); $handler1 = new TestHandler; $handler2 = new TestHandler; $logger->pushHandler($handler1); $logger->pushHandler($handler2); $this->assertEquals($handler2, $logger->popHandler()); $this->assertEquals($handler1, $logger->popHandler()); $this->expectException(\LogicException::class); $logger->popHandler(); } /** * @covers Monolog\Logger::setHandlers */ public function testSetHandlers() { $logger = new Logger(__METHOD__); $handler1 = new TestHandler; $handler2 = new TestHandler; $logger->pushHandler($handler1); $logger->setHandlers([$handler2]); // handler1 has been removed $this->assertEquals([$handler2], $logger->getHandlers()); $logger->setHandlers([ "AMapKey" => $handler1, "Woop" => $handler2, ]); // Keys have been scrubbed $this->assertEquals([$handler1, $handler2], $logger->getHandlers()); } /** * @covers Monolog\Logger::pushProcessor * @covers Monolog\Logger::popProcessor */ public function testPushPopProcessor() { $logger = new Logger(__METHOD__); $processor1 = new WebProcessor; $processor2 = new WebProcessor; $logger->pushProcessor($processor1); $logger->pushProcessor($processor2); $this->assertEquals($processor2, $logger->popProcessor()); $this->assertEquals($processor1, $logger->popProcessor()); $this->expectException(\LogicException::class); $logger->popProcessor(); } /** * @covers Monolog\Logger::addRecord */ public function testProcessorsAreExecuted() { $logger = new Logger(__METHOD__); $handler = new TestHandler; $logger->pushHandler($handler); $logger->pushProcessor(function ($record) { $record['extra']['win'] = true; return $record; }); $logger->error('test'); list($record) = $handler->getRecords(); $this->assertTrue($record['extra']['win']); } /** * @covers Monolog\Logger::addRecord */ public function testProcessorsAreCalledOnlyOnce() { $logger = new Logger(__METHOD__); $handler = $this->createMock('Monolog\Handler\HandlerInterface'); $handler->expects($this->any()) ->method('isHandling') ->will($this->returnValue(true)) ; $handler->expects($this->any()) ->method('handle') ->will($this->returnValue(true)) ; $logger->pushHandler($handler); $processor = $this->getMockBuilder('Monolog\Processor\WebProcessor') ->disableOriginalConstructor() ->onlyMethods(['__invoke']) ->getMock() ; $processor->expects($this->once()) ->method('__invoke') ->will($this->returnArgument(0)) ; $logger->pushProcessor($processor); $logger->error('test'); } /** * @covers Monolog\Logger::addRecord */ public function testProcessorsNotCalledWhenNotHandled() { $logger = new Logger(__METHOD__); $handler = $this->createMock('Monolog\Handler\HandlerInterface'); $handler->expects($this->once()) ->method('isHandling') ->will($this->returnValue(false)) ; $logger->pushHandler($handler); $that = $this; $logger->pushProcessor(function ($record) use ($that) { $that->fail('The processor should not be called'); }); $logger->alert('test'); } /** * @covers Monolog\Logger::addRecord */ public function testHandlersNotCalledBeforeFirstHandling() { $logger = new Logger(__METHOD__); $handler1 = $this->createMock('Monolog\Handler\HandlerInterface'); $handler1->expects($this->never()) ->method('isHandling') ->will($this->returnValue(false)) ; $handler1->expects($this->once()) ->method('handle') ->will($this->returnValue(false)) ; $logger->pushHandler($handler1); $handler2 = $this->createMock('Monolog\Handler\HandlerInterface'); $handler2->expects($this->once()) ->method('isHandling') ->will($this->returnValue(true)) ; $handler2->expects($this->once()) ->method('handle') ->will($this->returnValue(false)) ; $logger->pushHandler($handler2); $handler3 = $this->createMock('Monolog\Handler\HandlerInterface'); $handler3->expects($this->once()) ->method('isHandling') ->will($this->returnValue(false)) ; $handler3->expects($this->never()) ->method('handle') ; $logger->pushHandler($handler3); $logger->debug('test'); } /** * @covers Monolog\Logger::addRecord */ public function testHandlersNotCalledBeforeFirstHandlingWithAssocArray() { $handler1 = $this->createMock('Monolog\Handler\HandlerInterface'); $handler1->expects($this->never()) ->method('isHandling') ->will($this->returnValue(false)) ; $handler1->expects($this->once()) ->method('handle') ->will($this->returnValue(false)) ; $handler2 = $this->createMock('Monolog\Handler\HandlerInterface'); $handler2->expects($this->once()) ->method('isHandling') ->will($this->returnValue(true)) ; $handler2->expects($this->once()) ->method('handle') ->will($this->returnValue(false)) ; $handler3 = $this->createMock('Monolog\Handler\HandlerInterface'); $handler3->expects($this->once()) ->method('isHandling') ->will($this->returnValue(false)) ; $handler3->expects($this->never()) ->method('handle') ; $logger = new Logger(__METHOD__, ['last' => $handler3, 'second' => $handler2, 'first' => $handler1]); $logger->debug('test'); } /** * @covers Monolog\Logger::addRecord */ public function testBubblingWhenTheHandlerReturnsFalse() { $logger = new Logger(__METHOD__); $handler1 = $this->createMock('Monolog\Handler\HandlerInterface'); $handler1->expects($this->any()) ->method('isHandling') ->will($this->returnValue(true)) ; $handler1->expects($this->once()) ->method('handle') ->will($this->returnValue(false)) ; $logger->pushHandler($handler1); $handler2 = $this->createMock('Monolog\Handler\HandlerInterface'); $handler2->expects($this->any()) ->method('isHandling') ->will($this->returnValue(true)) ; $handler2->expects($this->once()) ->method('handle') ->will($this->returnValue(false)) ; $logger->pushHandler($handler2); $logger->debug('test'); } /** * @covers Monolog\Logger::addRecord */ public function testNotBubblingWhenTheHandlerReturnsTrue() { $logger = new Logger(__METHOD__); $handler1 = $this->createMock('Monolog\Handler\HandlerInterface'); $handler1->expects($this->any()) ->method('isHandling') ->will($this->returnValue(true)) ; $handler1->expects($this->never()) ->method('handle') ; $logger->pushHandler($handler1); $handler2 = $this->createMock('Monolog\Handler\HandlerInterface'); $handler2->expects($this->any()) ->method('isHandling') ->will($this->returnValue(true)) ; $handler2->expects($this->once()) ->method('handle') ->will($this->returnValue(true)) ; $logger->pushHandler($handler2); $logger->debug('test'); } /** * @covers Monolog\Logger::isHandling */ public function testIsHandling() { $logger = new Logger(__METHOD__); $handler1 = $this->createMock('Monolog\Handler\HandlerInterface'); $handler1->expects($this->any()) ->method('isHandling') ->will($this->returnValue(false)) ; $logger->pushHandler($handler1); $this->assertFalse($logger->isHandling(Logger::DEBUG)); $handler2 = $this->createMock('Monolog\Handler\HandlerInterface'); $handler2->expects($this->any()) ->method('isHandling') ->will($this->returnValue(true)) ; $logger->pushHandler($handler2); $this->assertTrue($logger->isHandling(Logger::DEBUG)); } /** * @dataProvider logMethodProvider * @covers Monolog\Logger::debug * @covers Monolog\Logger::info * @covers Monolog\Logger::notice * @covers Monolog\Logger::warning * @covers Monolog\Logger::error * @covers Monolog\Logger::critical * @covers Monolog\Logger::alert * @covers Monolog\Logger::emergency */ public function testLogMethods($method, $expectedLevel) { $logger = new Logger('foo'); $handler = new TestHandler; $logger->pushHandler($handler); $logger->{$method}('test'); list($record) = $handler->getRecords(); $this->assertEquals($expectedLevel, $record['level']); } public function logMethodProvider() { return [ // PSR-3 methods ['debug', Logger::DEBUG], ['info', Logger::INFO], ['notice', Logger::NOTICE], ['warning', Logger::WARNING], ['error', Logger::ERROR], ['critical', Logger::CRITICAL], ['alert', Logger::ALERT], ['emergency', Logger::EMERGENCY], ]; } /** * @dataProvider setTimezoneProvider * @covers Monolog\Logger::setTimezone */ public function testSetTimezone($tz) { $logger = new Logger('foo'); $logger->setTimezone($tz); $handler = new TestHandler; $logger->pushHandler($handler); $logger->info('test'); list($record) = $handler->getRecords(); $this->assertEquals($tz, $record['datetime']->getTimezone()); } public function setTimezoneProvider() { return array_map( function ($tz) { return [new \DateTimeZone($tz)]; }, \DateTimeZone::listIdentifiers() ); } /** * @covers Monolog\Logger::setTimezone * @covers Monolog\DateTimeImmutable::__construct */ public function testTimezoneIsRespectedInUTC() { foreach ([true, false] as $microseconds) { $logger = new Logger('foo'); $logger->useMicrosecondTimestamps($microseconds); $tz = new \DateTimeZone('America/New_York'); $logger->setTimezone($tz); $handler = new TestHandler; $logger->pushHandler($handler); $dt = new \DateTime('now', $tz); $logger->info('test'); list($record) = $handler->getRecords(); $this->assertEquals($tz, $record['datetime']->getTimezone()); $this->assertEquals($dt->format('Y/m/d H:i'), $record['datetime']->format('Y/m/d H:i'), 'Time should match timezone with microseconds set to: '.var_export($microseconds, true)); } } /** * @covers Monolog\Logger::setTimezone * @covers Monolog\DateTimeImmutable::__construct */ public function testTimezoneIsRespectedInOtherTimezone() { date_default_timezone_set('CET'); foreach ([true, false] as $microseconds) { $logger = new Logger('foo'); $logger->useMicrosecondTimestamps($microseconds); $tz = new \DateTimeZone('America/New_York'); $logger->setTimezone($tz); $handler = new TestHandler; $logger->pushHandler($handler); $dt = new \DateTime('now', $tz); $logger->info('test'); list($record) = $handler->getRecords(); $this->assertEquals($tz, $record['datetime']->getTimezone()); $this->assertEquals($dt->format('Y/m/d H:i'), $record['datetime']->format('Y/m/d H:i'), 'Time should match timezone with microseconds set to: '.var_export($microseconds, true)); } } public function tearDown(): void { date_default_timezone_set('UTC'); } /** * @dataProvider useMicrosecondTimestampsProvider * @covers Monolog\Logger::useMicrosecondTimestamps * @covers Monolog\Logger::addRecord */ public function testUseMicrosecondTimestamps($micro, $assert, $assertFormat) { if (PHP_VERSION_ID === 70103) { $this->markTestSkipped(); } $logger = new Logger('foo'); $logger->useMicrosecondTimestamps($micro); $handler = new TestHandler; $logger->pushHandler($handler); $logger->info('test'); list($record) = $handler->getRecords(); $this->{$assert}('000000', $record['datetime']->format('u')); $this->assertSame($record['datetime']->format($assertFormat), (string) $record['datetime']); } public function useMicrosecondTimestampsProvider() { return [ // this has a very small chance of a false negative (1/10^6) 'with microseconds' => [true, 'assertNotSame', 'Y-m-d\TH:i:s.uP'], // php 7.1 always includes microseconds, so we keep them in, but we format the datetime without 'without microseconds' => [false, 'assertNotSame', 'Y-m-d\TH:i:sP'], ]; } /** * @covers Monolog\Logger::setExceptionHandler */ public function testSetExceptionHandler() { $logger = new Logger(__METHOD__); $this->assertNull($logger->getExceptionHandler()); $callback = function ($ex) { }; $logger->setExceptionHandler($callback); $this->assertEquals($callback, $logger->getExceptionHandler()); } /** * @covers Monolog\Logger::handleException */ public function testDefaultHandleException() { $logger = new Logger(__METHOD__); $handler = $this->getMockBuilder('Monolog\Handler\HandlerInterface')->getMock(); $handler->expects($this->any()) ->method('isHandling') ->will($this->returnValue(true)) ; $handler->expects($this->any()) ->method('handle') ->will($this->throwException(new \Exception('Some handler exception'))) ; $this->expectException(\Exception::class); $logger->pushHandler($handler); $logger->info('test'); } /** * @covers Monolog\Logger::handleException * @covers Monolog\Logger::addRecord */ public function testCustomHandleException() { $logger = new Logger(__METHOD__); $that = $this; $logger->setExceptionHandler(function ($e, $record) use ($that) { $that->assertEquals($e->getMessage(), 'Some handler exception'); $that->assertTrue(is_array($record)); $that->assertEquals($record['message'], 'test'); }); $handler = $this->getMockBuilder('Monolog\Handler\HandlerInterface')->getMock(); $handler->expects($this->any()) ->method('isHandling') ->will($this->returnValue(true)) ; $handler->expects($this->any()) ->method('handle') ->will($this->throwException(new \Exception('Some handler exception'))) ; $logger->pushHandler($handler); $logger->info('test'); } public function testSerializable() { $logger = new Logger(__METHOD__); $copy = unserialize(serialize($logger)); self::assertInstanceOf(Logger::class, $copy); self::assertSame($logger->getName(), $copy->getName()); self::assertSame($logger->getTimezone()->getName(), $copy->getTimezone()->getName()); self::assertSame($logger->getHandlers(), $copy->getHandlers()); } public function testReset() { $logger = new Logger('app'); $testHandler = new Handler\TestHandler(); $testHandler->setSkipReset(true); $bufferHandler = new Handler\BufferHandler($testHandler); $groupHandler = new Handler\GroupHandler(array($bufferHandler)); $fingersCrossedHandler = new Handler\FingersCrossedHandler($groupHandler); $logger->pushHandler($fingersCrossedHandler); $processorUid1 = new Processor\UidProcessor(10); $uid1 = $processorUid1->getUid(); $groupHandler->pushProcessor($processorUid1); $processorUid2 = new Processor\UidProcessor(5); $uid2 = $processorUid2->getUid(); $logger->pushProcessor($processorUid2); $getProperty = function ($object, $property) { $reflectionProperty = new \ReflectionProperty(get_class($object), $property); $reflectionProperty->setAccessible(true); return $reflectionProperty->getValue($object); }; $that = $this; $assertBufferOfBufferHandlerEmpty = function () use ($getProperty, $bufferHandler, $that) { $that->assertEmpty($getProperty($bufferHandler, 'buffer')); }; $assertBuffersEmpty = function () use ($assertBufferOfBufferHandlerEmpty, $getProperty, $fingersCrossedHandler, $that) { $assertBufferOfBufferHandlerEmpty(); $that->assertEmpty($getProperty($fingersCrossedHandler, 'buffer')); }; $logger->debug('debug1'); $logger->reset(); $assertBuffersEmpty(); $this->assertFalse($testHandler->hasDebugRecords()); $this->assertFalse($testHandler->hasErrorRecords()); $this->assertNotSame($uid1, $uid1 = $processorUid1->getUid()); $this->assertNotSame($uid2, $uid2 = $processorUid2->getUid()); $logger->debug('debug2'); $logger->error('error2'); $logger->reset(); $assertBuffersEmpty(); $this->assertTrue($testHandler->hasRecordThatContains('debug2', Logger::DEBUG)); $this->assertTrue($testHandler->hasRecordThatContains('error2', Logger::ERROR)); $this->assertNotSame($uid1, $uid1 = $processorUid1->getUid()); $this->assertNotSame($uid2, $uid2 = $processorUid2->getUid()); $logger->info('info3'); $this->assertNotEmpty($getProperty($fingersCrossedHandler, 'buffer')); $assertBufferOfBufferHandlerEmpty(); $this->assertFalse($testHandler->hasInfoRecords()); $logger->reset(); $assertBuffersEmpty(); $this->assertFalse($testHandler->hasInfoRecords()); $this->assertNotSame($uid1, $uid1 = $processorUid1->getUid()); $this->assertNotSame($uid2, $uid2 = $processorUid2->getUid()); $logger->notice('notice4'); $logger->emergency('emergency4'); $logger->reset(); $assertBuffersEmpty(); $this->assertFalse($testHandler->hasInfoRecords()); $this->assertTrue($testHandler->hasRecordThatContains('notice4', Logger::NOTICE)); $this->assertTrue($testHandler->hasRecordThatContains('emergency4', Logger::EMERGENCY)); $this->assertNotSame($uid1, $processorUid1->getUid()); $this->assertNotSame($uid2, $processorUid2->getUid()); } /** * @covers Logger::addRecord */ public function testLogWithDateTime() { foreach ([true, false] as $microseconds) { $logger = new Logger(__METHOD__); $loggingHandler = new LoggingHandler($logger); $testHandler = new TestHandler(); $logger->pushHandler($loggingHandler); $logger->pushHandler($testHandler); $datetime = (new DateTimeImmutable($microseconds))->modify('2022-03-04 05:06:07'); $logger->addRecord(Logger::DEBUG, 'test', [], $datetime); list($record) = $testHandler->getRecords(); $this->assertEquals($datetime->format('Y-m-d H:i:s'), $record['datetime']->format('Y-m-d H:i:s')); } } /** * @requires PHP 8.1 */ public function testLogCycleDetectionWithFibersWithoutCycle() { $logger = new Logger(__METHOD__); $fiberSuspendHandler = new FiberSuspendHandler(); $testHandler = new TestHandler(); $logger->pushHandler($fiberSuspendHandler); $logger->pushHandler($testHandler); $fibers = []; for ($i = 0; $i < 10; $i++) { $fiber = new \Fiber(static function () use ($logger) { $logger->info('test'); }); $fiber->start(); // We need to keep a reference here, because otherwise the fiber gets automatically cleaned up $fibers[] = $fiber; } self::assertCount(10, $testHandler->getRecords()); } /** * @requires PHP 8.1 */ public function testLogCycleDetectionWithFibersWithCycle() { $logger = new Logger(__METHOD__); $fiberSuspendHandler = new FiberSuspendHandler(); $loggingHandler = new LoggingHandler($logger); $testHandler = new TestHandler(); $logger->pushHandler($fiberSuspendHandler); $logger->pushHandler($loggingHandler); $logger->pushHandler($testHandler); $fiber = new \Fiber(static function () use ($logger) { $logger->info('test'); }); $fiber->start(); self::assertCount(3, $testHandler->getRecords()); } } class LoggingHandler implements HandlerInterface { /** * @var Logger */ private $logger; public function __construct(Logger $logger) { $this->logger = $logger; } public function isHandling(array $record): bool { return true; } public function handle(array $record): bool { $this->logger->debug('Log triggered while logging'); return false; } public function handleBatch(array $records): void { } public function close(): void { } } class FiberSuspendHandler implements HandlerInterface { public function isHandling(array $record): bool { return true; } public function handle(array $record): bool { \Fiber::suspend(); return true; } public function handleBatch(array $records): void { } public function close(): void { } }