Passed
Push — master ( 2a1c3b...234454 )
by Benjamin
03:55 queued 01:54
created

Logger   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 231
Duplicated Lines 0 %

Test Coverage

Coverage 98.9%

Importance

Changes 0
Metric Value
eloc 70
dl 0
loc 231
ccs 90
cts 91
cp 0.989
rs 10
c 0
b 0
f 0
wmc 28

12 Methods

Rating   Name   Duplication   Size   Complexity  
A getDefaultContext() 0 3 1
A interpolate() 0 10 2
A setDefaultContext() 0 3 1
A setFacility() 0 3 1
A getFacility() 0 3 1
A __construct() 0 11 2
A getPublisher() 0 3 1
A log() 0 12 3
A setPublisher() 0 3 1
A initExceptionData() 0 20 2
B initContext() 0 30 10
A initMessage() 0 21 3
1
<?php
2
3
/*
4
 * This file is part of the php-gelf package.
5
 *
6
 * (c) Benjamin Zikarsky <http://benjamin-zikarsky.de>
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 Gelf;
13
14
use Gelf\Transport\UdpTransport;
15
use Psr\Log\LoggerInterface;
16
use Psr\Log\AbstractLogger;
17
use Exception;
18
19
/**
20
 * A basic PSR-3 compliant logger
21
 *
22
 * @author Benjamin Zikarsky <[email protected]>
23
 */
24
class Logger extends AbstractLogger implements LoggerInterface
25
{
26
    /**
27
     * @var string|null
28
     */
29
    protected $facility;
30
31
    /**
32
     * @var array
33
     */
34
    protected $defaultContext;
35
36
    /**
37
     * @var PublisherInterface
38
     */
39
    protected $publisher;
40
41
    /**
42
     * Creates a PSR-3 Logger for GELF/Graylog2
43
     *
44
     * @param PublisherInterface|null $publisher
45
     * @param string|null $facility
46
     * @param array $defaultContext
47
     */
48 16
    public function __construct(
49
        PublisherInterface $publisher = null,
50
        $facility = null,
51
        array $defaultContext = array()
52
    ) {
53
        // if no publisher is provided build a "default" publisher
54
        // which is logging via Gelf over UDP to localhost on the default port
55 16
        $this->publisher = $publisher ?: new Publisher(new UdpTransport());
56
57 16
        $this->setFacility($facility);
58 16
        $this->setDefaultContext($defaultContext);
59 16
    }
60
61
    /**
62
     * Publishes a given message and context with given level
63
     *
64
     * @param mixed $level
65
     * @param mixed $rawMessage
66
     * @param array $context
67
     */
68 14
    public function log($level, $rawMessage, array $context = array())
69
    {
70 14
        $message = $this->initMessage($level, $rawMessage, $context);
71
72
        // add exception data if present
73 14
        if (isset($context['exception'])
74 14
           && $context['exception'] instanceof Exception
75 14
        ) {
76 1
            $this->initExceptionData($message, $context['exception']);
77 1
        }
78
79 14
        $this->publisher->publish($message);
80 14
    }
81
82
    /**
83
     * Returns the currently used publisher
84
     *
85
     * @return PublisherInterface
86
     */
87 1
    public function getPublisher()
88
    {
89 1
        return $this->publisher;
90
    }
91
92
    /**
93
     * Sets a new publisher
94
     *
95
     * @param PublisherInterface $publisher
96
     */
97 1
    public function setPublisher(PublisherInterface $publisher)
98
    {
99 1
        $this->publisher = $publisher;
100 1
    }
101
102
    /**
103
     * Returns the faciilty-name used in GELF
104
     *
105
     * @return string|null
106
     */
107 1
    public function getFacility()
108
    {
109 1
        return $this->facility;
110
    }
111
112
    /**
113
     * Sets the facility for GELF messages
114
     *
115
     * @param string|null $facility
116
     */
117 16
    public function setFacility($facility = null)
118
    {
119 16
        $this->facility = $facility;
120 16
    }
121
122
    /**
123
     * @return array
124
     */
125 14
    public function getDefaultContext()
126
    {
127 14
        return $this->defaultContext;
128
    }
129
130
    /**
131
     * @param array $defaultContext
132
     */
133 16
    public function setDefaultContext($defaultContext)
134
    {
135 16
        $this->defaultContext = $defaultContext;
136 16
    }
137
138
    /**
139
     * Initializes message-object
140
     *
141
     * @param  mixed   $level
142
     * @param  mixed   $message
143
     * @param  array   $context
144
     * @return Message
145
     */
146 14
    protected function initMessage($level, $message, array $context)
147
    {
148
        // assert that message is a string, and interpolate placeholders
149 14
        $message = (string) $message;
150 14
        $context = $this->initContext($context);
151 14
        $message = self::interpolate($message, $context);
152
153
        // create message object
154 14
        $messageObj = new Message();
155 14
        $messageObj->setLevel($level);
156 14
        $messageObj->setShortMessage($message);
157 14
        $messageObj->setFacility($this->facility);
158
159 14
        foreach ($this->getDefaultContext() as $key => $value) {
160
            $messageObj->setAdditional($key, $value);
161 14
        }
162 14
        foreach ($context as $key => $value) {
163 11
            $messageObj->setAdditional($key, $value);
164 14
        }
165
166 14
        return $messageObj;
167
    }
168
169
    /**
170
     * Initializes context array, ensuring all values are string-safe
171
     *
172
     * @param array $context
173
     * @return array
174
     */
175 14
    protected function initContext($context)
176
    {
177 14
        foreach ($context as $key => &$value) {
178 11
            switch (gettype($value)) {
179 11
                case 'string':
180 11
                case 'integer':
181 11
                case 'double':
182
                    // These types require no conversion
183 3
                    break;
184 8
                case 'array':
185 8
                case 'boolean':
186 3
                    $value = json_encode($value);
187 3
                    break;
188 5
                case 'object':
189 3
                    if (method_exists($value, '__toString')) {
190 2
                        $value = (string)$value;
191 2
                    } else {
192 1
                        $value = '[object (' . get_class($value) . ')]';
193
                    }
194 3
                    break;
195 2
                case 'NULL':
196 1
                    $value = 'NULL';
197 1
                    break;
198 1
                default:
199 1
                    $value = '[' . gettype($value) . ']';
200 1
                    break;
201 11
            }
202 14
        }
203
204 14
        return $context;
205
    }
206
207
    /**
208
     * Initializes Exceptiondata with given message
209
     *
210
     * @param Message   $message
211
     * @param Exception $exception
212
     */
213 1
    protected function initExceptionData(Message $message, Exception $exception)
214
    {
215 1
        $message->setLine($exception->getLine());
216 1
        $message->setFile($exception->getFile());
217
218 1
        $longText = "";
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
219
220
        do {
221 1
            $longText .= sprintf(
222 1
                "%s: %s (%d)\n\n%s\n",
223 1
                get_class($exception),
224 1
                $exception->getMessage(),
225 1
                $exception->getCode(),
226 1
                $exception->getTraceAsString()
227 1
            );
228
229 1
            $exception = $exception->getPrevious();
230 1
        } while ($exception && $longText .= "\n--\n\n");
231
232 1
        $message->setFullMessage($longText);
233 1
    }
234
235
    /**
236
     * Interpolates context values into the message placeholders.
237
     *
238
     * Reference implementation
239
     * @link https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md#12-message
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 100 characters; contains 111 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
240
     *
241
     * @param mixed $message
242
     * @param array $context
243
     * @return string
244
     */
245 14
    private static function interpolate($message, array $context)
246
    {
247
        // build a replacement array with braces around the context keys
248 14
        $replace = array();
249 14
        foreach ($context as $key => $val) {
250 11
            $replace['{' . $key . '}'] = $val;
251 14
        }
252
253
        // interpolate replacement values into the message and return
254 14
        return strtr($message, $replace);
255
    }
256
}
0 ignored issues
show
Coding Style introduced by
As per coding style, files should not end with a newline character.

This check marks files that end in a newline character, i.e. an empy line.

Loading history...
257