Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php declare(strict_types=1);
2
 
3
/*
4
 * This file is part of the Monolog package.
5
 *
6
 * (c) Jordi Boggiano <j.boggiano@seld.be>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
 
12
namespace Monolog\Handler;
13
 
14
use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy;
15
use Monolog\Handler\FingersCrossed\ActivationStrategyInterface;
16
use Monolog\Logger;
17
use Monolog\ResettableInterface;
18
use Monolog\Formatter\FormatterInterface;
19
use Psr\Log\LogLevel;
20
 
21
/**
22
 * Buffers all records until a certain level is reached
23
 *
24
 * The advantage of this approach is that you don't get any clutter in your log files.
25
 * Only requests which actually trigger an error (or whatever your actionLevel is) will be
26
 * in the logs, but they will contain all records, not only those above the level threshold.
27
 *
28
 * You can then have a passthruLevel as well which means that at the end of the request,
29
 * even if it did not get activated, it will still send through log records of e.g. at least a
30
 * warning level.
31
 *
32
 * You can find the various activation strategies in the
33
 * Monolog\Handler\FingersCrossed\ namespace.
34
 *
35
 * @author Jordi Boggiano <j.boggiano@seld.be>
36
 *
37
 * @phpstan-import-type Record from \Monolog\Logger
38
 * @phpstan-import-type Level from \Monolog\Logger
39
 * @phpstan-import-type LevelName from \Monolog\Logger
40
 */
41
class FingersCrossedHandler extends Handler implements ProcessableHandlerInterface, ResettableInterface, FormattableHandlerInterface
42
{
43
    use ProcessableHandlerTrait;
44
 
45
    /**
46
     * @var callable|HandlerInterface
47
     * @phpstan-var callable(?Record, HandlerInterface): HandlerInterface|HandlerInterface
48
     */
49
    protected $handler;
50
    /** @var ActivationStrategyInterface */
51
    protected $activationStrategy;
52
    /** @var bool */
53
    protected $buffering = true;
54
    /** @var int */
55
    protected $bufferSize;
56
    /** @var Record[] */
57
    protected $buffer = [];
58
    /** @var bool */
59
    protected $stopBuffering;
60
    /**
61
     * @var ?int
62
     * @phpstan-var ?Level
63
     */
64
    protected $passthruLevel;
65
    /** @var bool */
66
    protected $bubble;
67
 
68
    /**
69
     * @psalm-param HandlerInterface|callable(?Record, HandlerInterface): HandlerInterface $handler
70
     *
71
     * @param callable|HandlerInterface              $handler            Handler or factory callable($record|null, $fingersCrossedHandler).
72
     * @param int|string|ActivationStrategyInterface $activationStrategy Strategy which determines when this handler takes action, or a level name/value at which the handler is activated
73
     * @param int                                    $bufferSize         How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
74
     * @param bool                                   $bubble             Whether the messages that are handled can bubble up the stack or not
75
     * @param bool                                   $stopBuffering      Whether the handler should stop buffering after being triggered (default true)
76
     * @param int|string                             $passthruLevel      Minimum level to always flush to handler on close, even if strategy not triggered
77
     *
78
     * @phpstan-param Level|LevelName|LogLevel::* $passthruLevel
79
     * @phpstan-param Level|LevelName|LogLevel::*|ActivationStrategyInterface $activationStrategy
80
     */
81
    public function __construct($handler, $activationStrategy = null, int $bufferSize = 0, bool $bubble = true, bool $stopBuffering = true, $passthruLevel = null)
82
    {
83
        if (null === $activationStrategy) {
84
            $activationStrategy = new ErrorLevelActivationStrategy(Logger::WARNING);
85
        }
86
 
87
        // convert simple int activationStrategy to an object
88
        if (!$activationStrategy instanceof ActivationStrategyInterface) {
89
            $activationStrategy = new ErrorLevelActivationStrategy($activationStrategy);
90
        }
91
 
92
        $this->handler = $handler;
93
        $this->activationStrategy = $activationStrategy;
94
        $this->bufferSize = $bufferSize;
95
        $this->bubble = $bubble;
96
        $this->stopBuffering = $stopBuffering;
97
 
98
        if ($passthruLevel !== null) {
99
            $this->passthruLevel = Logger::toMonologLevel($passthruLevel);
100
        }
101
 
102
        if (!$this->handler instanceof HandlerInterface && !is_callable($this->handler)) {
103
            throw new \RuntimeException("The given handler (".json_encode($this->handler).") is not a callable nor a Monolog\Handler\HandlerInterface object");
104
        }
105
    }
106
 
107
    /**
108
     * {@inheritDoc}
109
     */
110
    public function isHandling(array $record): bool
111
    {
112
        return true;
113
    }
114
 
115
    /**
116
     * Manually activate this logger regardless of the activation strategy
117
     */
118
    public function activate(): void
119
    {
120
        if ($this->stopBuffering) {
121
            $this->buffering = false;
122
        }
123
 
124
        $this->getHandler(end($this->buffer) ?: null)->handleBatch($this->buffer);
125
        $this->buffer = [];
126
    }
127
 
128
    /**
129
     * {@inheritDoc}
130
     */
131
    public function handle(array $record): bool
132
    {
133
        if ($this->processors) {
134
            /** @var Record $record */
135
            $record = $this->processRecord($record);
136
        }
137
 
138
        if ($this->buffering) {
139
            $this->buffer[] = $record;
140
            if ($this->bufferSize > 0 && count($this->buffer) > $this->bufferSize) {
141
                array_shift($this->buffer);
142
            }
143
            if ($this->activationStrategy->isHandlerActivated($record)) {
144
                $this->activate();
145
            }
146
        } else {
147
            $this->getHandler($record)->handle($record);
148
        }
149
 
150
        return false === $this->bubble;
151
    }
152
 
153
    /**
154
     * {@inheritDoc}
155
     */
156
    public function close(): void
157
    {
158
        $this->flushBuffer();
159
 
160
        $this->getHandler()->close();
161
    }
162
 
163
    public function reset()
164
    {
165
        $this->flushBuffer();
166
 
167
        $this->resetProcessors();
168
 
169
        if ($this->getHandler() instanceof ResettableInterface) {
170
            $this->getHandler()->reset();
171
        }
172
    }
173
 
174
    /**
175
     * Clears the buffer without flushing any messages down to the wrapped handler.
176
     *
177
     * It also resets the handler to its initial buffering state.
178
     */
179
    public function clear(): void
180
    {
181
        $this->buffer = [];
182
        $this->reset();
183
    }
184
 
185
    /**
186
     * Resets the state of the handler. Stops forwarding records to the wrapped handler.
187
     */
188
    private function flushBuffer(): void
189
    {
190
        if (null !== $this->passthruLevel) {
191
            $level = $this->passthruLevel;
192
            $this->buffer = array_filter($this->buffer, function ($record) use ($level) {
193
                return $record['level'] >= $level;
194
            });
195
            if (count($this->buffer) > 0) {
196
                $this->getHandler(end($this->buffer))->handleBatch($this->buffer);
197
            }
198
        }
199
 
200
        $this->buffer = [];
201
        $this->buffering = true;
202
    }
203
 
204
    /**
205
     * Return the nested handler
206
     *
207
     * If the handler was provided as a factory callable, this will trigger the handler's instantiation.
208
     *
209
     * @return HandlerInterface
210
     *
211
     * @phpstan-param Record $record
212
     */
213
    public function getHandler(array $record = null)
214
    {
215
        if (!$this->handler instanceof HandlerInterface) {
216
            $this->handler = ($this->handler)($record, $this);
217
            if (!$this->handler instanceof HandlerInterface) {
218
                throw new \RuntimeException("The factory callable should return a HandlerInterface");
219
            }
220
        }
221
 
222
        return $this->handler;
223
    }
224
 
225
    /**
226
     * {@inheritDoc}
227
     */
228
    public function setFormatter(FormatterInterface $formatter): HandlerInterface
229
    {
230
        $handler = $this->getHandler();
231
        if ($handler instanceof FormattableHandlerInterface) {
232
            $handler->setFormatter($formatter);
233
 
234
            return $this;
235
        }
236
 
237
        throw new \UnexpectedValueException('The nested handler of type '.get_class($handler).' does not support formatters.');
238
    }
239
 
240
    /**
241
     * {@inheritDoc}
242
     */
243
    public function getFormatter(): FormatterInterface
244
    {
245
        $handler = $this->getHandler();
246
        if ($handler instanceof FormattableHandlerInterface) {
247
            return $handler->getFormatter();
248
        }
249
 
250
        throw new \UnexpectedValueException('The nested handler of type '.get_class($handler).' does not support formatters.');
251
    }
252
}