LoggerTest.php 26 KB

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