Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Illuminate/Log/Context/ContextLogProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public function __invoke(LogRecord $record): LogRecord

return $record->with(extra: [
...$record->extra,
...$app->get(ContextRepository::class)->all(),
...$app->get(ContextRepository::class)->allWithContextables(),
]);
}
}
13 changes: 13 additions & 0 deletions src/Illuminate/Log/Context/Contracts/Contextable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Illuminate\Log\Context\Contracts;

interface Contextable
{
/**
* The data to append to your log output.
*
* @return array<string, mixed>
*/
public function contextData();
}
71 changes: 67 additions & 4 deletions src/Illuminate/Log/Context/Repository.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Closure;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Log\Context\Contracts\Contextable;
use Illuminate\Log\Context\Events\ContextDehydrating as Dehydrating;
use Illuminate\Log\Context\Events\ContextHydrated as Hydrated;
use Illuminate\Queue\SerializesModels;
Expand Down Expand Up @@ -40,6 +41,11 @@ class Repository
*/
protected $hidden = [];

/**
* @var array<class-string<Contracts\Contextable>, Contracts\Contextable>
*/
protected $contextables = [];

/**
* The callback that should handle unserialize exceptions.
*
Expand Down Expand Up @@ -109,6 +115,17 @@ public function all()
return $this->data;
}

public function allWithContextables()
{
$data = $this->data;

foreach($this->contextables as $contextable) {
$data = array_merge($data, $contextable->contextData());
}

return $data;
}

/**
* Retrieve all the hidden context data.
*
Expand Down Expand Up @@ -370,6 +387,48 @@ public function push($key, ...$values)
return $this;
}

/**
* Register a contextable.
*
* @param array<array-key, Contextable>|Contextable $contextable
* @return $this
*/
public function contextable($contextable)
{
$contextables = is_array($contextable) ? $contextable : [$contextable];

foreach($contextables as $contextable) {
$this->contextables[$contextable::class] = $contextable;
}

return $this;
}

/**
* Retrieve all registered contextables.
*
* @return array<class-string<Contextable>, Contextable>
*/
public function getContextables()
{
return $this->contextables;
}

/**
* Remove a Contextable.
*
* @param class-string<Contextable>|Contextable $contextable
* @return $this
*/
public function forgetContextable($contextable)
{
$class = is_string($contextable) ? $contextable : $contextable::class;

unset($this->contextables[$class]);

return $this;
}

/**
* Pop the latest value from the key's stack.
*
Expand Down Expand Up @@ -572,7 +631,7 @@ public function scope(callable $callback, array $data = [], array $hidden = [])
*/
public function isEmpty()
{
return $this->all() === [] && $this->allHidden() === [];
return $this->all() === [] && $this->allHidden() === [] && $this->getContextables() === [];
}

/**
Expand Down Expand Up @@ -623,6 +682,7 @@ public function flush()
{
$this->data = [];
$this->hidden = [];
$this->contextables = [];

return $this;
}
Expand All @@ -638,7 +698,8 @@ public function dehydrate()
{
$instance = (new static($this->events))
->add($this->all())
->addHidden($this->allHidden());
->addHidden($this->allHidden())
->contextable($this->getContextables());

$instance->events->dispatch(new Dehydrating($instance));

Expand All @@ -647,6 +708,7 @@ public function dehydrate()
return $instance->isEmpty() ? null : [
'data' => array_map($serialize, $instance->all()),
'hidden' => array_map($serialize, $instance->allHidden()),
'contextables' => array_map($serialize, $instance->getContextables()),
];
}

Expand Down Expand Up @@ -686,13 +748,14 @@ public function hydrate($context)
}
};

[$data, $hidden] = [
[$data, $hidden, $contextable] = [
(new Collection($context['data'] ?? []))->map(fn ($value, $key) => $unserialize($value, $key, false))->all(),
(new Collection($context['hidden'] ?? []))->map(fn ($value, $key) => $unserialize($value, $key, true))->all(),
(new Collection($context['contextables'] ?? []))->map(fn ($value, $key) => $unserialize($value, $key, false))->all(),
];

$this->events->dispatch(new Hydrated(
$this->flush()->add($data)->addHidden($hidden)
$this->flush()->add($data)->addHidden($hidden)->contextable($contextable)
));

return $this;
Expand Down
2 changes: 2 additions & 0 deletions tests/Integration/Log/ContextIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public function test_it_can_hydrate_null()
{
Context::hydrate(null);
$this->assertEquals([], Context::all());
$this->assertEquals([], Context::getContextables());
}

public function test_it_handles_eloquent()
Expand All @@ -37,6 +38,7 @@ public function test_it_handles_eloquent()
'number' => 'i:55;',
],
'hidden' => [],
'contextables' => [],
], $dehydrated);

Context::flush();
Expand Down
Binary file modified tests/Log/ContextTest.php
Binary file not shown.