-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLogProvider.php
More file actions
135 lines (116 loc) · 4.08 KB
/
LogProvider.php
File metadata and controls
135 lines (116 loc) · 4.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
<?php declare(strict_types=1);
namespace StellarWP\Foundation\Log;
use lucatume\DI52\Container;
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\AbstractHandler;
use Monolog\Handler\ErrorLogHandler;
use Monolog\Handler\FormattableHandlerInterface;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use Psr\Log\LoggerInterface;
use RuntimeException;
use StellarWP\Foundation\Container\Contracts\Provider;
use StellarWP\Foundation\Log\Formatters\ColoredLineFormatter;
use StellarWP\Foundation\Log\Handlers\NullHandler;
/**
* Default logging provider for consumers that want Foundation to wire logging for them.
*
* This provider is intentionally conservative: if the configured logging transport is
* unavailable, the application should keep running. Consumers that need different
* channels, handlers, or failure behavior can register their own provider instead.
*/
final class LogProvider extends Provider
{
public const string LOG_LEVEL = 'foundation.log.log_level';
public const string CHANNEL_ERRORLOG = 'errorlog';
private const string CHANNEL_CONSOLE = 'console';
private const string CHANNEL_NULL = 'null';
private const string CHANNEL_STACK = 'stack';
public const array CHANNELS = [
self::CHANNEL_CONSOLE => [
'class' => StreamHandler::class,
'formatter' => ColoredLineFormatter::class,
],
self::CHANNEL_ERRORLOG => [
'class' => ErrorLogHandler::class,
'formatter' => LineFormatter::class,
],
self::CHANNEL_STACK => [
self::CHANNEL_CONSOLE,
self::CHANNEL_ERRORLOG,
],
self::CHANNEL_NULL => [
'class' => NullHandler::class,
],
];
/**
* {@inheritDoc}
*/
public function register(): void {
$this->container->singleton(self::LOG_LEVEL, LogLevel::fromName($this->config->get('log.level', 'debug')));
$this->container->when(ColoredLineFormatter::class)
->needs('$dateFormat')
->give('Y-m-d H:i:s.v e');
$channel = $this->config->get('log.channel');
$this->container->singleton(
StreamHandler::class,
fn ($c) => new StreamHandler(
$this->config->get("log.channels.$channel.with.stream", 'php://stdout'),
$c->get(self::LOG_LEVEL)
)
);
$this->container->bind(
LoggerInterface::class,
static function (Container $c) use ($channel): LoggerInterface {
$handler = self::CHANNELS[$channel] ?? false;
if (! $handler) {
throw new RuntimeException(
sprintf(
'Invalid log channel. Valid options are: %s',
implode(',', array_keys(self::CHANNELS))
)
);
}
$logger = new Logger($channel);
/**
* @var array<array{handler: AbstractHandler, formatter: string|class-string}> $handlers
*/
$handlers = [];
// Single handler channel.
if (! empty($handler['class'])) {
if ($channel === self::CHANNEL_ERRORLOG && ! self::isErrorLogAvailable()) {
$handler = self::CHANNELS[self::CHANNEL_NULL];
}
$handlers[] = [
'handler' => $c->get($handler['class']),
'formatter' => $handler['formatter'] ?? '',
];
} else {
// We are on a stack channel, which uses multiple existing handlers.
foreach ($handler as $stackChannel) {
if ($stackChannel === self::CHANNEL_ERRORLOG && ! self::isErrorLogAvailable()) {
continue;
}
$handlers[] = [
'handler' => $c->get(self::CHANNELS[$stackChannel]['class']),
'formatter' => self::CHANNELS[$stackChannel]['formatter'],
];
}
}
/** @var array{handler: AbstractHandler, formatter: string|class-string} $registeredHandler */
foreach ($handlers as $registeredHandler) {
if (! empty($registeredHandler['formatter']) && $registeredHandler['handler'] instanceof FormattableHandlerInterface) {
$registeredHandler['handler']->setFormatter($c->get($registeredHandler['formatter']));
}
// Set the configured log level for each handler.
$registeredHandler['handler']->setLevel($c->get(self::LOG_LEVEL));
$logger->pushHandler($registeredHandler['handler']);
}
return $logger;
}
);
}
private static function isErrorLogAvailable(): bool {
return function_exists('error_log');
}
}