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