Test Failed
Push — master ( 17a475...dbbd8f )
by Bastien
01:46
created

DeamonLoggerExtraWebProcessor::onKernelRequest()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 0
cts 5
cp 0
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 6
1
<?php
2
3
namespace Deamon\LoggerExtraBundle\Processors\Monolog;
4
5
use Deamon\LoggerExtraBundle\Services\DeamonLoggerExtraContext;
6
use Monolog\Processor\WebProcessor as BaseWebProcessor;
7
use Symfony\Component\HttpFoundation\Request;
8
use Symfony\Component\HttpFoundation\RequestStack;
9
use Symfony\Component\HttpKernel\Event\RequestEvent;
10
use Symfony\Component\HttpKernel\KernelEvents;
11
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
12
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
13
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
14
use Symfony\Component\Security\Core\User\UserInterface;
15
16
class DeamonLoggerExtraWebProcessor extends BaseWebProcessor
17
{
18
    /**
19
     * @var string
20
     */
21
    private $environment = null;
22
23
    /**
24
     * @var DeamonLoggerExtraContext
25
     */
26
    private $loggerExtraContext = null;
27
28
    /**
29
     * @var TokenStorageInterface
30
     */
31
    private $tokenStorage = null;
32
33
    /**
34
     * @var RequestStack
35
     */
36
    private $requestStack = null;
37
38
    /**
39
     * @var array|null
40
     */
41
    private $displayConfig;
42
43
    /**
44
     * @var string
45
     */
46
    private $channelPrefix;
47
48
    /** @var string */
49
    private $userClass;
50
51
    /** @var array */
52
    private $userMethods;
53
54
    /**
55
     * @var array
56
     */
57
    private $record;
58
59 10
    public function __construct(?array $config = null)
60
    {
61 10
        parent::__construct([]);
62 10
        $this->channelPrefix = $config['channel_prefix'];
63 10
        $this->displayConfig = $config['display'];
64 10
        $this->userClass = $config['user_class'];
65 10
        $this->userMethods = $config['user_methods'];
66 10
    }
67
68
    /**
69
     * @param array $record
70
     *
71
     * @return array
72
     */
73 10
    public function __invoke(array $record)
74
    {
75 10
        $this->record = parent::__invoke($record);
76
77 10
        $this->addContextInfo();
78 10
        $this->addRequestInfo();
79 10
        $this->addUserInfo();
80 10
        $this->addChannelInfo();
81
82 10
        return $this->record;
83
    }
84
85
    /**
86
     * Add extra info about the context of the generated log.
87
     */
88 10
    private function addContextInfo(): void
89
    {
90 10
        if (null !== $this->environment) {
91 2
            $this->addInfo('env', $this->environment);
92
        }
93
94 10
        if (null !== $this->loggerExtraContext) {
95 2
            $this->addInfo('locale', $this->loggerExtraContext->getLocale());
96 2
            if ($this->configShowExtraInfo('application_name')) {
97 2
                $this->record['extra']['application'] = $this->loggerExtraContext->getApplicationName();
98
            }
99
        }
100 10
    }
101
102
    /**
103
     * Add extra info about the request generating the log.
104
     */
105 10
    private function addRequestInfo(): void
106
    {
107 10
        if (null !== $this->requestStack) {
108 1
            $request = $this->requestStack->getCurrentRequest();
109 1
            if ($request instanceof Request) {
110 1
                $this->addInfo('url', $request->getRequestUri());
111 1
                $this->addInfo('route', $request->get('_route'));
112 1
                $this->addInfo('user_agent', $request->server->get('HTTP_USER_AGENT'));
113 1
                $this->addInfo('accept_encoding', $request->headers->get('Accept-Encoding'));
114 1
                $this->addInfo('client_ip', $request->getClientIp());
115
            }
116
        }
117 10
    }
118
119
    /**
120
     * Add extra info on the user generating the log.
121
     */
122 10
    private function addUserInfo(): void
123
    {
124 10
        if (!$this->configShowExtraInfo('user')) {
125 6
            return;
126
        }
127
128 4
        if (!class_exists($this->userClass) && !interface_exists($this->userClass)) {
129 1
            return;
130
        }
131
132 3
        if (!$this->tokenStorage instanceof TokenStorage) {
133 1
            return;
134
        }
135
136 2
        $token = $this->tokenStorage->getToken();
137 2
        if ($this->isUserInstanceValid($token) && null !== $user = $token->getUser()) {
138 1
            $this->appendUserMethodInfo($user);
139
        }
140 2
    }
141
142
    /**
143
     * append method result of user object.
144
     *
145
     * @param UserInterface $user
146
     */
147 1
    private function appendUserMethodInfo(UserInterface $user): void
148
    {
149 1
        foreach ($this->userMethods as $name => $method) {
150 1
            if (method_exists($user, $method)) {
151 1
                $this->record['extra'][$name] = $user->$method();
152
            }
153
        }
154 1
    }
155
156
    /**
157
     * Check if passed token is an instance of TokenInterface and an instance of config UserClass.
158
     *
159
     * @param TokenInterface|null $token
160
     *
161
     * @return bool
162
     */
163 2
    private function isUserInstanceValid(?TokenInterface $token): bool
164
    {
165 2
        return $token instanceof TokenInterface && $token->getUser() instanceof $this->userClass;
166
    }
167
168
    /**
169
     * Add channel info to ease the log interpretation.
170
     */
171 10
    private function addChannelInfo(): void
172
    {
173 10
        if(!array_key_exists('global_channel', $this->record['extra'])){
174 10
            $this->addInfo('global_channel', $this->record['channel']);
175
        }
176
177 10
        if ($this->channelPrefix !== null && substr($this->record['channel'], 0, strlen($this->channelPrefix)) !== $this->channelPrefix) {
178 1
            $this->record['channel'] = sprintf('%s.%s', $this->channelPrefix, $this->record['channel']);
179
        }
180 10
    }
181
182
    /**
183
     * Add the extra info if configured to.
184
     *
185
     * @param string $key
186
     * @param mixed  $value
187
     */
188 10
    private function addInfo(string $key, $value): void
189
    {
190 10
        if ($this->configShowExtraInfo($key) && $value !== null) {
191 5
            $this->record['extra'][$key] = $value;
192
        }
193 10
    }
194
195
    /**
196
     * Tells if the config to display the extra info is enabled or not.
197
     *
198
     * @param string $extraInfo
199
     *
200
     * @return bool
201
     */
202 10
    private function configShowExtraInfo(string $extraInfo): bool
203
    {
204 10
        return isset($this->displayConfig[$extraInfo]) && $this->displayConfig[$extraInfo];
205
    }
206
207
    public function onKernelRequest(RequestEvent $event)
208
    {
209
        if ($event->isMasterRequest()) {
210
            $this->serverData = $event->getRequest()->server->all();
211
            $this->serverData['REMOTE_ADDR'] = $event->getRequest()->getClientIp();
212
        }
213
    }
214
215
    public static function getSubscribedEvents()
216
    {
217
        return [
218
            KernelEvents::REQUEST => ['onKernelRequest', 4096],
219
        ];
220
    }
221
222
    /**
223
     * @param DeamonLoggerExtraContext $loggerExtraContext
224
     */
225 2
    public function setLoggerExtraContext(DeamonLoggerExtraContext $loggerExtraContext): void
226
    {
227 2
        $this->loggerExtraContext = $loggerExtraContext;
228 2
    }
229
230
    /**
231
     * @param string $environment
232
     */
233 2
    public function setEnvironment(string $environment): void
234
    {
235 2
        $this->environment = $environment;
236 2
    }
237
238
    /**
239
     * @param TokenStorageInterface $tokenStorage
240
     */
241 2
    public function setTokenStorage(TokenStorageInterface $tokenStorage): void
242
    {
243 2
        $this->tokenStorage = $tokenStorage;
244 2
    }
245
246
    /**
247
     * @param RequestStack $requestStack
248
     */
249 1
    public function setRequestStack(RequestStack $requestStack): void
250
    {
251 1
        $this->requestStack = $requestStack;
252 1
    }
253
}
254