Completed
Pull Request — master (#84)
by Pavel
08:52
created

Logger::initExceptionData()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 21
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 21
ccs 0
cts 15
cp 0
rs 9.3142
c 0
b 0
f 0
cc 3
eloc 14
nc 1
nop 2
crap 12
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
        if (isset($context['exception'])
66
           && $context['exception'] instanceof Exception
67
        ) {
68
            $this->initExceptionData($message, $context['exception']);
69
        }
70
71
        $this->publisher->publish($message);
72
    }
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
     * Initializes message-object
116
     *
117
     * @param  mixed   $level
118
     * @param  mixed   $message
119
     * @param  array   $context
120
     * @return Message
121
     */
122 14
    protected function initMessage($level, $message, array $context)
123
    {
124
        // assert that message is a string, and interpolate placeholders
125 14
        $message = (string) $message;
126 14
        $context = $this->initContext($context);
127 14
        $message = self::interpolate($message, $context);
128
129
        // create message object
130 14
        $messageObj = new Message();
131 14
        $messageObj->setLevel($level);
132
        $messageObj->setShortMessage($message);
133
        $messageObj->setFacility($this->facility);
134
135
        foreach ($context as $key => $value) {
136
            $messageObj->setAdditional($key, $value);
137
        }
138
139
        return $messageObj;
140
    }
141
142
    /**
143
     * Initializes context array, ensuring all values are string-safe
144
     *
145
     * @param array $context
146
     * @return array
147
     */
148 14
    protected function initContext($context)
149
    {
150 14
        foreach ($context as $key => &$value) {
151 11
            switch (gettype($value)) {
152 11
                case 'string':
153 11
                case 'integer':
154 11
                case 'double':
155
                    // These types require no conversion
156 3
                    break;
157 8
                case 'array':
158 8
                case 'boolean':
159 3
                    $value = json_encode($value);
160 3
                    break;
161 5
                case 'object':
162 3
                    if (method_exists($value, '__toString')) {
163 2
                        $value = (string)$value;
164 2
                    } else {
165 1
                        $value = '[object (' . get_class($value) . ')]';
166
                    }
167 3
                    break;
168 2
                case 'NULL':
169 1
                    $value = 'NULL';
170 1
                    break;
171 1
                default:
172 1
                    $value = '[' . gettype($value) . ']';
173 1
                    break;
174 11
            }
175 14
        }
176
177 14
        return $context;
178
    }
179
180
    /**
181
     * Initializes Exceptiondata with given message
182
     *
183
     * @param Message   $message
184
     * @param Exception $exception
185
     */
186
    protected function initExceptionData(Message $message, Exception $exception)
187
    {
188
        $message->setLine($exception->getLine());
189
        $message->setFile($exception->getFile());
190
191
        $longText = "";
192
193
        do {
194
            $longText .= sprintf(
195
                "%s: %s (%d)\n\n%s\n",
196
                get_class($exception),
197
                $exception->getMessage(),
198
                $exception->getCode(),
199
                $exception->getTraceAsString()
200
            );
201
202
            $exception = $exception->getPrevious();
203
        } while ($exception && $longText .= "\n--\n\n");
204
205
        $message->setFullMessage($longText);
206
    }
207
208
    /**
209
     * Interpolates context values into the message placeholders.
210
     *
211
     * Reference implementation
212
     * @link https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md#12-message
213
     *
214
     * @param mixed $message
215
     * @param array $context
216
     * @return string
217
     */
218 14
    private static function interpolate($message, array $context)
219
    {
220
        // build a replacement array with braces around the context keys
221 14
        $replace = array();
222 14
        foreach ($context as $key => $val) {
223 11
            $replace['{' . $key . '}'] = $val;
224 14
        }
225
226
        // interpolate replacement values into the message and return
227 14
        return strtr($message, $replace);
228
    }
229
}
230