LoggerTest.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797
  1. <?php declare(strict_types=1);
  2. /*
  3. * This file is part of the Monolog package.
  4. *
  5. * (c) Jordi Boggiano <j.boggiano@seld.be>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Monolog;
  11. use Monolog\Handler\HandlerInterface;
  12. use Monolog\Processor\WebProcessor;
  13. use Monolog\Handler\TestHandler;
  14. class LoggerTest extends \PHPUnit\Framework\TestCase
  15. {
  16. /**
  17. * @covers Monolog\Logger::getName
  18. */
  19. public function testGetName()
  20. {
  21. $logger = new Logger('foo');
  22. $this->assertEquals('foo', $logger->getName());
  23. }
  24. /**
  25. * @covers Monolog\Logger::getLevelName
  26. */
  27. public function testGetLevelName()
  28. {
  29. $this->assertEquals('ERROR', Logger::getLevelName(Logger::ERROR));
  30. }
  31. /**
  32. * @covers Monolog\Logger::withName
  33. */
  34. public function testWithName()
  35. {
  36. $first = new Logger('first', [$handler = new TestHandler()]);
  37. $second = $first->withName('second');
  38. $this->assertSame('first', $first->getName());
  39. $this->assertSame('second', $second->getName());
  40. $this->assertSame($handler, $second->popHandler());
  41. }
  42. /**
  43. * @covers Monolog\Logger::toMonologLevel
  44. */
  45. public function testConvertPSR3ToMonologLevel()
  46. {
  47. $this->assertEquals(Logger::toMonologLevel('debug'), 100);
  48. $this->assertEquals(Logger::toMonologLevel('info'), 200);
  49. $this->assertEquals(Logger::toMonologLevel('notice'), 250);
  50. $this->assertEquals(Logger::toMonologLevel('warning'), 300);
  51. $this->assertEquals(Logger::toMonologLevel('error'), 400);
  52. $this->assertEquals(Logger::toMonologLevel('critical'), 500);
  53. $this->assertEquals(Logger::toMonologLevel('alert'), 550);
  54. $this->assertEquals(Logger::toMonologLevel('emergency'), 600);
  55. }
  56. /**
  57. * @covers Monolog\Logger::getLevelName
  58. */
  59. public function testGetLevelNameThrows()
  60. {
  61. $this->expectException(\InvalidArgumentException::class);
  62. Logger::getLevelName(5);
  63. }
  64. /**
  65. * @covers Monolog\Logger::__construct
  66. */
  67. public function testChannel()
  68. {
  69. $logger = new Logger('foo');
  70. $handler = new TestHandler;
  71. $logger->pushHandler($handler);
  72. $logger->warning('test');
  73. list($record) = $handler->getRecords();
  74. $this->assertEquals('foo', $record['channel']);
  75. }
  76. /**
  77. * @covers Monolog\Logger::addRecord
  78. */
  79. public function testLogPreventsCircularLogging()
  80. {
  81. $logger = new Logger(__METHOD__);
  82. $loggingHandler = new LoggingHandler($logger);
  83. $testHandler = new TestHandler();
  84. $logger->pushHandler($loggingHandler);
  85. $logger->pushHandler($testHandler);
  86. $logger->addRecord(Logger::ALERT, 'test');
  87. $records = $testHandler->getRecords();
  88. $this->assertCount(3, $records);
  89. $this->assertSame('ALERT', $records[0]['level_name']);
  90. $this->assertSame('DEBUG', $records[1]['level_name']);
  91. $this->assertSame('WARNING', $records[2]['level_name']);
  92. }
  93. /**
  94. * @covers Monolog\Logger::addRecord
  95. */
  96. public function testLog()
  97. {
  98. $logger = new Logger(__METHOD__);
  99. $handler = $this->prophesize('Monolog\Handler\NullHandler');
  100. $handler->handle(\Prophecy\Argument::any())->shouldBeCalled();
  101. $handler->isHandling(['level' => 300])->willReturn(true);
  102. $logger->pushHandler($handler->reveal());
  103. $this->assertTrue($logger->addRecord(Logger::WARNING, 'test'));
  104. }
  105. /**
  106. * @covers Monolog\Logger::addRecord
  107. */
  108. public function testLogNotHandled()
  109. {
  110. $logger = new Logger(__METHOD__);
  111. $handler = $this->prophesize('Monolog\Handler\NullHandler');
  112. $handler->handle()->shouldNotBeCalled();
  113. $handler->isHandling(['level' => 300])->willReturn(false);
  114. $logger->pushHandler($handler->reveal());
  115. $this->assertFalse($logger->addRecord(Logger::WARNING, 'test'));
  116. }
  117. public function testHandlersInCtor()
  118. {
  119. $handler1 = new TestHandler;
  120. $handler2 = new TestHandler;
  121. $logger = new Logger(__METHOD__, [$handler1, $handler2]);
  122. $this->assertEquals($handler1, $logger->popHandler());
  123. $this->assertEquals($handler2, $logger->popHandler());
  124. }
  125. public function testProcessorsInCtor()
  126. {
  127. $processor1 = new WebProcessor;
  128. $processor2 = new WebProcessor;
  129. $logger = new Logger(__METHOD__, [], [$processor1, $processor2]);
  130. $this->assertEquals($processor1, $logger->popProcessor());
  131. $this->assertEquals($processor2, $logger->popProcessor());
  132. }
  133. /**
  134. * @covers Monolog\Logger::pushHandler
  135. * @covers Monolog\Logger::popHandler
  136. */
  137. public function testPushPopHandler()
  138. {
  139. $logger = new Logger(__METHOD__);
  140. $handler1 = new TestHandler;
  141. $handler2 = new TestHandler;
  142. $logger->pushHandler($handler1);
  143. $logger->pushHandler($handler2);
  144. $this->assertEquals($handler2, $logger->popHandler());
  145. $this->assertEquals($handler1, $logger->popHandler());
  146. $this->expectException(\LogicException::class);
  147. $logger->popHandler();
  148. }
  149. /**
  150. * @covers Monolog\Logger::setHandlers
  151. */
  152. public function testSetHandlers()
  153. {
  154. $logger = new Logger(__METHOD__);
  155. $handler1 = new TestHandler;
  156. $handler2 = new TestHandler;
  157. $logger->pushHandler($handler1);
  158. $logger->setHandlers([$handler2]);
  159. // handler1 has been removed
  160. $this->assertEquals([$handler2], $logger->getHandlers());
  161. $logger->setHandlers([
  162. "AMapKey" => $handler1,
  163. "Woop" => $handler2,
  164. ]);
  165. // Keys have been scrubbed
  166. $this->assertEquals([$handler1, $handler2], $logger->getHandlers());
  167. }
  168. /**
  169. * @covers Monolog\Logger::pushProcessor
  170. * @covers Monolog\Logger::popProcessor
  171. */
  172. public function testPushPopProcessor()
  173. {
  174. $logger = new Logger(__METHOD__);
  175. $processor1 = new WebProcessor;
  176. $processor2 = new WebProcessor;
  177. $logger->pushProcessor($processor1);
  178. $logger->pushProcessor($processor2);
  179. $this->assertEquals($processor2, $logger->popProcessor());
  180. $this->assertEquals($processor1, $logger->popProcessor());
  181. $this->expectException(\LogicException::class);
  182. $logger->popProcessor();
  183. }
  184. /**
  185. * @covers Monolog\Logger::addRecord
  186. */
  187. public function testProcessorsAreExecuted()
  188. {
  189. $logger = new Logger(__METHOD__);
  190. $handler = new TestHandler;
  191. $logger->pushHandler($handler);
  192. $logger->pushProcessor(function ($record) {
  193. $record['extra']['win'] = true;
  194. return $record;
  195. });
  196. $logger->error('test');
  197. list($record) = $handler->getRecords();
  198. $this->assertTrue($record['extra']['win']);
  199. }
  200. /**
  201. * @covers Monolog\Logger::addRecord
  202. */
  203. public function testProcessorsAreCalledOnlyOnce()
  204. {
  205. $logger = new Logger(__METHOD__);
  206. $handler = $this->createMock('Monolog\Handler\HandlerInterface');
  207. $handler->expects($this->any())
  208. ->method('isHandling')
  209. ->will($this->returnValue(true))
  210. ;
  211. $handler->expects($this->any())
  212. ->method('handle')
  213. ->will($this->returnValue(true))
  214. ;
  215. $logger->pushHandler($handler);
  216. $processor = $this->getMockBuilder('Monolog\Processor\WebProcessor')
  217. ->disableOriginalConstructor()
  218. ->onlyMethods(['__invoke'])
  219. ->getMock()
  220. ;
  221. $processor->expects($this->once())
  222. ->method('__invoke')
  223. ->will($this->returnArgument(0))
  224. ;
  225. $logger->pushProcessor($processor);
  226. $logger->error('test');
  227. }
  228. /**
  229. * @covers Monolog\Logger::addRecord
  230. */
  231. public function testProcessorsNotCalledWhenNotHandled()
  232. {
  233. $logger = new Logger(__METHOD__);
  234. $handler = $this->createMock('Monolog\Handler\HandlerInterface');
  235. $handler->expects($this->once())
  236. ->method('isHandling')
  237. ->will($this->returnValue(false))
  238. ;
  239. $logger->pushHandler($handler);
  240. $that = $this;
  241. $logger->pushProcessor(function ($record) use ($that) {
  242. $that->fail('The processor should not be called');
  243. });
  244. $logger->alert('test');
  245. }
  246. /**
  247. * @covers Monolog\Logger::addRecord
  248. */
  249. public function testHandlersNotCalledBeforeFirstHandling()
  250. {
  251. $logger = new Logger(__METHOD__);
  252. $handler1 = $this->createMock('Monolog\Handler\HandlerInterface');
  253. $handler1->expects($this->never())
  254. ->method('isHandling')
  255. ->will($this->returnValue(false))
  256. ;
  257. $handler1->expects($this->once())
  258. ->method('handle')
  259. ->will($this->returnValue(false))
  260. ;
  261. $logger->pushHandler($handler1);
  262. $handler2 = $this->createMock('Monolog\Handler\HandlerInterface');
  263. $handler2->expects($this->once())
  264. ->method('isHandling')
  265. ->will($this->returnValue(true))
  266. ;
  267. $handler2->expects($this->once())
  268. ->method('handle')
  269. ->will($this->returnValue(false))
  270. ;
  271. $logger->pushHandler($handler2);
  272. $handler3 = $this->createMock('Monolog\Handler\HandlerInterface');
  273. $handler3->expects($this->once())
  274. ->method('isHandling')
  275. ->will($this->returnValue(false))
  276. ;
  277. $handler3->expects($this->never())
  278. ->method('handle')
  279. ;
  280. $logger->pushHandler($handler3);
  281. $logger->debug('test');
  282. }
  283. /**
  284. * @covers Monolog\Logger::addRecord
  285. */
  286. public function testHandlersNotCalledBeforeFirstHandlingWithAssocArray()
  287. {
  288. $handler1 = $this->createMock('Monolog\Handler\HandlerInterface');
  289. $handler1->expects($this->never())
  290. ->method('isHandling')
  291. ->will($this->returnValue(false))
  292. ;
  293. $handler1->expects($this->once())
  294. ->method('handle')
  295. ->will($this->returnValue(false))
  296. ;
  297. $handler2 = $this->createMock('Monolog\Handler\HandlerInterface');
  298. $handler2->expects($this->once())
  299. ->method('isHandling')
  300. ->will($this->returnValue(true))
  301. ;
  302. $handler2->expects($this->once())
  303. ->method('handle')
  304. ->will($this->returnValue(false))
  305. ;
  306. $handler3 = $this->createMock('Monolog\Handler\HandlerInterface');
  307. $handler3->expects($this->once())
  308. ->method('isHandling')
  309. ->will($this->returnValue(false))
  310. ;
  311. $handler3->expects($this->never())
  312. ->method('handle')
  313. ;
  314. $logger = new Logger(__METHOD__, ['last' => $handler3, 'second' => $handler2, 'first' => $handler1]);
  315. $logger->debug('test');
  316. }
  317. /**
  318. * @covers Monolog\Logger::addRecord
  319. */
  320. public function testBubblingWhenTheHandlerReturnsFalse()
  321. {
  322. $logger = new Logger(__METHOD__);
  323. $handler1 = $this->createMock('Monolog\Handler\HandlerInterface');
  324. $handler1->expects($this->any())
  325. ->method('isHandling')
  326. ->will($this->returnValue(true))
  327. ;
  328. $handler1->expects($this->once())
  329. ->method('handle')
  330. ->will($this->returnValue(false))
  331. ;
  332. $logger->pushHandler($handler1);
  333. $handler2 = $this->createMock('Monolog\Handler\HandlerInterface');
  334. $handler2->expects($this->any())
  335. ->method('isHandling')
  336. ->will($this->returnValue(true))
  337. ;
  338. $handler2->expects($this->once())
  339. ->method('handle')
  340. ->will($this->returnValue(false))
  341. ;
  342. $logger->pushHandler($handler2);
  343. $logger->debug('test');
  344. }
  345. /**
  346. * @covers Monolog\Logger::addRecord
  347. */
  348. public function testNotBubblingWhenTheHandlerReturnsTrue()
  349. {
  350. $logger = new Logger(__METHOD__);
  351. $handler1 = $this->createMock('Monolog\Handler\HandlerInterface');
  352. $handler1->expects($this->any())
  353. ->method('isHandling')
  354. ->will($this->returnValue(true))
  355. ;
  356. $handler1->expects($this->never())
  357. ->method('handle')
  358. ;
  359. $logger->pushHandler($handler1);
  360. $handler2 = $this->createMock('Monolog\Handler\HandlerInterface');
  361. $handler2->expects($this->any())
  362. ->method('isHandling')
  363. ->will($this->returnValue(true))
  364. ;
  365. $handler2->expects($this->once())
  366. ->method('handle')
  367. ->will($this->returnValue(true))
  368. ;
  369. $logger->pushHandler($handler2);
  370. $logger->debug('test');
  371. }
  372. /**
  373. * @covers Monolog\Logger::isHandling
  374. */
  375. public function testIsHandling()
  376. {
  377. $logger = new Logger(__METHOD__);
  378. $handler1 = $this->createMock('Monolog\Handler\HandlerInterface');
  379. $handler1->expects($this->any())
  380. ->method('isHandling')
  381. ->will($this->returnValue(false))
  382. ;
  383. $logger->pushHandler($handler1);
  384. $this->assertFalse($logger->isHandling(Logger::DEBUG));
  385. $handler2 = $this->createMock('Monolog\Handler\HandlerInterface');
  386. $handler2->expects($this->any())
  387. ->method('isHandling')
  388. ->will($this->returnValue(true))
  389. ;
  390. $logger->pushHandler($handler2);
  391. $this->assertTrue($logger->isHandling(Logger::DEBUG));
  392. }
  393. /**
  394. * @dataProvider logMethodProvider
  395. * @covers Monolog\Logger::debug
  396. * @covers Monolog\Logger::info
  397. * @covers Monolog\Logger::notice
  398. * @covers Monolog\Logger::warning
  399. * @covers Monolog\Logger::error
  400. * @covers Monolog\Logger::critical
  401. * @covers Monolog\Logger::alert
  402. * @covers Monolog\Logger::emergency
  403. */
  404. public function testLogMethods($method, $expectedLevel)
  405. {
  406. $logger = new Logger('foo');
  407. $handler = new TestHandler;
  408. $logger->pushHandler($handler);
  409. $logger->{$method}('test');
  410. list($record) = $handler->getRecords();
  411. $this->assertEquals($expectedLevel, $record['level']);
  412. }
  413. public function logMethodProvider()
  414. {
  415. return [
  416. // PSR-3 methods
  417. ['debug', Logger::DEBUG],
  418. ['info', Logger::INFO],
  419. ['notice', Logger::NOTICE],
  420. ['warning', Logger::WARNING],
  421. ['error', Logger::ERROR],
  422. ['critical', Logger::CRITICAL],
  423. ['alert', Logger::ALERT],
  424. ['emergency', Logger::EMERGENCY],
  425. ];
  426. }
  427. /**
  428. * @dataProvider setTimezoneProvider
  429. * @covers Monolog\Logger::setTimezone
  430. */
  431. public function testSetTimezone($tz)
  432. {
  433. $logger = new Logger('foo');
  434. $logger->setTimezone($tz);
  435. $handler = new TestHandler;
  436. $logger->pushHandler($handler);
  437. $logger->info('test');
  438. list($record) = $handler->getRecords();
  439. $this->assertEquals($tz, $record['datetime']->getTimezone());
  440. }
  441. public function setTimezoneProvider()
  442. {
  443. return array_map(
  444. function ($tz) {
  445. return [new \DateTimeZone($tz)];
  446. },
  447. \DateTimeZone::listIdentifiers()
  448. );
  449. }
  450. /**
  451. * @covers Monolog\Logger::setTimezone
  452. * @covers Monolog\DateTimeImmutable::__construct
  453. */
  454. public function testTimezoneIsRespectedInUTC()
  455. {
  456. foreach ([true, false] as $microseconds) {
  457. $logger = new Logger('foo');
  458. $logger->useMicrosecondTimestamps($microseconds);
  459. $tz = new \DateTimeZone('America/New_York');
  460. $logger->setTimezone($tz);
  461. $handler = new TestHandler;
  462. $logger->pushHandler($handler);
  463. $dt = new \DateTime('now', $tz);
  464. $logger->info('test');
  465. list($record) = $handler->getRecords();
  466. $this->assertEquals($tz, $record['datetime']->getTimezone());
  467. $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));
  468. }
  469. }
  470. /**
  471. * @covers Monolog\Logger::setTimezone
  472. * @covers Monolog\DateTimeImmutable::__construct
  473. */
  474. public function testTimezoneIsRespectedInOtherTimezone()
  475. {
  476. date_default_timezone_set('CET');
  477. foreach ([true, false] as $microseconds) {
  478. $logger = new Logger('foo');
  479. $logger->useMicrosecondTimestamps($microseconds);
  480. $tz = new \DateTimeZone('America/New_York');
  481. $logger->setTimezone($tz);
  482. $handler = new TestHandler;
  483. $logger->pushHandler($handler);
  484. $dt = new \DateTime('now', $tz);
  485. $logger->info('test');
  486. list($record) = $handler->getRecords();
  487. $this->assertEquals($tz, $record['datetime']->getTimezone());
  488. $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));
  489. }
  490. }
  491. public function tearDown(): void
  492. {
  493. date_default_timezone_set('UTC');
  494. }
  495. /**
  496. * @dataProvider useMicrosecondTimestampsProvider
  497. * @covers Monolog\Logger::useMicrosecondTimestamps
  498. * @covers Monolog\Logger::addRecord
  499. */
  500. public function testUseMicrosecondTimestamps($micro, $assert, $assertFormat)
  501. {
  502. if (PHP_VERSION_ID === 70103) {
  503. $this->markTestSkipped();
  504. }
  505. $logger = new Logger('foo');
  506. $logger->useMicrosecondTimestamps($micro);
  507. $handler = new TestHandler;
  508. $logger->pushHandler($handler);
  509. $logger->info('test');
  510. list($record) = $handler->getRecords();
  511. $this->{$assert}('000000', $record['datetime']->format('u'));
  512. $this->assertSame($record['datetime']->format($assertFormat), (string) $record['datetime']);
  513. }
  514. public function useMicrosecondTimestampsProvider()
  515. {
  516. return [
  517. // this has a very small chance of a false negative (1/10^6)
  518. 'with microseconds' => [true, 'assertNotSame', 'Y-m-d\TH:i:s.uP'],
  519. // php 7.1 always includes microseconds, so we keep them in, but we format the datetime without
  520. 'without microseconds' => [false, 'assertNotSame', 'Y-m-d\TH:i:sP'],
  521. ];
  522. }
  523. /**
  524. * @covers Monolog\Logger::setExceptionHandler
  525. */
  526. public function testSetExceptionHandler()
  527. {
  528. $logger = new Logger(__METHOD__);
  529. $this->assertNull($logger->getExceptionHandler());
  530. $callback = function ($ex) {
  531. };
  532. $logger->setExceptionHandler($callback);
  533. $this->assertEquals($callback, $logger->getExceptionHandler());
  534. }
  535. /**
  536. * @covers Monolog\Logger::handleException
  537. */
  538. public function testDefaultHandleException()
  539. {
  540. $logger = new Logger(__METHOD__);
  541. $handler = $this->getMockBuilder('Monolog\Handler\HandlerInterface')->getMock();
  542. $handler->expects($this->any())
  543. ->method('isHandling')
  544. ->will($this->returnValue(true))
  545. ;
  546. $handler->expects($this->any())
  547. ->method('handle')
  548. ->will($this->throwException(new \Exception('Some handler exception')))
  549. ;
  550. $this->expectException(\Exception::class);
  551. $logger->pushHandler($handler);
  552. $logger->info('test');
  553. }
  554. /**
  555. * @covers Monolog\Logger::handleException
  556. * @covers Monolog\Logger::addRecord
  557. */
  558. public function testCustomHandleException()
  559. {
  560. $logger = new Logger(__METHOD__);
  561. $that = $this;
  562. $logger->setExceptionHandler(function ($e, $record) use ($that) {
  563. $that->assertEquals($e->getMessage(), 'Some handler exception');
  564. $that->assertTrue(is_array($record));
  565. $that->assertEquals($record['message'], 'test');
  566. });
  567. $handler = $this->getMockBuilder('Monolog\Handler\HandlerInterface')->getMock();
  568. $handler->expects($this->any())
  569. ->method('isHandling')
  570. ->will($this->returnValue(true))
  571. ;
  572. $handler->expects($this->any())
  573. ->method('handle')
  574. ->will($this->throwException(new \Exception('Some handler exception')))
  575. ;
  576. $logger->pushHandler($handler);
  577. $logger->info('test');
  578. }
  579. public function testReset()
  580. {
  581. $logger = new Logger('app');
  582. $testHandler = new Handler\TestHandler();
  583. $testHandler->setSkipReset(true);
  584. $bufferHandler = new Handler\BufferHandler($testHandler);
  585. $groupHandler = new Handler\GroupHandler(array($bufferHandler));
  586. $fingersCrossedHandler = new Handler\FingersCrossedHandler($groupHandler);
  587. $logger->pushHandler($fingersCrossedHandler);
  588. $processorUid1 = new Processor\UidProcessor(10);
  589. $uid1 = $processorUid1->getUid();
  590. $groupHandler->pushProcessor($processorUid1);
  591. $processorUid2 = new Processor\UidProcessor(5);
  592. $uid2 = $processorUid2->getUid();
  593. $logger->pushProcessor($processorUid2);
  594. $getProperty = function ($object, $property) {
  595. $reflectionProperty = new \ReflectionProperty(get_class($object), $property);
  596. $reflectionProperty->setAccessible(true);
  597. return $reflectionProperty->getValue($object);
  598. };
  599. $that = $this;
  600. $assertBufferOfBufferHandlerEmpty = function () use ($getProperty, $bufferHandler, $that) {
  601. $that->assertEmpty($getProperty($bufferHandler, 'buffer'));
  602. };
  603. $assertBuffersEmpty = function () use ($assertBufferOfBufferHandlerEmpty, $getProperty, $fingersCrossedHandler, $that) {
  604. $assertBufferOfBufferHandlerEmpty();
  605. $that->assertEmpty($getProperty($fingersCrossedHandler, 'buffer'));
  606. };
  607. $logger->debug('debug1');
  608. $logger->reset();
  609. $assertBuffersEmpty();
  610. $this->assertFalse($testHandler->hasDebugRecords());
  611. $this->assertFalse($testHandler->hasErrorRecords());
  612. $this->assertNotSame($uid1, $uid1 = $processorUid1->getUid());
  613. $this->assertNotSame($uid2, $uid2 = $processorUid2->getUid());
  614. $logger->debug('debug2');
  615. $logger->error('error2');
  616. $logger->reset();
  617. $assertBuffersEmpty();
  618. $this->assertTrue($testHandler->hasRecordThatContains('debug2', Logger::DEBUG));
  619. $this->assertTrue($testHandler->hasRecordThatContains('error2', Logger::ERROR));
  620. $this->assertNotSame($uid1, $uid1 = $processorUid1->getUid());
  621. $this->assertNotSame($uid2, $uid2 = $processorUid2->getUid());
  622. $logger->info('info3');
  623. $this->assertNotEmpty($getProperty($fingersCrossedHandler, 'buffer'));
  624. $assertBufferOfBufferHandlerEmpty();
  625. $this->assertFalse($testHandler->hasInfoRecords());
  626. $logger->reset();
  627. $assertBuffersEmpty();
  628. $this->assertFalse($testHandler->hasInfoRecords());
  629. $this->assertNotSame($uid1, $uid1 = $processorUid1->getUid());
  630. $this->assertNotSame($uid2, $uid2 = $processorUid2->getUid());
  631. $logger->notice('notice4');
  632. $logger->emergency('emergency4');
  633. $logger->reset();
  634. $assertBuffersEmpty();
  635. $this->assertFalse($testHandler->hasInfoRecords());
  636. $this->assertTrue($testHandler->hasRecordThatContains('notice4', Logger::NOTICE));
  637. $this->assertTrue($testHandler->hasRecordThatContains('emergency4', Logger::EMERGENCY));
  638. $this->assertNotSame($uid1, $processorUid1->getUid());
  639. $this->assertNotSame($uid2, $processorUid2->getUid());
  640. }
  641. /**
  642. * @covers Logger::addRecord
  643. */
  644. public function testLogWithDateTime()
  645. {
  646. foreach ([true, false] as $microseconds) {
  647. $logger = new Logger(__METHOD__);
  648. $loggingHandler = new LoggingHandler($logger);
  649. $testHandler = new TestHandler();
  650. $logger->pushHandler($loggingHandler);
  651. $logger->pushHandler($testHandler);
  652. $datetime = (new DateTimeImmutable($microseconds))->modify('2022-03-04 05:06:07');
  653. $logger->addRecord(Logger::DEBUG, 'test', [], $datetime);
  654. list($record) = $testHandler->getRecords();
  655. $this->assertEquals($datetime->format('Y-m-d H:i:s'), $record['datetime']->format('Y-m-d H:i:s'));
  656. }
  657. }
  658. }
  659. class LoggingHandler implements HandlerInterface
  660. {
  661. /**
  662. * @var Logger
  663. */
  664. private $logger;
  665. public function __construct(Logger $logger)
  666. {
  667. $this->logger = $logger;
  668. }
  669. public function isHandling(array $record): bool
  670. {
  671. return true;
  672. }
  673. public function handle(array $record): bool
  674. {
  675. $this->logger->debug('Log triggered while logging');
  676. return false;
  677. }
  678. public function handleBatch(array $records): void
  679. {
  680. }
  681. public function close(): void
  682. {
  683. }
  684. }