Completed
Pull Request — master (#65)
by Danny
05:25
created

Logger::initExceptionData()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 21
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 3

Importance

Changes 2
Bugs 1 Features 1
Metric Value
c 2
b 1
f 1
dl 0
loc 21
ccs 15
cts 15
cp 1
rs 9.3142
cc 3
eloc 14
nc 1
nop 2
crap 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 PublisherInterface
33
     */
34
    protected $publisher;
35
36
    /**
37
     * Creates a PSR-3 Logger for GELF/Graylog2
38
     *
39
     * @param PublisherInterface|null $publisher
40
     * @param string|null             $facility
41
     */
42 16
    public function __construct(
43
        PublisherInterface $publisher = null,
44
        $facility = null
45
    ) {
46
        // if no publisher is provided build a "default" publisher
47
        // which is logging via Gelf over UDP to localhost on the default port
48 16
        $this->publisher = $publisher ?: new Publisher(new UdpTransport());
49
50 16
        $this->setFacility($facility);
51 16
    }
52
53
    /**
54
     * Publishes a given message and context with given level
55
     *
56
     * @param mixed $level
57
     * @param mixed $rawMessage
58
     * @param array $context
59
     */
60 14
    public function log($level, $rawMessage, array $context = array())
61
    {
62 14
        $message = $this->initMessage($level, $rawMessage, $context);
63
64
        // add exception data if present
65 14
        if (isset($context['exception'])
66 14
           && $context['exception'] instanceof Exception
67 14
        ) {
68 1
            $this->initExceptionData($message, $context['exception']);
69 1
        }
70
71 14
        $this->publisher->publish($message);
72 14
    }
73
74
    /**
75
     * Returns the currently used publisher
76
     *
77
     * @return PublisherInterface
78
     */
79 1
    public function getPublisher()
80
    {
81 1
        return $this->publisher;
82
    }
83
84
    /**
85
     * Sets a new publisher
86
     *
87
     * @param PublisherInterface $publisher
88
     */
89 1
    public function setPublisher(PublisherInterface $publisher)
90
    {
91 1
        $this->publisher = $publisher;
92 1
    }
93
94
    /**
95
     * Returns the faciilty-name used in GELF
96
     *
97
     * @return string|null
98
     */
99 1
    public function getFacility()
100
    {
101 1
        return $this->facility;
102
    }
103
104
    /**
105
     * Sets the facility for GELF messages
106
     *
107
     * @param string|null $facility
108
     */
109 16
    public function setFacility($facility = null)
110
    {
111 16
        $this->facility = $facility;
112 16
    }
113
114
    /**
115
     * @return Message
116
     */
117 14
    protected function createMessage()
118
    {
119 14
        return new Message();
120
    }
121
122
    /**
123
     * Initializes message-object
124
     *
125
     * @param  mixed   $level
126
     * @param  mixed   $message
127
     * @param  array   $context
128
     * @return Message
129
     */
130 14
    protected function initMessage($level, $message, array $context)
131
    {
132
        // assert that message is a string, and interpolate placeholders
133 14
        $message = (string) $message;
134 14
        $context = $this->initContext($context);
135 14
        $message = self::interpolate($message, $context);
136
137
        // create message object
138 14
        $messageObj = $this->createMessage();
139 14
        $messageObj->setLevel($level);
140 14
        $messageObj->setShortMessage($message);
141 14
        $messageObj->setFacility($this->facility);
142
143 14
        foreach ($context as $key => $value) {
144 11
            $messageObj->setAdditional($key, $value);
145 14
        }
146
147 14
        return $messageObj;
148
    }
149
150
    /**
151
     * Initializes context array, ensuring all values are string-safe
152
     *
153
     * @param array $context
154
     * @return array
155
     */
156 14
    protected function initContext($context)
157
    {
158 14
        foreach ($context as $key => &$value) {
159 11
            switch (gettype($value)) {
160 11
                case 'string':
161 11
                case 'integer':
162 11
                case 'double':
163
                    // These types require no conversion
164 3
                    break;
165 8
                case 'array':
166 8
                case 'boolean':
167 3
                    $value = json_encode($value);
168 3
                    break;
169 5
                case 'object':
170 3
                    if (method_exists($value, '__toString')) {
171 2
                        $value = (string)$value;
172 2
                    } else {
173 1
                        $value = '[object (' . get_class($value) . ')]';
174
                    }
175 3
                    break;
176 2
                case 'NULL':
177 1
                    $value = 'NULL';
178 1
                    break;
179 1
                default:
180 1
                    $value = '[' . gettype($value) . ']';
181 1
                    break;
182 11
            }
183 14
        }
184
185 14
        return $context;
186
    }
187
188
    /**
189
     * Initializes Exceptiondata with given message
190
     *
191
     * @param Message   $message
192
     * @param Exception $exception
193
     */
194 1
    protected function initExceptionData(Message $message, Exception $exception)
195
    {
196 1
        $message->setLine($exception->getLine());
197 1
        $message->setFile($exception->getFile());
198
199 1
        $longText = "";
200
201
        do {
202 1
            $longText .= sprintf(
203 1
                "%s: %s (%d)\n\n%s\n",
204 1
                get_class($exception),
205 1
                $exception->getMessage(),
206 1
                $exception->getCode(),
207 1
                $exception->getTraceAsString()
208 1
            );
209
210 1
            $exception = $exception->getPrevious();
211 1
        } while ($exception && $longText .= "\n--\n\n");
212
213 1
        $message->setFullMessage($longText);
214 1
    }
215
216
    /**
217
     * Interpolates context values into the message placeholders.
218
     *
219
     * Reference implementation
220
     * @link https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md#12-message
221
     *
222
     * @param mixed $message
223
     * @param array $context
224
     * @return string
225
     */
226 14
    private static function interpolate($message, array $context)
227
    {
228
        // build a replacement array with braces around the context keys
229 14
        $replace = array();
230 14
        foreach ($context as $key => $val) {
231 11
            $replace['{' . $key . '}'] = $val;
232 14
        }
233
234
        // interpolate replacement values into the message and return
235 14
        return strtr($message, $replace);
236
    }
237
}
238