LogManager::error()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is part of the dingtalk.
4
 * User: Ilham Tahir <[email protected]>
5
 * This source file is subject to the MIT license that is bundled
6
 * with this source code in the file LICENSE.
7
 */
8
9
namespace Aplisin\DingTalk\Kernel\Log;
10
11
use Aplisin\DingTalk\Kernel\ServiceContainer;
12
use Psr\Log\LoggerInterface;
13
use Monolog\Logger as Monolog;
14
use Monolog\Formatter\LineFormatter;
15
use Monolog\Handler\ErrorLogHandler;
16
use Monolog\Handler\HandlerInterface;
17
use Monolog\Handler\RotatingFileHandler;
18
use Monolog\Handler\SlackWebhookHandler;
19
use Monolog\Handler\StreamHandler;
20
use Monolog\Handler\SyslogHandler;
21
22
class LogManager implements LoggerInterface
23
{
24
    /**
25
     * @var ServiceContainer
26
     */
27
    protected $app;
28
29
    /**
30
     * @var array
31
     */
32
    protected $channels = [];
33
34
    protected $customCreators = [];
35
36
    protected $levels = [
37
        'debug' => Monolog::DEBUG,
38
        'info' => Monolog::INFO,
39
        'notice' => Monolog::NOTICE,
40
        'warning' => Monolog::WARNING,
41
        'error' => Monolog::ERROR,
42
        'critical' => Monolog::CRITICAL,
43
        'alert' => Monolog::ALERT,
44
        'emergency' => Monolog::EMERGENCY,
45
    ];
46
47
    /**
48
     * LogManager constructor.
49
     * @param ServiceContainer $app
50
     */
51
    public function __construct(ServiceContainer $app)
52
    {
53
        $this->app = $app;
54
    }
55
56
    /**
57
     * @param array $channels
58
     * @param null $channel
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $channel is correct as it would always require null to be passed?
Loading history...
59
     * @return LoggerInterface
60
     */
61
    public function stack(array $channels, $channel = null)
62
    {
63
        return $this->createStackDriver(compact('channels', 'channel'));
64
    }
65
66
    public function channel($channel = null)
67
    {
68
        return $this->get($channel);
69
    }
70
71
    public function driver($driver = null)
72
    {
73
        return $this->get($driver ?? $this->getDefaultDriver());
74
    }
75
76
    /**
77
     * @param $name
78
     * @return LoggerInterface
79
     */
80
    protected function get($name)
81
    {
82
        try {
83
            return $this->channels[$name] ?? ($this->channels[$name] = $this->resolve($name));
84
        } catch (\Throwable $e) {
85
            $logger = $this->createEmergencyLogger();
86
87
            $logger->emergency('Unable to create configured logger. Using emergency logger.', [
88
                'exception' => $e,
89
            ]);
90
91
            return $logger;
92
        }
93
    }
94
95
    protected function resolve($name)
96
    {
97
        $config = $this->app['config']->get(\sprintf('log.channels.%s', $name));
98
99
        if (is_null($config)) {
100
            throw new \InvalidArgumentException(\sprintf('Log [%s] is not defined.', $name));
101
        }
102
103
        if (isset($this->customCreators[$config['driver']])) {
104
            return $this->callCustomCreator($config);
105
        }
106
107
        $driverMethod = 'create'.ucfirst($config['driver']).'Driver';
108
109
        if (method_exists($this, $driverMethod)) {
110
            return $this->{$driverMethod}($config);
111
        }
112
113
        throw new \InvalidArgumentException(\sprintf('Driver [%s] is not supported.', $config['driver']));
114
    }
115
116
    /**
117
     * @return Monolog
118
     * @throws \Exception
119
     */
120
    protected function createEmergencyLogger()
121
    {
122
        return new Monolog('AplisinDingTalk', $this->prepareHandlers([
123
            new StreamHandler(\sys_get_temp_dir().'/dingtalk/dingtalk.log', $this->level(['level' => 'debug']))
124
        ]));
125
    }
126
127
    protected function callCustomCreator(array $config)
128
    {
129
        return $this->customCreators[$config['driver']]($this->app, $config);
130
    }
131
132
    protected function createStackDriver(array $config)
133
    {
134
        $handlers = [];
135
136
        foreach ($config['channels'] ?? [] as $channel) {
137
            $handlers = \array_merge($handlers, $this->channel($channel)->getHandlers());
0 ignored issues
show
Bug introduced by
The method getHandlers() does not exist on Psr\Log\LoggerInterface. It seems like you code against a sub-type of said class. However, the method does not exist in Psr\Log\AbstractLogger or Psr\Log\NullLogger. Are you sure you never get one of those? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

137
            $handlers = \array_merge($handlers, $this->channel($channel)->/** @scrutinizer ignore-call */ getHandlers());
Loading history...
138
        }
139
140
        return new Monolog($this->parseChannel($config), $handlers);
141
    }
142
143
    protected function createSingleDriver(array $config)
144
    {
145
        return new Monolog($this->parseChannel($config), [
146
            $this->prepareHandler(
147
                new StreamHandler($config['path'], $this->level($config))
148
            ),
149
        ]);
150
    }
151
152
    protected function createDailyDriver(array $config)
153
    {
154
        return new Monolog($this->parseChannel($config), [
155
            $this->prepareHandler(
156
                new RotatingFileHandler(
157
                    $config['path'],
158
                    $config['days'] ?? 7,
159
                    $this->level($config)
160
                )
161
            ),
162
        ]);
163
    }
164
165
    protected function createSlackDriver(array $config)
166
    {
167
        return new Monolog($this->parseChannel($config), [
168
            $this->prepareHandler(new SlackWebhookHandler(
169
                $config['url'],
170
                $config['channel'] ?? null,
171
                $config['username'] ?? 'AplisinDingTalk',
172
                $config['attachment'] ?? true,
173
                $config['emoji'] ?? ':boom:',
174
                $config['short'] ?? false,
175
                $config['context'] ?? true,
176
                $this->level($config)
177
            )),
178
        ]);
179
    }
180
181
    protected function createSyslogDriver(array $config)
182
    {
183
        return new Monolog($this->parseChannel($config), [
184
            $this->prepareHandler(
185
                new SyslogHandler(
186
                    'AplisinDingTalk',
187
                    $config['facility'] ?? LOG_USER,
188
                    $this->level($config)
189
                )
190
            ),
191
        ]);
192
    }
193
194
    protected function createErrorlogDriver(array $config)
195
    {
196
        return new Monolog($this->parseChannel($config), [
197
            $this->prepareHandler(
198
                new ErrorLogHandler(
199
                    $config['type'] ?? ErrorLogHandler::OPERATING_SYSTEM,
200
                    $this->level($config)
201
                )
202
            ),
203
        ]);
204
    }
205
206
    protected function prepareHandlers(array $handlers)
207
    {
208
        foreach ($handlers as $key => $handler) {
209
            $handlers[$key] = $this->prepareHandler($handler);
210
        }
211
212
        return $handlers;
213
    }
214
215
    protected function prepareHandler(HandlerInterface $handler)
216
    {
217
        return $handler->setFormatter($this->formatter());
218
    }
219
220
    protected function formatter()
221
    {
222
        $formatter = new LineFormatter(null, null, true, true);
223
        $formatter->includeStacktraces();
224
225
        return $formatter;
226
    }
227
228
    protected function parseChannel(array $config)
229
    {
230
        return $config['name'] ?? null;
231
    }
232
233
    protected function level(array $config)
234
    {
235
        $level = $config['level'] ?? 'debug';
236
237
        if (isset($this->levels[$level])) {
238
            return $this->levels[$level];
239
        }
240
241
        throw new \InvalidArgumentException('Invalid log level.');
242
    }
243
244
    public function getDefaultDriver()
245
    {
246
        return $this->app['config']['log.default'];
247
    }
248
249
    public function setDefaultDriver($name)
250
    {
251
        $this->app['config']['log.default'] = $name;
252
    }
253
254
    public function extend($driver, \Closure $callback)
255
    {
256
        $this->customCreators[$driver] = $callback->bindTo($this, $this);
257
258
        return $this;
259
    }
260
261
    public function emergency($message, array $context = [])
262
    {
263
        return $this->driver()->emergency($message, $context);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->driver()->emergency($message, $context) targeting Psr\Log\LoggerInterface::emergency() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
264
    }
265
266
    public function alert($message, array $context = [])
267
    {
268
        return $this->driver()->alert($message, $context);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->driver()->alert($message, $context) targeting Psr\Log\LoggerInterface::alert() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
269
    }
270
271
    public function critical($message, array $context = [])
272
    {
273
        return $this->driver()->critical($message, $context);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->driver()->critical($message, $context) targeting Psr\Log\LoggerInterface::critical() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
274
    }
275
276
    public function error($message, array $context = [])
277
    {
278
        return $this->driver()->error($message, $context);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->driver()->error($message, $context) targeting Psr\Log\LoggerInterface::error() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
279
    }
280
281
    public function warning($message, array $context = [])
282
    {
283
        return $this->driver()->warning($message, $context);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->driver()->warning($message, $context) targeting Psr\Log\LoggerInterface::warning() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
284
    }
285
286
    public function notice($message, array $context = [])
287
    {
288
        return $this->driver()->notice($message, $context);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->driver()->notice($message, $context) targeting Psr\Log\LoggerInterface::notice() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
289
    }
290
291
    public function info($message, array $context = [])
292
    {
293
        return $this->driver()->info($message, $context);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->driver()->info($message, $context) targeting Psr\Log\LoggerInterface::info() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
294
    }
295
296
    public function debug($message, array $context = [])
297
    {
298
        return $this->driver()->debug($message, $context);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->driver()->debug($message, $context) targeting Psr\Log\LoggerInterface::debug() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
299
    }
300
301
    public function log($level, $message, array $context = [])
302
    {
303
        return $this->driver()->log($level, $message, $context);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->driver()->log($level, $message, $context) targeting Psr\Log\LoggerInterface::log() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
304
    }
305
306
    public function __call($method, $parameters)
307
    {
308
        return $this->driver()->$method(...$parameters);
309
    }
310
}
311