Passed
Push — master ( 785bbf...2460fb )
by Bastien
01:48
created

DeamonLoggerExtraWebProcessor::addUserInfo()   B

Complexity

Conditions 7
Paths 4

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 7

Importance

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