From 5c0011cd1b063c2b35eb131d49944f9dc12e0c10 Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Fri, 6 May 2022 11:31:55 +1000 Subject: [PATCH 1/3] allow context to be shared across channels and stacks --- src/Illuminate/Log/LogManager.php | 40 ++++++++++- src/Illuminate/Support/Facades/Log.php | 2 + tests/Log/LogManagerTest.php | 91 ++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Log/LogManager.php b/src/Illuminate/Log/LogManager.php index 751b5e58b275..1c159ed6362e 100644 --- a/src/Illuminate/Log/LogManager.php +++ b/src/Illuminate/Log/LogManager.php @@ -51,6 +51,13 @@ class LogManager implements LoggerInterface */ protected $dateFormat = 'Y-m-d H:i:s'; + /** + * The context shared across channels and stacks. + * + * @var array + */ + protected $sharedContext = []; + /** * Create a new Log manager instance. * @@ -84,10 +91,10 @@ public function build(array $config) */ public function stack(array $channels, $channel = null) { - return new Logger( + return (new Logger( $this->createStackDriver(compact('channels', 'channel')), $this->app['events'] - ); + ))->withContext($this->sharedContext); } /** @@ -123,7 +130,7 @@ protected function get($name, ?array $config = null) { try { return $this->channels[$name] ?? with($this->resolve($name, $config), function ($logger) use ($name) { - return $this->channels[$name] = $this->tap($name, new Logger($logger, $this->app['events'])); + return $this->channels[$name] = $this->tap($name, new Logger($logger, $this->app['events']))->withContext($this->sharedContext); }); } catch (Throwable $e) { return tap($this->createEmergencyLogger(), function ($logger) use ($e) { @@ -509,6 +516,33 @@ public function forgetChannel($driver = null) } } + /** + * Share context across channels and stacks. + * + * @param array $context + * @return $this + */ + public function shareContext(array $context) + { + foreach ($this->channels as $channel) { + $channel->withContext($context); + } + + $this->sharedContext = array_merge($this->sharedContext, $context); + + return $this; + } + + /** + * The context shared across channels and stacks. + * + * @return array + */ + public function sharedContext() + { + return $this->sharedContext; + } + /** * Parse the driver name. * diff --git a/src/Illuminate/Support/Facades/Log.php b/src/Illuminate/Support/Facades/Log.php index 68493fd22af2..65bc6e71779b 100755 --- a/src/Illuminate/Support/Facades/Log.php +++ b/src/Illuminate/Support/Facades/Log.php @@ -8,6 +8,8 @@ * @method static \Psr\Log\LoggerInterface build(array $config) * @method static \Illuminate\Log\Logger withContext(array $context = []) * @method static \Illuminate\Log\Logger withoutContext() + * @method static \Illuminate\Log\LogManager shareContext(array $context) + * @method static array sharedContext() * @method static void alert(string $message, array $context = []) * @method static void critical(string $message, array $context = []) * @method static void debug(string $message, array $context = []) diff --git a/tests/Log/LogManagerTest.php b/tests/Log/LogManagerTest.php index cd7a3b236d70..9b5abd172461 100755 --- a/tests/Log/LogManagerTest.php +++ b/tests/Log/LogManagerTest.php @@ -481,4 +481,95 @@ public function testWrappingHandlerInFingersCrossedWhenActionLevelIsUsed() $this->assertInstanceOf(StreamHandler::class, $expectedStreamHandler); $this->assertEquals(Monolog::DEBUG, $expectedStreamHandler->getLevel()); } + + public function testItSharesContextWithAlreadyResolvedChannels() + { + $manager = new LogManager($this->app); + $channel = $manager->channel('single'); + $context = null; + + $channel->listen(function ($message) use (&$context) { + $context = $message->context; + }); + $manager->shareContext([ + 'invocation-id' => 'expected-id', + ]); + $channel->info('xxxx'); + + $this->assertSame(['invocation-id' => 'expected-id'], $context); + } + + public function testItSharesContextWithFreshlyResolvedChannels() + { + $manager = new LogManager($this->app); + $context = null; + + $manager->shareContext([ + 'invocation-id' => 'expected-id', + ]); + $manager->channel('single')->listen(function ($message) use (&$context) { + $context = $message->context; + }); + $manager->channel('single')->info('xxxx'); + + $this->assertSame(['invocation-id' => 'expected-id'], $context); + } + + public function testContextCanBePublicallyAccessedByOtherLoggingSystems() + { + $manager = new LogManager($this->app); + $context = null; + + $manager->shareContext([ + 'invocation-id' => 'expected-id', + ]); + + $this->assertSame($manager->sharedContext(), ['invocation-id' => 'expected-id']); + } + + public function testItSharesContextWithStacksWhenTheyAreResolved() + { + $manager = new LogManager($this->app); + $context = null; + + $manager->shareContext([ + 'invocation-id' => 'expected-id', + ]); + $stack = $manager->stack(['single']); + $stack->listen(function ($message) use (&$context) { + $context = $message->context; + }); + $stack->info('xxxx'); + + $this->assertSame(['invocation-id' => 'expected-id'], $context); + } + + public function testItMergesSharedContextRatherThanReplacing() + { + $manager = new LogManager($this->app); + $context = null; + + $manager->shareContext([ + 'invocation-id' => 'expected-id', + ]); + $manager->shareContext([ + 'invocation-start' => 1651800456, + ]); + $manager->channel('single')->listen(function ($message) use (&$context) { + $context = $message->context; + }); + $manager->channel('single')->info('xxxx', [ + 'logged' => 'context', + ]); + + $this->assertSame([ + 'invocation-id' => 'expected-id', + 'invocation-start' => 1651800456, + 'logged' => 'context', + ], $context); + $this->assertSame([ + 'invocation-id' => 'expected-id', + 'invocation-start' => 1651800456, + ], $manager->sharedContext()); + } } From 3e5e28e5144ef4e35f4b6ecba422d1f399246ee1 Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Sat, 7 May 2022 19:20:34 +1000 Subject: [PATCH 2/3] add ability to flush the shared context --- src/Illuminate/Log/LogManager.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Illuminate/Log/LogManager.php b/src/Illuminate/Log/LogManager.php index 1c159ed6362e..0a7c28709efd 100644 --- a/src/Illuminate/Log/LogManager.php +++ b/src/Illuminate/Log/LogManager.php @@ -543,6 +543,18 @@ public function sharedContext() return $this->sharedContext; } + /** + * Flush the shared context. + * + * @return array + */ + public function flushSharedContext() + { + $this->sharedContext = []; + + return $this; + } + /** * Parse the driver name. * From 64719e32f737f761b6db2c2992a434fc67af06aa Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 9 May 2022 10:31:11 -0500 Subject: [PATCH 3/3] formatting " --- src/Illuminate/Log/LogManager.php | 78 +++++++++++++++---------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/src/Illuminate/Log/LogManager.php b/src/Illuminate/Log/LogManager.php index 0a7c28709efd..bc3e74b8f058 100644 --- a/src/Illuminate/Log/LogManager.php +++ b/src/Illuminate/Log/LogManager.php @@ -445,6 +445,45 @@ protected function formatter() }); } + /** + * Share context across channels and stacks. + * + * @param array $context + * @return $this + */ + public function shareContext(array $context) + { + foreach ($this->channels as $channel) { + $channel->withContext($context); + } + + $this->sharedContext = array_merge($this->sharedContext, $context); + + return $this; + } + + /** + * The context shared across channels and stacks. + * + * @return array + */ + public function sharedContext() + { + return $this->sharedContext; + } + + /** + * Flush the shared context. + * + * @return array + */ + public function flushSharedContext() + { + $this->sharedContext = []; + + return $this; + } + /** * Get fallback log channel name. * @@ -516,45 +555,6 @@ public function forgetChannel($driver = null) } } - /** - * Share context across channels and stacks. - * - * @param array $context - * @return $this - */ - public function shareContext(array $context) - { - foreach ($this->channels as $channel) { - $channel->withContext($context); - } - - $this->sharedContext = array_merge($this->sharedContext, $context); - - return $this; - } - - /** - * The context shared across channels and stacks. - * - * @return array - */ - public function sharedContext() - { - return $this->sharedContext; - } - - /** - * Flush the shared context. - * - * @return array - */ - public function flushSharedContext() - { - $this->sharedContext = []; - - return $this; - } - /** * Parse the driver name. *