LogManagerTest.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. <?php
  2. namespace Illuminate\Tests\Log;
  3. use Illuminate\Log\Logger;
  4. use Illuminate\Log\LogManager;
  5. use Monolog\Formatter\HtmlFormatter;
  6. use Monolog\Formatter\LineFormatter;
  7. use Monolog\Formatter\NormalizerFormatter;
  8. use Monolog\Handler\FingersCrossedHandler;
  9. use Monolog\Handler\LogEntriesHandler;
  10. use Monolog\Handler\NewRelicHandler;
  11. use Monolog\Handler\NullHandler;
  12. use Monolog\Handler\StreamHandler;
  13. use Monolog\Handler\SyslogHandler;
  14. use Monolog\Logger as Monolog;
  15. use Monolog\Processor\UidProcessor;
  16. use Orchestra\Testbench\TestCase;
  17. use ReflectionProperty;
  18. use RuntimeException;
  19. class LogManagerTest extends TestCase
  20. {
  21. public function testLogManagerCachesLoggerInstances()
  22. {
  23. $manager = new LogManager($this->app);
  24. $logger1 = $manager->channel('single')->getLogger();
  25. $logger2 = $manager->channel('single')->getLogger();
  26. $this->assertSame($logger1, $logger2);
  27. }
  28. public function testStackChannel()
  29. {
  30. $config = $this->app['config'];
  31. $config->set('logging.channels.stack', [
  32. 'driver' => 'stack',
  33. 'channels' => ['stderr', 'stdout'],
  34. ]);
  35. $config->set('logging.channels.stderr', [
  36. 'driver' => 'monolog',
  37. 'handler' => StreamHandler::class,
  38. 'level' => 'notice',
  39. 'with' => [
  40. 'stream' => 'php://stderr',
  41. 'bubble' => false,
  42. ],
  43. ]);
  44. $config->set('logging.channels.stdout', [
  45. 'driver' => 'monolog',
  46. 'handler' => StreamHandler::class,
  47. 'level' => 'info',
  48. 'with' => [
  49. 'stream' => 'php://stdout',
  50. 'bubble' => true,
  51. ],
  52. ]);
  53. $manager = new LogManager($this->app);
  54. // create logger with handler specified from configuration
  55. $logger = $manager->channel('stack');
  56. $handlers = $logger->getLogger()->getHandlers();
  57. $this->assertInstanceOf(Logger::class, $logger);
  58. $this->assertCount(2, $handlers);
  59. $this->assertInstanceOf(StreamHandler::class, $handlers[0]);
  60. $this->assertInstanceOf(StreamHandler::class, $handlers[1]);
  61. $this->assertEquals(Monolog::NOTICE, $handlers[0]->getLevel());
  62. $this->assertEquals(Monolog::INFO, $handlers[1]->getLevel());
  63. $this->assertFalse($handlers[0]->getBubble());
  64. $this->assertTrue($handlers[1]->getBubble());
  65. }
  66. public function testLogManagerCreatesConfiguredMonologHandler()
  67. {
  68. $config = $this->app['config'];
  69. $config->set('logging.channels.nonbubblingstream', [
  70. 'driver' => 'monolog',
  71. 'name' => 'foobar',
  72. 'handler' => StreamHandler::class,
  73. 'level' => 'notice',
  74. 'with' => [
  75. 'stream' => 'php://stderr',
  76. 'bubble' => false,
  77. ],
  78. ]);
  79. $manager = new LogManager($this->app);
  80. // create logger with handler specified from configuration
  81. $logger = $manager->channel('nonbubblingstream');
  82. $handlers = $logger->getLogger()->getHandlers();
  83. $this->assertInstanceOf(Logger::class, $logger);
  84. $this->assertSame('foobar', $logger->getName());
  85. $this->assertCount(1, $handlers);
  86. $this->assertInstanceOf(StreamHandler::class, $handlers[0]);
  87. $this->assertEquals(Monolog::NOTICE, $handlers[0]->getLevel());
  88. $this->assertFalse($handlers[0]->getBubble());
  89. $url = new ReflectionProperty(get_class($handlers[0]), 'url');
  90. $url->setAccessible(true);
  91. $this->assertSame('php://stderr', $url->getValue($handlers[0]));
  92. $config->set('logging.channels.logentries', [
  93. 'driver' => 'monolog',
  94. 'name' => 'le',
  95. 'handler' => LogEntriesHandler::class,
  96. 'with' => [
  97. 'token' => '123456789',
  98. ],
  99. ]);
  100. $logger = $manager->channel('logentries');
  101. $handlers = $logger->getLogger()->getHandlers();
  102. $logToken = new ReflectionProperty(get_class($handlers[0]), 'logToken');
  103. $logToken->setAccessible(true);
  104. $this->assertInstanceOf(LogEntriesHandler::class, $handlers[0]);
  105. $this->assertSame('123456789', $logToken->getValue($handlers[0]));
  106. }
  107. public function testLogManagerCreatesMonologHandlerWithConfiguredFormatter()
  108. {
  109. $config = $this->app['config'];
  110. $config->set('logging.channels.newrelic', [
  111. 'driver' => 'monolog',
  112. 'name' => 'nr',
  113. 'handler' => NewRelicHandler::class,
  114. 'formatter' => 'default',
  115. ]);
  116. $manager = new LogManager($this->app);
  117. // create logger with handler specified from configuration
  118. $logger = $manager->channel('newrelic');
  119. $handler = $logger->getLogger()->getHandlers()[0];
  120. $this->assertInstanceOf(NewRelicHandler::class, $handler);
  121. $this->assertInstanceOf(NormalizerFormatter::class, $handler->getFormatter());
  122. $config->set('logging.channels.newrelic2', [
  123. 'driver' => 'monolog',
  124. 'name' => 'nr',
  125. 'handler' => NewRelicHandler::class,
  126. 'formatter' => HtmlFormatter::class,
  127. 'formatter_with' => [
  128. 'dateFormat' => 'Y/m/d--test',
  129. ],
  130. ]);
  131. $logger = $manager->channel('newrelic2');
  132. $handler = $logger->getLogger()->getHandlers()[0];
  133. $formatter = $handler->getFormatter();
  134. $this->assertInstanceOf(NewRelicHandler::class, $handler);
  135. $this->assertInstanceOf(HtmlFormatter::class, $formatter);
  136. $dateFormat = new ReflectionProperty(get_class($formatter), 'dateFormat');
  137. $dateFormat->setAccessible(true);
  138. $this->assertSame('Y/m/d--test', $dateFormat->getValue($formatter));
  139. }
  140. public function testLogManagerCreatesMonologHandlerWithProperFormatter()
  141. {
  142. $config = $this->app->make('config');
  143. $config->set('logging.channels.null', [
  144. 'driver' => 'monolog',
  145. 'handler' => NullHandler::class,
  146. 'formatter' => HtmlFormatter::class,
  147. ]);
  148. $manager = new LogManager($this->app);
  149. // create logger with handler specified from configuration
  150. $logger = $manager->channel('null');
  151. $handler = $logger->getLogger()->getHandlers()[0];
  152. if (Monolog::API === 1) {
  153. $this->assertInstanceOf(NullHandler::class, $handler);
  154. $this->assertInstanceOf(HtmlFormatter::class, $handler->getFormatter());
  155. } else {
  156. $this->assertInstanceOf(NullHandler::class, $handler);
  157. }
  158. $config->set('logging.channels.null2', [
  159. 'driver' => 'monolog',
  160. 'handler' => NullHandler::class,
  161. ]);
  162. $logger = $manager->channel('null2');
  163. $handler = $logger->getLogger()->getHandlers()[0];
  164. if (Monolog::API === 1) {
  165. $this->assertInstanceOf(NullHandler::class, $handler);
  166. $this->assertInstanceOf(LineFormatter::class, $handler->getFormatter());
  167. } else {
  168. $this->assertInstanceOf(NullHandler::class, $handler);
  169. }
  170. }
  171. public function testItUtilisesTheNullDriverDuringTestsWhenNullDriverUsed()
  172. {
  173. $config = $this->app->make('config');
  174. $config->set('logging.default', null);
  175. $config->set('logging.channels.null', [
  176. 'driver' => 'monolog',
  177. 'handler' => NullHandler::class,
  178. ]);
  179. $manager = new class($this->app) extends LogManager
  180. {
  181. protected function createEmergencyLogger()
  182. {
  183. throw new RuntimeException('Emergency logger was created.');
  184. }
  185. };
  186. // In tests, this should not need to create the emergency logger...
  187. $manager->info('message');
  188. // we should also be able to forget the null channel...
  189. $this->assertCount(1, $manager->getChannels());
  190. $manager->forgetChannel();
  191. $this->assertCount(0, $manager->getChannels());
  192. // However in production we want it to fallback to the emergency logger...
  193. $this->app['env'] = 'production';
  194. try {
  195. $manager->info('message');
  196. $this->fail('Emergency logger was not created as expected.');
  197. } catch (RuntimeException $exception) {
  198. $this->assertSame('Emergency logger was created.', $exception->getMessage());
  199. }
  200. }
  201. public function testLogManagerCreateSingleDriverWithConfiguredFormatter()
  202. {
  203. $config = $this->app['config'];
  204. $config->set('logging.channels.defaultsingle', [
  205. 'driver' => 'single',
  206. 'name' => 'ds',
  207. 'path' => storage_path('logs/laravel.log'),
  208. ]);
  209. $manager = new LogManager($this->app);
  210. // create logger with handler specified from configuration
  211. $logger = $manager->channel('defaultsingle');
  212. $handler = $logger->getLogger()->getHandlers()[0];
  213. $formatter = $handler->getFormatter();
  214. $this->assertInstanceOf(StreamHandler::class, $handler);
  215. $this->assertInstanceOf(LineFormatter::class, $formatter);
  216. $config->set('logging.channels.formattedsingle', [
  217. 'driver' => 'single',
  218. 'name' => 'fs',
  219. 'path' => storage_path('logs/laravel.log'),
  220. 'formatter' => HtmlFormatter::class,
  221. 'formatter_with' => [
  222. 'dateFormat' => 'Y/m/d--test',
  223. ],
  224. ]);
  225. $logger = $manager->channel('formattedsingle');
  226. $handler = $logger->getLogger()->getHandlers()[0];
  227. $formatter = $handler->getFormatter();
  228. $this->assertInstanceOf(StreamHandler::class, $handler);
  229. $this->assertInstanceOf(HtmlFormatter::class, $formatter);
  230. $dateFormat = new ReflectionProperty(get_class($formatter), 'dateFormat');
  231. $dateFormat->setAccessible(true);
  232. $this->assertSame('Y/m/d--test', $dateFormat->getValue($formatter));
  233. }
  234. public function testLogManagerCreateDailyDriverWithConfiguredFormatter()
  235. {
  236. $config = $this->app['config'];
  237. $config->set('logging.channels.defaultdaily', [
  238. 'driver' => 'daily',
  239. 'name' => 'dd',
  240. 'path' => storage_path('logs/laravel.log'),
  241. ]);
  242. $manager = new LogManager($this->app);
  243. // create logger with handler specified from configuration
  244. $logger = $manager->channel('defaultdaily');
  245. $handler = $logger->getLogger()->getHandlers()[0];
  246. $formatter = $handler->getFormatter();
  247. $this->assertInstanceOf(StreamHandler::class, $handler);
  248. $this->assertInstanceOf(LineFormatter::class, $formatter);
  249. $config->set('logging.channels.formatteddaily', [
  250. 'driver' => 'daily',
  251. 'name' => 'fd',
  252. 'path' => storage_path('logs/laravel.log'),
  253. 'formatter' => HtmlFormatter::class,
  254. 'formatter_with' => [
  255. 'dateFormat' => 'Y/m/d--test',
  256. ],
  257. ]);
  258. $logger = $manager->channel('formatteddaily');
  259. $handler = $logger->getLogger()->getHandlers()[0];
  260. $formatter = $handler->getFormatter();
  261. $this->assertInstanceOf(StreamHandler::class, $handler);
  262. $this->assertInstanceOf(HtmlFormatter::class, $formatter);
  263. $dateFormat = new ReflectionProperty(get_class($formatter), 'dateFormat');
  264. $dateFormat->setAccessible(true);
  265. $this->assertSame('Y/m/d--test', $dateFormat->getValue($formatter));
  266. }
  267. public function testLogManagerCreateSyslogDriverWithConfiguredFormatter()
  268. {
  269. $config = $this->app['config'];
  270. $config->set('logging.channels.defaultsyslog', [
  271. 'driver' => 'syslog',
  272. 'name' => 'ds',
  273. ]);
  274. $manager = new LogManager($this->app);
  275. // create logger with handler specified from configuration
  276. $logger = $manager->channel('defaultsyslog');
  277. $handler = $logger->getLogger()->getHandlers()[0];
  278. $formatter = $handler->getFormatter();
  279. $this->assertInstanceOf(SyslogHandler::class, $handler);
  280. $this->assertInstanceOf(LineFormatter::class, $formatter);
  281. $config->set('logging.channels.formattedsyslog', [
  282. 'driver' => 'syslog',
  283. 'name' => 'fs',
  284. 'formatter' => HtmlFormatter::class,
  285. 'formatter_with' => [
  286. 'dateFormat' => 'Y/m/d--test',
  287. ],
  288. ]);
  289. $logger = $manager->channel('formattedsyslog');
  290. $handler = $logger->getLogger()->getHandlers()[0];
  291. $formatter = $handler->getFormatter();
  292. $this->assertInstanceOf(SyslogHandler::class, $handler);
  293. $this->assertInstanceOf(HtmlFormatter::class, $formatter);
  294. $dateFormat = new ReflectionProperty(get_class($formatter), 'dateFormat');
  295. $dateFormat->setAccessible(true);
  296. $this->assertSame('Y/m/d--test', $dateFormat->getValue($formatter));
  297. }
  298. public function testLogManagerPurgeResolvedChannels()
  299. {
  300. $manager = new LogManager($this->app);
  301. $this->assertEmpty($manager->getChannels());
  302. $manager->channel('single')->getLogger();
  303. $this->assertCount(1, $manager->getChannels());
  304. $manager->forgetChannel('single');
  305. $this->assertEmpty($manager->getChannels());
  306. }
  307. public function testLogManagerCanBuildOnDemandChannel()
  308. {
  309. $manager = new LogManager($this->app);
  310. $logger = $manager->build([
  311. 'driver' => 'single',
  312. 'path' => storage_path('logs/on-demand.log'),
  313. ]);
  314. $handler = $logger->getLogger()->getHandlers()[0];
  315. $this->assertInstanceOf(StreamHandler::class, $handler);
  316. $url = new ReflectionProperty(get_class($handler), 'url');
  317. $url->setAccessible(true);
  318. $this->assertSame(storage_path('logs/on-demand.log'), $url->getValue($handler));
  319. }
  320. public function testLogManagerCanUseOnDemandChannelInOnDemandStack()
  321. {
  322. $manager = new LogManager($this->app);
  323. $this->app['config']->set('logging.channels.test', [
  324. 'driver' => 'single',
  325. ]);
  326. $factory = new class()
  327. {
  328. public function __invoke()
  329. {
  330. return new Monolog(
  331. 'uuid',
  332. [new StreamHandler(storage_path('logs/custom.log'))],
  333. [new UidProcessor()]
  334. );
  335. }
  336. };
  337. $channel = $manager->build([
  338. 'driver' => 'custom',
  339. 'via' => get_class($factory),
  340. ]);
  341. $logger = $manager->stack(['test', $channel]);
  342. $handler = $logger->getLogger()->getHandlers()[1];
  343. $processor = $logger->getLogger()->getProcessors()[0];
  344. $this->assertInstanceOf(StreamHandler::class, $handler);
  345. $this->assertInstanceOf(UidProcessor::class, $processor);
  346. $url = new ReflectionProperty(get_class($handler), 'url');
  347. $url->setAccessible(true);
  348. $this->assertSame(storage_path('logs/custom.log'), $url->getValue($handler));
  349. }
  350. public function testWrappingHandlerInFingersCrossedWhenActionLevelIsUsed()
  351. {
  352. $config = $this->app['config'];
  353. $config->set('logging.channels.fingerscrossed', [
  354. 'driver' => 'monolog',
  355. 'handler' => StreamHandler::class,
  356. 'level' => 'debug',
  357. 'action_level' => 'critical',
  358. 'with' => [
  359. 'stream' => 'php://stderr',
  360. 'bubble' => false,
  361. ],
  362. ]);
  363. $manager = new LogManager($this->app);
  364. // create logger with handler specified from configuration
  365. $logger = $manager->channel('fingerscrossed');
  366. $handlers = $logger->getLogger()->getHandlers();
  367. $this->assertInstanceOf(Logger::class, $logger);
  368. $this->assertCount(1, $handlers);
  369. $expectedFingersCrossedHandler = $handlers[0];
  370. $this->assertInstanceOf(FingersCrossedHandler::class, $expectedFingersCrossedHandler);
  371. $activationStrategyProp = new ReflectionProperty(get_class($expectedFingersCrossedHandler), 'activationStrategy');
  372. $activationStrategyProp->setAccessible(true);
  373. $activationStrategyValue = $activationStrategyProp->getValue($expectedFingersCrossedHandler);
  374. $actionLevelProp = new ReflectionProperty(get_class($activationStrategyValue), 'actionLevel');
  375. $actionLevelProp->setAccessible(true);
  376. $actionLevelValue = $actionLevelProp->getValue($activationStrategyValue);
  377. $this->assertEquals(Monolog::CRITICAL, $actionLevelValue);
  378. if (method_exists($expectedFingersCrossedHandler, 'getHandler')) {
  379. $expectedStreamHandler = $expectedFingersCrossedHandler->getHandler();
  380. } else {
  381. $handlerProp = new ReflectionProperty(get_class($expectedFingersCrossedHandler), 'handler');
  382. $handlerProp->setAccessible(true);
  383. $expectedStreamHandler = $handlerProp->getValue($expectedFingersCrossedHandler);
  384. }
  385. $this->assertInstanceOf(StreamHandler::class, $expectedStreamHandler);
  386. $this->assertEquals(Monolog::DEBUG, $expectedStreamHandler->getLevel());
  387. }
  388. }