LoggerTest.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798
  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. use Monolog\Test\TestCase;
  15. class LoggerTest extends TestCase
  16. {
  17. /**
  18. * @covers Logger::getName
  19. */
  20. public function testGetName()
  21. {
  22. $logger = new Logger('foo');
  23. $this->assertEquals('foo', $logger->getName());
  24. }
  25. /**
  26. * @covers Logger::withName
  27. */
  28. public function testWithName()
  29. {
  30. $first = new Logger('first', [$handler = new TestHandler()]);
  31. $second = $first->withName('second');
  32. $this->assertSame('first', $first->getName());
  33. $this->assertSame('second', $second->getName());
  34. $this->assertSame($handler, $second->popHandler());
  35. }
  36. /**
  37. * @covers Logger::toMonologLevel
  38. */
  39. public function testConvertPSR3ToMonologLevel()
  40. {
  41. $this->assertEquals(Logger::toMonologLevel('debug'), Level::Debug);
  42. $this->assertEquals(Logger::toMonologLevel('info'), Level::Info);
  43. $this->assertEquals(Logger::toMonologLevel('notice'), Level::Notice);
  44. $this->assertEquals(Logger::toMonologLevel('warning'), Level::Warning);
  45. $this->assertEquals(Logger::toMonologLevel('error'), Level::Error);
  46. $this->assertEquals(Logger::toMonologLevel('critical'), Level::Critical);
  47. $this->assertEquals(Logger::toMonologLevel('alert'), Level::Alert);
  48. $this->assertEquals(Logger::toMonologLevel('emergency'), Level::Emergency);
  49. }
  50. /**
  51. * @covers Logger::__construct
  52. */
  53. public function testChannel()
  54. {
  55. $logger = new Logger('foo');
  56. $handler = new TestHandler;
  57. $logger->pushHandler($handler);
  58. $logger->warning('test');
  59. list($record) = $handler->getRecords();
  60. $this->assertEquals('foo', $record->channel);
  61. }
  62. /**
  63. * @covers Logger::addRecord
  64. */
  65. public function testLogPreventsCircularLogging()
  66. {
  67. $logger = new Logger(__METHOD__);
  68. $loggingHandler = new LoggingHandler($logger);
  69. $testHandler = new TestHandler();
  70. $logger->pushHandler($loggingHandler);
  71. $logger->pushHandler($testHandler);
  72. $logger->addRecord(Level::Alert, 'test');
  73. $records = $testHandler->getRecords();
  74. $this->assertCount(3, $records);
  75. $this->assertSame('ALERT', $records[0]->level->getName());
  76. $this->assertSame('DEBUG', $records[1]->level->getName());
  77. $this->assertSame('WARNING', $records[2]->level->getName());
  78. }
  79. /**
  80. * @covers Monolog\Logger::addRecord
  81. */
  82. public function testLog()
  83. {
  84. $logger = new Logger(__METHOD__);
  85. $handler = $this->getMockBuilder('Monolog\Handler\HandlerInterface')->getMock();
  86. $handler->expects($this->never())->method('isHandling');
  87. $handler->expects($this->once())->method('handle');
  88. $logger->pushHandler($handler);
  89. $this->assertTrue($logger->addRecord(Level::Warning, 'test'));
  90. }
  91. /**
  92. * @covers Logger::addRecord
  93. */
  94. public function testLogAlwaysHandledIfNoProcessorsArePresent()
  95. {
  96. $logger = new Logger(__METHOD__);
  97. $handler = $this->getMockBuilder('Monolog\Handler\HandlerInterface')->getMock();
  98. $handler->expects($this->never())->method('isHandling');
  99. $handler->expects($this->once())->method('handle');
  100. $logger->pushHandler($handler);
  101. $this->assertTrue($logger->addRecord(Level::Warning, 'test'));
  102. }
  103. /**
  104. * @covers Logger::addRecord
  105. */
  106. public function testLogNotHandledIfProcessorsArePresent()
  107. {
  108. $logger = new Logger(__METHOD__);
  109. $handler = $this->getMockBuilder('Monolog\Handler\HandlerInterface')->getMock();
  110. $handler->expects($this->once())->method('isHandling')->will($this->returnValue(false));
  111. $handler->expects($this->never())->method('handle');
  112. $logger->pushProcessor(fn (LogRecord $record) => $record);
  113. $logger->pushHandler($handler);
  114. $this->assertFalse($logger->addRecord(Level::Warning, 'test'));
  115. }
  116. public function testHandlersInCtor()
  117. {
  118. $handler1 = new TestHandler;
  119. $handler2 = new TestHandler;
  120. $logger = new Logger(__METHOD__, [$handler1, $handler2]);
  121. $this->assertEquals($handler1, $logger->popHandler());
  122. $this->assertEquals($handler2, $logger->popHandler());
  123. }
  124. public function testProcessorsInCtor()
  125. {
  126. $processor1 = new WebProcessor;
  127. $processor2 = new WebProcessor;
  128. $logger = new Logger(__METHOD__, [], [$processor1, $processor2]);
  129. $this->assertEquals($processor1, $logger->popProcessor());
  130. $this->assertEquals($processor2, $logger->popProcessor());
  131. }
  132. /**
  133. * @covers Logger::pushHandler
  134. * @covers Logger::popHandler
  135. */
  136. public function testPushPopHandler()
  137. {
  138. $logger = new Logger(__METHOD__);
  139. $handler1 = new TestHandler;
  140. $handler2 = new TestHandler;
  141. $logger->pushHandler($handler1);
  142. $logger->pushHandler($handler2);
  143. $this->assertEquals($handler2, $logger->popHandler());
  144. $this->assertEquals($handler1, $logger->popHandler());
  145. $this->expectException(\LogicException::class);
  146. $logger->popHandler();
  147. }
  148. /**
  149. * @covers Logger::setHandlers
  150. */
  151. public function testSetHandlers()
  152. {
  153. $logger = new Logger(__METHOD__);
  154. $handler1 = new TestHandler;
  155. $handler2 = new TestHandler;
  156. $logger->pushHandler($handler1);
  157. $logger->setHandlers([$handler2]);
  158. // handler1 has been removed
  159. $this->assertEquals([$handler2], $logger->getHandlers());
  160. $logger->setHandlers([
  161. "AMapKey" => $handler1,
  162. "Woop" => $handler2,
  163. ]);
  164. // Keys have been scrubbed
  165. $this->assertEquals([$handler1, $handler2], $logger->getHandlers());
  166. }
  167. /**
  168. * @covers Logger::pushProcessor
  169. * @covers Logger::popProcessor
  170. */
  171. public function testPushPopProcessor()
  172. {
  173. $logger = new Logger(__METHOD__);
  174. $processor1 = new WebProcessor;
  175. $processor2 = new WebProcessor;
  176. $logger->pushProcessor($processor1);
  177. $logger->pushProcessor($processor2);
  178. $this->assertEquals($processor2, $logger->popProcessor());
  179. $this->assertEquals($processor1, $logger->popProcessor());
  180. $this->expectException(\LogicException::class);
  181. $logger->popProcessor();
  182. }
  183. /**
  184. * @covers Logger::addRecord
  185. */
  186. public function testProcessorsAreExecuted()
  187. {
  188. $logger = new Logger(__METHOD__);
  189. $handler = new TestHandler;
  190. $logger->pushHandler($handler);
  191. $logger->pushProcessor(function ($record) {
  192. $record->extra['win'] = true;
  193. return $record;
  194. });
  195. $logger->error('test');
  196. list($record) = $handler->getRecords();
  197. $this->assertTrue($record->extra['win']);
  198. }
  199. /**
  200. * @covers Logger::addRecord
  201. */
  202. public function testProcessorsAreCalledOnlyOnce()
  203. {
  204. $logger = new Logger(__METHOD__);
  205. $handler = $this->createMock('Monolog\Handler\HandlerInterface');
  206. $handler->expects($this->any())
  207. ->method('isHandling')
  208. ->will($this->returnValue(true))
  209. ;
  210. $handler->expects($this->any())
  211. ->method('handle')
  212. ->will($this->returnValue(true))
  213. ;
  214. $logger->pushHandler($handler);
  215. $processor = $this->getMockBuilder('Monolog\Processor\WebProcessor')
  216. ->disableOriginalConstructor()
  217. ->onlyMethods(['__invoke'])
  218. ->getMock()
  219. ;
  220. $processor->expects($this->once())
  221. ->method('__invoke')
  222. ->will($this->returnArgument(0))
  223. ;
  224. $logger->pushProcessor($processor);
  225. $logger->error('test');
  226. }
  227. /**
  228. * @covers Logger::addRecord
  229. */
  230. public function testProcessorsNotCalledWhenNotHandled()
  231. {
  232. $logger = new Logger(__METHOD__);
  233. $handler = $this->createMock('Monolog\Handler\HandlerInterface');
  234. $handler->expects($this->once())
  235. ->method('isHandling')
  236. ->will($this->returnValue(false))
  237. ;
  238. $logger->pushHandler($handler);
  239. $that = $this;
  240. $logger->pushProcessor(function ($record) use ($that) {
  241. $that->fail('The processor should not be called');
  242. });
  243. $logger->alert('test');
  244. }
  245. /**
  246. * @covers Logger::addRecord
  247. */
  248. public function testHandlersNotCalledBeforeFirstHandlingWhenProcessorsPresent()
  249. {
  250. $logger = new Logger(__METHOD__);
  251. $logger->pushProcessor(fn ($record) => $record);
  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 Logger::addRecord
  285. */
  286. public function testHandlersNotCalledBeforeFirstHandlingWhenProcessorsPresentWithAssocArray()
  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->pushProcessor(fn ($record) => $record);
  316. $logger->debug('test');
  317. }
  318. /**
  319. * @covers Logger::addRecord
  320. */
  321. public function testBubblingWhenTheHandlerReturnsFalse()
  322. {
  323. $logger = new Logger(__METHOD__);
  324. $handler1 = $this->createMock('Monolog\Handler\HandlerInterface');
  325. $handler1->expects($this->any())
  326. ->method('isHandling')
  327. ->will($this->returnValue(true))
  328. ;
  329. $handler1->expects($this->once())
  330. ->method('handle')
  331. ->will($this->returnValue(false))
  332. ;
  333. $logger->pushHandler($handler1);
  334. $handler2 = $this->createMock('Monolog\Handler\HandlerInterface');
  335. $handler2->expects($this->any())
  336. ->method('isHandling')
  337. ->will($this->returnValue(true))
  338. ;
  339. $handler2->expects($this->once())
  340. ->method('handle')
  341. ->will($this->returnValue(false))
  342. ;
  343. $logger->pushHandler($handler2);
  344. $logger->debug('test');
  345. }
  346. /**
  347. * @covers Logger::addRecord
  348. */
  349. public function testNotBubblingWhenTheHandlerReturnsTrue()
  350. {
  351. $logger = new Logger(__METHOD__);
  352. $handler1 = $this->createMock('Monolog\Handler\HandlerInterface');
  353. $handler1->expects($this->any())
  354. ->method('isHandling')
  355. ->will($this->returnValue(true))
  356. ;
  357. $handler1->expects($this->never())
  358. ->method('handle')
  359. ;
  360. $logger->pushHandler($handler1);
  361. $handler2 = $this->createMock('Monolog\Handler\HandlerInterface');
  362. $handler2->expects($this->any())
  363. ->method('isHandling')
  364. ->will($this->returnValue(true))
  365. ;
  366. $handler2->expects($this->once())
  367. ->method('handle')
  368. ->will($this->returnValue(true))
  369. ;
  370. $logger->pushHandler($handler2);
  371. $logger->debug('test');
  372. }
  373. /**
  374. * @covers Logger::isHandling
  375. */
  376. public function testIsHandling()
  377. {
  378. $logger = new Logger(__METHOD__);
  379. $handler1 = $this->createMock('Monolog\Handler\HandlerInterface');
  380. $handler1->expects($this->any())
  381. ->method('isHandling')
  382. ->will($this->returnValue(false))
  383. ;
  384. $logger->pushHandler($handler1);
  385. $this->assertFalse($logger->isHandling(Level::Debug));
  386. $handler2 = $this->createMock('Monolog\Handler\HandlerInterface');
  387. $handler2->expects($this->any())
  388. ->method('isHandling')
  389. ->will($this->returnValue(true))
  390. ;
  391. $logger->pushHandler($handler2);
  392. $this->assertTrue($logger->isHandling(Level::Debug));
  393. }
  394. /**
  395. * @dataProvider logMethodProvider
  396. * @covers Level::Debug
  397. * @covers Level::Info
  398. * @covers Level::Notice
  399. * @covers Level::Warning
  400. * @covers Level::Error
  401. * @covers Level::Critical
  402. * @covers Level::Alert
  403. * @covers Level::Emergency
  404. */
  405. public function testLogMethods(string $method, Level $expectedLevel)
  406. {
  407. $logger = new Logger('foo');
  408. $handler = new TestHandler;
  409. $logger->pushHandler($handler);
  410. $logger->{$method}('test');
  411. list($record) = $handler->getRecords();
  412. $this->assertEquals($expectedLevel, $record->level);
  413. }
  414. public function logMethodProvider()
  415. {
  416. return [
  417. // PSR-3 methods
  418. ['debug', Level::Debug],
  419. ['info', Level::Info],
  420. ['notice', Level::Notice],
  421. ['warning', Level::Warning],
  422. ['error', Level::Error],
  423. ['critical', Level::Critical],
  424. ['alert', Level::Alert],
  425. ['emergency', Level::Emergency],
  426. ];
  427. }
  428. /**
  429. * @dataProvider setTimezoneProvider
  430. * @covers Logger::setTimezone
  431. */
  432. public function testSetTimezone($tz)
  433. {
  434. $logger = new Logger('foo');
  435. $logger->setTimezone($tz);
  436. $handler = new TestHandler;
  437. $logger->pushHandler($handler);
  438. $logger->info('test');
  439. list($record) = $handler->getRecords();
  440. $this->assertEquals($tz, $record->datetime->getTimezone());
  441. }
  442. public function setTimezoneProvider()
  443. {
  444. return array_map(
  445. function ($tz) {
  446. return [new \DateTimeZone($tz)];
  447. },
  448. \DateTimeZone::listIdentifiers()
  449. );
  450. }
  451. /**
  452. * @covers Logger::setTimezone
  453. * @covers DateTimeImmutable::__construct
  454. */
  455. public function testTimezoneIsRespectedInUTC()
  456. {
  457. foreach ([true, false] as $microseconds) {
  458. $logger = new Logger('foo');
  459. $logger->useMicrosecondTimestamps($microseconds);
  460. $tz = new \DateTimeZone('America/New_York');
  461. $logger->setTimezone($tz);
  462. $handler = new TestHandler;
  463. $logger->pushHandler($handler);
  464. $dt = new \DateTime('now', $tz);
  465. $logger->info('test');
  466. list($record) = $handler->getRecords();
  467. $this->assertEquals($tz, $record->datetime->getTimezone());
  468. $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));
  469. }
  470. }
  471. /**
  472. * @covers Logger::setTimezone
  473. * @covers DateTimeImmutable::__construct
  474. */
  475. public function testTimezoneIsRespectedInOtherTimezone()
  476. {
  477. date_default_timezone_set('CET');
  478. foreach ([true, false] as $microseconds) {
  479. $logger = new Logger('foo');
  480. $logger->useMicrosecondTimestamps($microseconds);
  481. $tz = new \DateTimeZone('America/New_York');
  482. $logger->setTimezone($tz);
  483. $handler = new TestHandler;
  484. $logger->pushHandler($handler);
  485. $dt = new \DateTime('now', $tz);
  486. $logger->info('test');
  487. list($record) = $handler->getRecords();
  488. $this->assertEquals($tz, $record->datetime->getTimezone());
  489. $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));
  490. }
  491. }
  492. public function tearDown(): void
  493. {
  494. date_default_timezone_set('UTC');
  495. }
  496. /**
  497. * @dataProvider useMicrosecondTimestampsProvider
  498. * @covers Logger::useMicrosecondTimestamps
  499. * @covers Logger::addRecord
  500. */
  501. public function testUseMicrosecondTimestamps($micro, $assert, $assertFormat)
  502. {
  503. if (PHP_VERSION_ID === 70103) {
  504. $this->markTestSkipped();
  505. }
  506. $logger = new Logger('foo');
  507. $logger->useMicrosecondTimestamps($micro);
  508. $handler = new TestHandler;
  509. $logger->pushHandler($handler);
  510. $logger->info('test');
  511. list($record) = $handler->getRecords();
  512. $this->{$assert}('000000', $record->datetime->format('u'));
  513. $this->assertSame($record->datetime->format($assertFormat), (string) $record->datetime);
  514. }
  515. public function useMicrosecondTimestampsProvider()
  516. {
  517. return [
  518. // this has a very small chance of a false negative (1/10^6)
  519. 'with microseconds' => [true, 'assertNotSame', 'Y-m-d\TH:i:s.uP'],
  520. // php 7.1 always includes microseconds, so we keep them in, but we format the datetime without
  521. 'without microseconds' => [false, 'assertNotSame', 'Y-m-d\TH:i:sP'],
  522. ];
  523. }
  524. /**
  525. * @covers Logger::setExceptionHandler
  526. */
  527. public function testSetExceptionHandler()
  528. {
  529. $logger = new Logger(__METHOD__);
  530. $this->assertNull($logger->getExceptionHandler());
  531. $callback = function ($ex) {
  532. };
  533. $logger->setExceptionHandler($callback);
  534. $this->assertEquals($callback, $logger->getExceptionHandler());
  535. }
  536. /**
  537. * @covers Logger::handleException
  538. */
  539. public function testDefaultHandleException()
  540. {
  541. $logger = new Logger(__METHOD__);
  542. $handler = $this->getMockBuilder('Monolog\Handler\HandlerInterface')->getMock();
  543. $handler->expects($this->any())
  544. ->method('isHandling')
  545. ->will($this->returnValue(true))
  546. ;
  547. $handler->expects($this->any())
  548. ->method('handle')
  549. ->will($this->throwException(new \Exception('Some handler exception')))
  550. ;
  551. $this->expectException(\Exception::class);
  552. $logger->pushHandler($handler);
  553. $logger->info('test');
  554. }
  555. /**
  556. * @covers Logger::handleException
  557. * @covers Logger::addRecord
  558. */
  559. public function testCustomHandleException()
  560. {
  561. $logger = new Logger(__METHOD__);
  562. $that = $this;
  563. $logger->setExceptionHandler(function ($e, $record) use ($that) {
  564. $that->assertEquals($e->getMessage(), 'Some handler exception');
  565. $that->assertInstanceOf(LogRecord::class, $record);
  566. $that->assertEquals($record->message, 'test');
  567. });
  568. $handler = $this->getMockBuilder('Monolog\Handler\HandlerInterface')->getMock();
  569. $handler->expects($this->any())
  570. ->method('isHandling')
  571. ->will($this->returnValue(true))
  572. ;
  573. $handler->expects($this->any())
  574. ->method('handle')
  575. ->will($this->throwException(new \Exception('Some handler exception')))
  576. ;
  577. $logger->pushHandler($handler);
  578. $logger->info('test');
  579. }
  580. public function testReset()
  581. {
  582. $logger = new Logger('app');
  583. $testHandler = new Handler\TestHandler();
  584. $testHandler->setSkipReset(true);
  585. $bufferHandler = new Handler\BufferHandler($testHandler);
  586. $groupHandler = new Handler\GroupHandler([$bufferHandler]);
  587. $fingersCrossedHandler = new Handler\FingersCrossedHandler($groupHandler);
  588. $logger->pushHandler($fingersCrossedHandler);
  589. $processorUid1 = new Processor\UidProcessor(10);
  590. $uid1 = $processorUid1->getUid();
  591. $groupHandler->pushProcessor($processorUid1);
  592. $processorUid2 = new Processor\UidProcessor(5);
  593. $uid2 = $processorUid2->getUid();
  594. $logger->pushProcessor($processorUid2);
  595. $getProperty = function ($object, $property) {
  596. $reflectionProperty = new \ReflectionProperty(get_class($object), $property);
  597. $reflectionProperty->setAccessible(true);
  598. return $reflectionProperty->getValue($object);
  599. };
  600. $assertBufferOfBufferHandlerEmpty = function () use ($getProperty, $bufferHandler) {
  601. self::assertEmpty($getProperty($bufferHandler, 'buffer'));
  602. };
  603. $assertBuffersEmpty = function () use ($assertBufferOfBufferHandlerEmpty, $getProperty, $fingersCrossedHandler) {
  604. $assertBufferOfBufferHandlerEmpty();
  605. self::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', Level::Debug));
  619. $this->assertTrue($testHandler->hasRecordThatContains('error2', Level::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', Level::Notice));
  637. $this->assertTrue($testHandler->hasRecordThatContains('emergency4', Level::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(Level::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(LogRecord $record): bool
  670. {
  671. return true;
  672. }
  673. public function handle(LogRecord $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. }