Completed
Push — master ( a552ca...886306 )
by Benjamin
02:11
created

Logger::getDefaultContext()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
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 = "";
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
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
}
257