Completed
Pull Request — master (#65)
by Danny
02:50
created

Logger::createMessage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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