Logger::initContext()   B
last analyzed

Complexity

Conditions 10
Paths 10

Size

Total Lines 30
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 10

Importance

Changes 0
Metric Value
cc 10
eloc 23
c 0
b 0
f 0
nc 10
nop 1
dl 0
loc 30
rs 7.6666
ccs 8
cts 8
cp 1
crap 10

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
declare(strict_types=1);
3
4
/*
5
 * This file is part of the php-gelf package.
6
 *
7
 * (c) Benjamin Zikarsky <http://benjamin-zikarsky.de>
8
 *
9
 * For the full copyright and license information, please view the LICENSE
10
 * file that was distributed with this source code.
11
 */
12
13
namespace Gelf;
14
15
use Gelf\Transport\UdpTransport;
16
use Psr\Log\LoggerInterface;
17
use Psr\Log\AbstractLogger;
18
use Exception;
19
use Stringable;
20
21
/**
22
 * A basic PSR-3 compliant logger
23
 *
24
 * @author Benjamin Zikarsky <[email protected]>
25
 */
26
class Logger extends AbstractLogger implements LoggerInterface
27
{
28
    private PublisherInterface $publisher;
29
30
    /**
31
     * Creates a PSR-3 Logger for GELF/Graylog2
32
     */
33
    public function __construct(
34
        ?PublisherInterface $publisher = null,
35
        private array $defaultContext = []
36
    ) {
37
        // if no publisher is provided build a "default" publisher
38
        // which is logging via Gelf over UDP to localhost on the default port
39
        $this->publisher = $publisher ?? new Publisher(new UdpTransport());
40
    }
41
42
    /** @inheritDoc */
43
    public function log($level, $message, array $context = []): void
44
    {
45
        $messageObj = $this->initMessage($level, $message, $context);
46
47
        // add exception data if present
48 16
        if (isset($context['exception'])
49
           && $context['exception'] instanceof Exception
50
        ) {
51
            $this->initExceptionData($messageObj, $context['exception']);
52
        }
53
54
        $this->publisher->publish($messageObj);
55 16
    }
56
57 16
    /**
58 16
     * Returns the currently used publisher
59 16
     */
60
    public function getPublisher(): PublisherInterface
61
    {
62
        return $this->publisher;
63
    }
64
65
    /**
66
     * Sets a new publisher
67
     */
68 14
    public function setPublisher(PublisherInterface $publisher): void
69
    {
70 14
        $this->publisher = $publisher;
71
    }
72
73 14
    public function getDefaultContext(): array
74 14
    {
75
        return $this->defaultContext;
76 1
    }
77
78
    public function setDefaultContext(array $defaultContext): void
79 14
    {
80 14
        $this->defaultContext = $defaultContext;
81
    }
82
83
    /**
84
     * Initializes message-object
85
     */
86
    private function initMessage(mixed $level, string|Stringable $message, array $context): Message
87 1
    {
88
        // assert that message is a string, and interpolate placeholders
89 1
        $message = (string) $message;
90
        $context = $this->initContext($context);
91
        $message = self::interpolate($message, $context);
92
93
        // create message object
94
        $messageObj = new Message();
95
        $messageObj->setLevel($level);
96
        $messageObj->setShortMessage($message);
97 1
98
        foreach ($this->getDefaultContext() as $key => $value) {
99 1
            $messageObj->setAdditional($key, $value);
100 1
        }
101
        foreach ($context as $key => $value) {
102
            $messageObj->setAdditional($key, $value);
103
        }
104
105
        return $messageObj;
106
    }
107 1
108
    /**
109 1
     * Initializes context array, ensuring all values are string-safe
110
     */
111
    private function initContext(array $context): array
112
    {
113
        foreach ($context as &$value) {
114
            switch (gettype($value)) {
115
                case 'string':
116
                case 'integer':
117 16
                case 'double':
118
                    // These types require no conversion
119 16
                    break;
120 16
                case 'array':
121
                case 'boolean':
122
                    $value = json_encode($value);
123
                    break;
124
                case 'object':
125 14
                    if (method_exists($value, '__toString')) {
126
                        $value = (string)$value;
127 14
                    } else {
128
                        $value = '[object (' . get_class($value) . ')]';
129
                    }
130
                    break;
131
                case 'NULL':
132
                    $value = 'NULL';
133 16
                    break;
134
                default:
135 16
                    $value = '[' . gettype($value) . ']';
136 16
                    break;
137
            }
138
        }
139
140
        return $context;
141
    }
142
143
    /**
144
     * Initializes Exception-data with given message
145
     */
146 14
    private function initExceptionData(Message $message, Exception $exception): void
147
    {
148
        $message->setAdditional('line', $exception->getLine());
149 14
        $message->setAdditional('file', $exception->getFile());
150 14
151 14
        $longText = "";
152
153
        do {
154 14
            $longText .= sprintf(
155 14
                "%s: %s (%d)\n\n%s\n",
156 14
                get_class($exception),
157 14
                $exception->getMessage(),
158
                $exception->getCode(),
159 14
                $exception->getTraceAsString()
160
            );
161
162 14
            $exception = $exception->getPrevious();
163 11
        } while ($exception && $longText .= "\n--\n\n");
164
165
        $message->setFullMessage($longText);
166 14
    }
167
168
    /**
169
     * Interpolates context values into the message placeholders.
170
     *
171
     * Reference implementation
172
     * @link https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md#12-message
173
     */
174
    private static function interpolate(string|Stringable $message, array $context): string
175 14
    {
176
        // build a replacement array with braces around the context keys
177 14
        $replace = array();
178 11
        foreach ($context as $key => $val) {
179 11
            $replace['{' . $key . '}'] = $val;
180 10
        }
181 9
182
        // interpolate replacement values into the message and return
183 3
        return strtr((string)$message, $replace);
184 8
    }
185
}
186