Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 namespace Drupal\Core\Logger;
|
Chris@0
|
4
|
Chris@0
|
5 use Drupal\Core\Session\AccountInterface;
|
Chris@0
|
6 use Psr\Log\LoggerInterface;
|
Chris@0
|
7 use Psr\Log\LoggerTrait;
|
Chris@0
|
8 use Psr\Log\LogLevel;
|
Chris@0
|
9 use Symfony\Component\HttpFoundation\RequestStack;
|
Chris@0
|
10
|
Chris@0
|
11 /**
|
Chris@0
|
12 * Defines a logger channel that most implementations will use.
|
Chris@0
|
13 */
|
Chris@0
|
14 class LoggerChannel implements LoggerChannelInterface {
|
Chris@0
|
15 use LoggerTrait;
|
Chris@0
|
16
|
Chris@0
|
17 /**
|
Chris@0
|
18 * Maximum call depth to self::log() for a single log message.
|
Chris@0
|
19 *
|
Chris@0
|
20 * It's very easy for logging channel code to call out to other library code
|
Chris@0
|
21 * that will create log messages. In that case, we will recurse back in to
|
Chris@0
|
22 * LoggerChannel::log() multiple times while processing a single originating
|
Chris@0
|
23 * message. To prevent infinite recursion, we track the call depth and bail
|
Chris@0
|
24 * out at LoggerChannel::MAX_CALL_DEPTH iterations.
|
Chris@0
|
25 *
|
Chris@0
|
26 * @var int
|
Chris@0
|
27 */
|
Chris@0
|
28 const MAX_CALL_DEPTH = 5;
|
Chris@0
|
29
|
Chris@0
|
30 /**
|
Chris@0
|
31 * Number of times LoggerChannel::log() has been called for a single message.
|
Chris@0
|
32 *
|
Chris@0
|
33 * @var int
|
Chris@0
|
34 */
|
Chris@0
|
35 protected $callDepth = 0;
|
Chris@0
|
36
|
Chris@0
|
37 /**
|
Chris@0
|
38 * The name of the channel of this logger instance.
|
Chris@0
|
39 *
|
Chris@0
|
40 * @var string
|
Chris@0
|
41 */
|
Chris@0
|
42 protected $channel;
|
Chris@0
|
43
|
Chris@0
|
44 /**
|
Chris@0
|
45 * Map of PSR3 log constants to RFC 5424 log constants.
|
Chris@0
|
46 *
|
Chris@0
|
47 * @var array
|
Chris@0
|
48 */
|
Chris@0
|
49 protected $levelTranslation = [
|
Chris@0
|
50 LogLevel::EMERGENCY => RfcLogLevel::EMERGENCY,
|
Chris@0
|
51 LogLevel::ALERT => RfcLogLevel::ALERT,
|
Chris@0
|
52 LogLevel::CRITICAL => RfcLogLevel::CRITICAL,
|
Chris@0
|
53 LogLevel::ERROR => RfcLogLevel::ERROR,
|
Chris@0
|
54 LogLevel::WARNING => RfcLogLevel::WARNING,
|
Chris@0
|
55 LogLevel::NOTICE => RfcLogLevel::NOTICE,
|
Chris@0
|
56 LogLevel::INFO => RfcLogLevel::INFO,
|
Chris@0
|
57 LogLevel::DEBUG => RfcLogLevel::DEBUG,
|
Chris@0
|
58 ];
|
Chris@0
|
59
|
Chris@0
|
60 /**
|
Chris@0
|
61 * An array of arrays of \Psr\Log\LoggerInterface keyed by priority.
|
Chris@0
|
62 *
|
Chris@0
|
63 * @var array
|
Chris@0
|
64 */
|
Chris@0
|
65 protected $loggers = [];
|
Chris@0
|
66
|
Chris@0
|
67 /**
|
Chris@0
|
68 * The request stack object.
|
Chris@0
|
69 *
|
Chris@0
|
70 * @var \Symfony\Component\HttpFoundation\RequestStack
|
Chris@0
|
71 */
|
Chris@0
|
72 protected $requestStack;
|
Chris@0
|
73
|
Chris@0
|
74 /**
|
Chris@0
|
75 * The current user object.
|
Chris@0
|
76 *
|
Chris@0
|
77 * @var \Drupal\Core\Session\AccountInterface
|
Chris@0
|
78 */
|
Chris@0
|
79 protected $currentUser;
|
Chris@0
|
80
|
Chris@0
|
81 /**
|
Chris@0
|
82 * Constructs a LoggerChannel object
|
Chris@0
|
83 *
|
Chris@0
|
84 * @param string $channel
|
Chris@0
|
85 * The channel name for this instance.
|
Chris@0
|
86 */
|
Chris@0
|
87 public function __construct($channel) {
|
Chris@0
|
88 $this->channel = $channel;
|
Chris@0
|
89 }
|
Chris@0
|
90
|
Chris@0
|
91 /**
|
Chris@0
|
92 * {@inheritdoc}
|
Chris@0
|
93 */
|
Chris@0
|
94 public function log($level, $message, array $context = []) {
|
Chris@0
|
95 if ($this->callDepth == self::MAX_CALL_DEPTH) {
|
Chris@0
|
96 return;
|
Chris@0
|
97 }
|
Chris@0
|
98 $this->callDepth++;
|
Chris@0
|
99
|
Chris@0
|
100 // Merge in defaults.
|
Chris@0
|
101 $context += [
|
Chris@0
|
102 'channel' => $this->channel,
|
Chris@0
|
103 'link' => '',
|
Chris@0
|
104 'user' => NULL,
|
Chris@0
|
105 'uid' => 0,
|
Chris@0
|
106 'request_uri' => '',
|
Chris@0
|
107 'referer' => '',
|
Chris@0
|
108 'ip' => '',
|
Chris@0
|
109 'timestamp' => time(),
|
Chris@0
|
110 ];
|
Chris@0
|
111 // Some context values are only available when in a request context.
|
Chris@0
|
112 if ($this->requestStack && $request = $this->requestStack->getCurrentRequest()) {
|
Chris@0
|
113 $context['request_uri'] = $request->getUri();
|
Chris@0
|
114 $context['referer'] = $request->headers->get('Referer', '');
|
Chris@0
|
115 $context['ip'] = $request->getClientIP();
|
Chris@0
|
116 try {
|
Chris@0
|
117 if ($this->currentUser) {
|
Chris@0
|
118 $context['user'] = $this->currentUser;
|
Chris@0
|
119 $context['uid'] = $this->currentUser->id();
|
Chris@0
|
120 }
|
Chris@0
|
121 }
|
Chris@0
|
122 catch (\Exception $e) {
|
Chris@0
|
123 // An exception might be thrown if the database connection is not
|
Chris@0
|
124 // available or due to another unexpected reason. It is more important
|
Chris@0
|
125 // to log the error that we already have so any additional exceptions
|
Chris@0
|
126 // are ignored.
|
Chris@0
|
127 }
|
Chris@0
|
128 }
|
Chris@0
|
129
|
Chris@0
|
130 if (is_string($level)) {
|
Chris@0
|
131 // Convert to integer equivalent for consistency with RFC 5424.
|
Chris@0
|
132 $level = $this->levelTranslation[$level];
|
Chris@0
|
133 }
|
Chris@0
|
134 // Call all available loggers.
|
Chris@0
|
135 foreach ($this->sortLoggers() as $logger) {
|
Chris@0
|
136 $logger->log($level, $message, $context);
|
Chris@0
|
137 }
|
Chris@0
|
138
|
Chris@0
|
139 $this->callDepth--;
|
Chris@0
|
140 }
|
Chris@0
|
141
|
Chris@0
|
142 /**
|
Chris@0
|
143 * {@inheritdoc}
|
Chris@0
|
144 */
|
Chris@0
|
145 public function setRequestStack(RequestStack $requestStack = NULL) {
|
Chris@0
|
146 $this->requestStack = $requestStack;
|
Chris@0
|
147 }
|
Chris@0
|
148
|
Chris@0
|
149 /**
|
Chris@0
|
150 * {@inheritdoc}
|
Chris@0
|
151 */
|
Chris@0
|
152 public function setCurrentUser(AccountInterface $current_user = NULL) {
|
Chris@0
|
153 $this->currentUser = $current_user;
|
Chris@0
|
154 }
|
Chris@0
|
155
|
Chris@0
|
156 /**
|
Chris@0
|
157 * {@inheritdoc}
|
Chris@0
|
158 */
|
Chris@0
|
159 public function setLoggers(array $loggers) {
|
Chris@0
|
160 $this->loggers = $loggers;
|
Chris@0
|
161 }
|
Chris@0
|
162
|
Chris@0
|
163 /**
|
Chris@0
|
164 * {@inheritdoc}
|
Chris@0
|
165 */
|
Chris@0
|
166 public function addLogger(LoggerInterface $logger, $priority = 0) {
|
Chris@0
|
167 $this->loggers[$priority][] = $logger;
|
Chris@0
|
168 }
|
Chris@0
|
169
|
Chris@0
|
170 /**
|
Chris@0
|
171 * Sorts loggers according to priority.
|
Chris@0
|
172 *
|
Chris@0
|
173 * @return array
|
Chris@0
|
174 * An array of sorted loggers by priority.
|
Chris@0
|
175 */
|
Chris@0
|
176 protected function sortLoggers() {
|
Chris@0
|
177 $sorted = [];
|
Chris@0
|
178 krsort($this->loggers);
|
Chris@0
|
179
|
Chris@0
|
180 foreach ($this->loggers as $loggers) {
|
Chris@0
|
181 $sorted = array_merge($sorted, $loggers);
|
Chris@0
|
182 }
|
Chris@0
|
183 return $sorted;
|
Chris@0
|
184 }
|
Chris@0
|
185
|
Chris@0
|
186 }
|