Skip to content

Commit 864ef6a

Browse files
[9.x] Share logging context across channels and stacks (#42276)
* allow context to be shared across channels and stacks * add ability to flush the shared context * formatting " Co-authored-by: Taylor Otwell <[email protected]>
1 parent e02307f commit 864ef6a

File tree

3 files changed

+142
-3
lines changed

3 files changed

+142
-3
lines changed

src/Illuminate/Log/LogManager.php

+49-3
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ class LogManager implements LoggerInterface
5151
*/
5252
protected $dateFormat = 'Y-m-d H:i:s';
5353

54+
/**
55+
* The context shared across channels and stacks.
56+
*
57+
* @var array
58+
*/
59+
protected $sharedContext = [];
60+
5461
/**
5562
* Create a new Log manager instance.
5663
*
@@ -84,10 +91,10 @@ public function build(array $config)
8491
*/
8592
public function stack(array $channels, $channel = null)
8693
{
87-
return new Logger(
94+
return (new Logger(
8895
$this->createStackDriver(compact('channels', 'channel')),
8996
$this->app['events']
90-
);
97+
))->withContext($this->sharedContext);
9198
}
9299

93100
/**
@@ -123,7 +130,7 @@ protected function get($name, ?array $config = null)
123130
{
124131
try {
125132
return $this->channels[$name] ?? with($this->resolve($name, $config), function ($logger) use ($name) {
126-
return $this->channels[$name] = $this->tap($name, new Logger($logger, $this->app['events']));
133+
return $this->channels[$name] = $this->tap($name, new Logger($logger, $this->app['events']))->withContext($this->sharedContext);
127134
});
128135
} catch (Throwable $e) {
129136
return tap($this->createEmergencyLogger(), function ($logger) use ($e) {
@@ -438,6 +445,45 @@ protected function formatter()
438445
});
439446
}
440447

448+
/**
449+
* Share context across channels and stacks.
450+
*
451+
* @param array $context
452+
* @return $this
453+
*/
454+
public function shareContext(array $context)
455+
{
456+
foreach ($this->channels as $channel) {
457+
$channel->withContext($context);
458+
}
459+
460+
$this->sharedContext = array_merge($this->sharedContext, $context);
461+
462+
return $this;
463+
}
464+
465+
/**
466+
* The context shared across channels and stacks.
467+
*
468+
* @return array
469+
*/
470+
public function sharedContext()
471+
{
472+
return $this->sharedContext;
473+
}
474+
475+
/**
476+
* Flush the shared context.
477+
*
478+
* @return array
479+
*/
480+
public function flushSharedContext()
481+
{
482+
$this->sharedContext = [];
483+
484+
return $this;
485+
}
486+
441487
/**
442488
* Get fallback log channel name.
443489
*

src/Illuminate/Support/Facades/Log.php

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
* @method static \Psr\Log\LoggerInterface build(array $config)
99
* @method static \Illuminate\Log\Logger withContext(array $context = [])
1010
* @method static \Illuminate\Log\Logger withoutContext()
11+
* @method static \Illuminate\Log\LogManager shareContext(array $context)
12+
* @method static array sharedContext()
1113
* @method static void alert(string $message, array $context = [])
1214
* @method static void critical(string $message, array $context = [])
1315
* @method static void debug(string $message, array $context = [])

tests/Log/LogManagerTest.php

+91
Original file line numberDiff line numberDiff line change
@@ -481,4 +481,95 @@ public function testWrappingHandlerInFingersCrossedWhenActionLevelIsUsed()
481481
$this->assertInstanceOf(StreamHandler::class, $expectedStreamHandler);
482482
$this->assertEquals(Monolog::DEBUG, $expectedStreamHandler->getLevel());
483483
}
484+
485+
public function testItSharesContextWithAlreadyResolvedChannels()
486+
{
487+
$manager = new LogManager($this->app);
488+
$channel = $manager->channel('single');
489+
$context = null;
490+
491+
$channel->listen(function ($message) use (&$context) {
492+
$context = $message->context;
493+
});
494+
$manager->shareContext([
495+
'invocation-id' => 'expected-id',
496+
]);
497+
$channel->info('xxxx');
498+
499+
$this->assertSame(['invocation-id' => 'expected-id'], $context);
500+
}
501+
502+
public function testItSharesContextWithFreshlyResolvedChannels()
503+
{
504+
$manager = new LogManager($this->app);
505+
$context = null;
506+
507+
$manager->shareContext([
508+
'invocation-id' => 'expected-id',
509+
]);
510+
$manager->channel('single')->listen(function ($message) use (&$context) {
511+
$context = $message->context;
512+
});
513+
$manager->channel('single')->info('xxxx');
514+
515+
$this->assertSame(['invocation-id' => 'expected-id'], $context);
516+
}
517+
518+
public function testContextCanBePublicallyAccessedByOtherLoggingSystems()
519+
{
520+
$manager = new LogManager($this->app);
521+
$context = null;
522+
523+
$manager->shareContext([
524+
'invocation-id' => 'expected-id',
525+
]);
526+
527+
$this->assertSame($manager->sharedContext(), ['invocation-id' => 'expected-id']);
528+
}
529+
530+
public function testItSharesContextWithStacksWhenTheyAreResolved()
531+
{
532+
$manager = new LogManager($this->app);
533+
$context = null;
534+
535+
$manager->shareContext([
536+
'invocation-id' => 'expected-id',
537+
]);
538+
$stack = $manager->stack(['single']);
539+
$stack->listen(function ($message) use (&$context) {
540+
$context = $message->context;
541+
});
542+
$stack->info('xxxx');
543+
544+
$this->assertSame(['invocation-id' => 'expected-id'], $context);
545+
}
546+
547+
public function testItMergesSharedContextRatherThanReplacing()
548+
{
549+
$manager = new LogManager($this->app);
550+
$context = null;
551+
552+
$manager->shareContext([
553+
'invocation-id' => 'expected-id',
554+
]);
555+
$manager->shareContext([
556+
'invocation-start' => 1651800456,
557+
]);
558+
$manager->channel('single')->listen(function ($message) use (&$context) {
559+
$context = $message->context;
560+
});
561+
$manager->channel('single')->info('xxxx', [
562+
'logged' => 'context',
563+
]);
564+
565+
$this->assertSame([
566+
'invocation-id' => 'expected-id',
567+
'invocation-start' => 1651800456,
568+
'logged' => 'context',
569+
], $context);
570+
$this->assertSame([
571+
'invocation-id' => 'expected-id',
572+
'invocation-start' => 1651800456,
573+
], $manager->sharedContext());
574+
}
484575
}

0 commit comments

Comments
 (0)