Skip to content

Commit f6a9530

Browse files
committed
Added Context class
1 parent 746dfa4 commit f6a9530

4 files changed

Lines changed: 237 additions & 0 deletions

File tree

app/Config/Logger.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,24 @@ class Logger extends BaseConfig
5151
*/
5252
public string $dateFormat = 'Y-m-d H:i:s';
5353

54+
/**
55+
* --------------------------------------------------------------------------
56+
* Whether to log the global context
57+
* --------------------------------------------------------------------------
58+
*
59+
* You can enable/disable logging of global context data, which comes from the
60+
* `CodeIgniter\Context\Context` class. This data is automatically included in
61+
* logs, and can be set using the `set()` method of the Context class. This is
62+
* useful for including additional information in your logs, such as user IDs,
63+
* request IDs, etc.
64+
*
65+
* **NOTE:** This **DOES NOT** include any data that has been marked as hidden
66+
* using the `setHidden()` method of the Context class.
67+
*
68+
* @var bool
69+
*/
70+
public bool $logGlobalContext = false;
71+
5472
/**
5573
* --------------------------------------------------------------------------
5674
* Log Handlers

system/Config/Services.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use CodeIgniter\Cache\ResponseCache;
1919
use CodeIgniter\CLI\Commands;
2020
use CodeIgniter\CodeIgniter;
21+
use CodeIgniter\Context\Context;
2122
use CodeIgniter\Database\ConnectionInterface;
2223
use CodeIgniter\Database\MigrationRunner;
2324
use CodeIgniter\Debug\Exceptions;
@@ -872,4 +873,18 @@ public static function typography(bool $getShared = true)
872873

873874
return new Typography();
874875
}
876+
877+
/**
878+
* The Context class provides a way to store and retrieve static data throughout requests.
879+
*
880+
* @return Context
881+
*/
882+
public static function context(bool $getShared = true)
883+
{
884+
if ($getShared) {
885+
return static::getSharedInstance('context');
886+
}
887+
888+
return new Context();
889+
}
875890
}

system/Context/Context.php

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
<?php
2+
3+
namespace CodeIgniter\Context;
4+
5+
class Context
6+
{
7+
/**
8+
* The data stored in the context.
9+
*
10+
* @var array<string, mixed>
11+
*/
12+
protected array $data;
13+
14+
/**
15+
* The data that is stored, but not included in logs.
16+
*
17+
* @var array<string, mixed>
18+
*/
19+
private array $hiddenData;
20+
21+
/**
22+
* Constructor
23+
*/
24+
public function __construct()
25+
{
26+
$this->data = [];
27+
$this->hiddenData = [];
28+
}
29+
30+
/**
31+
* Set a key-value pair to the context.
32+
*
33+
* @param string|array<string, mixed> $key The key to identify the data. Can be a string or an array of key-value pairs.
34+
* @param mixed $value The value to be stored in the context.
35+
* @return $this
36+
*/
37+
public function set(string|array $key, mixed $value): self
38+
{
39+
if (is_array($key)) {
40+
$this->data = array_merge($this->data, $key);
41+
return $this;
42+
}
43+
44+
$this->data[$key] = $value;
45+
return $this;
46+
}
47+
48+
/**
49+
* Set a hidden key-value pair to the context. This data will not be included in logs.
50+
*
51+
* @param string|array<string, mixed> $key The key to identify the data. Can be a string or an array of key-value pairs.
52+
* @param mixed $value The value to be stored in the context.
53+
* @return $this
54+
*/
55+
public function setHidden(string|array $key, mixed $value): self
56+
{
57+
if (is_array($key)) {
58+
$this->hiddenData = array_merge($this->hiddenData, $key);
59+
return $this;
60+
}
61+
62+
$this->hiddenData[$key] = $value;
63+
return $this;
64+
}
65+
66+
/**
67+
* Get a value from the context by its key, or return a default value if the key does not exist.
68+
*
69+
* @param string $key The key to identify the data.
70+
* @param mixed|null $default The default value to return if the key does not exist in the context.
71+
* @return mixed The value associated with the key, or the default value if the key does not exist.
72+
*/
73+
public function get(string $key, mixed $default = null): mixed
74+
{
75+
return $this->data[$key] ?? $default;
76+
}
77+
78+
/**
79+
* Get all data from the context
80+
*
81+
* @return array<string, mixed> An array of all key-value pairs in the context.
82+
*/
83+
public function getAll(): array
84+
{
85+
return $this->data;
86+
}
87+
88+
/**
89+
* Get a hidden value from the context by its key, or return a default value if the key does not exist.
90+
*
91+
* @param string $key The key to identify the data.
92+
* @param mixed|null $default The default value to return if the key does not exist in the context.
93+
* @return mixed The value associated with the key, or the default value if the key does not exist.
94+
*/
95+
public function getHidden(string $key, mixed $default = null): mixed
96+
{
97+
return $this->hiddenData[$key] ?? $default;
98+
}
99+
100+
/**
101+
* Get all hidden data from the context
102+
*
103+
* @return array<string, mixed> An array of all key-value pairs in the hidden context.
104+
*/
105+
public function getAllHidden(): array
106+
{
107+
return $this->hiddenData;
108+
}
109+
110+
/**
111+
* Check if a key exists in the context.
112+
*
113+
* @param string $key The key to check for existence in the context.
114+
* @return bool True if the key exists in the context, false otherwise.
115+
*/
116+
public function has(string $key): bool
117+
{
118+
return array_key_exists($key, $this->data);
119+
}
120+
121+
/**
122+
* Check if a key exists in the hidden context.
123+
*
124+
* @param string $key The key to check for existence in the hidden context.
125+
* @return bool True if the key exists in the hidden context, false otherwise.
126+
*/
127+
public function hasHidden(string $key): bool
128+
{
129+
return array_key_exists($key, $this->hiddenData);
130+
}
131+
132+
/**
133+
* Remove a key-value pair from the context by its key.
134+
*
135+
* @param string $key The key to identify the data to be removed from the context.
136+
* @return $this
137+
*/
138+
public function remove(string $key): self
139+
{
140+
unset($this->data[$key]);
141+
return $this;
142+
}
143+
144+
/**
145+
* Remove a key-value pair from the hidden context by its key.
146+
*
147+
* @param string $key The key to identify the data to be removed from the hidden context.
148+
* @return $this
149+
*/
150+
public function removeHidden(string $key): self
151+
{
152+
unset($this->hiddenData[$key]);
153+
return $this;
154+
}
155+
156+
/**
157+
* Clear all data from the context, including hidden data.
158+
*
159+
* @return $this
160+
*/
161+
public function clearAll(): self
162+
{
163+
$this->clear();
164+
$this->clearHidden();
165+
return $this;
166+
}
167+
168+
/**
169+
* Clear all data from the context.
170+
*
171+
* @return $this
172+
*/
173+
public function clear(): self
174+
{
175+
$this->data = [];
176+
return $this;
177+
}
178+
179+
/**
180+
* Clear all hidden data from the context.
181+
*
182+
* @return $this
183+
*/
184+
public function clearHidden(): self
185+
{
186+
$this->hiddenData = [];
187+
return $this;
188+
}
189+
}

system/Log/Logger.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,15 @@ class Logger implements LoggerInterface
114114
*/
115115
protected $cacheLogs = false;
116116

117+
/**
118+
* Whether to log the global context data.
119+
*
120+
* Set in app/Config/Logger.php
121+
*
122+
* @var bool
123+
*/
124+
protected $logGlobalContext;
125+
117126
/**
118127
* Constructor.
119128
*
@@ -154,6 +163,8 @@ public function __construct($config, bool $debug = CI_DEBUG)
154163
if ($this->cacheLogs) {
155164
$this->logCache = [];
156165
}
166+
167+
$this->logGlobalContext = $config->logGlobalContext;
157168
}
158169

159170
/**
@@ -252,6 +263,10 @@ public function log($level, string|Stringable $message, array $context = []): vo
252263

253264
$message = $this->interpolate($message, $context);
254265

266+
if ($this->logGlobalContext) {
267+
$message .= ' ' . json_encode(service('context')->getAll());
268+
}
269+
255270
if ($this->cacheLogs) {
256271
$this->logCache[] = ['level' => $level, 'msg' => $message];
257272
}

0 commit comments

Comments
 (0)