dc57f15163729966b5c2055d13f87f062bafec31
[friendica.git/.git] / src / Util / Logger / SyslogLogger.php
1 <?php
2
3 namespace Friendica\Util\Logger;
4
5 use Friendica\Network\HTTPException\InternalServerErrorException;
6 use Psr\Log\InvalidArgumentException;
7 use Psr\Log\LoggerInterface;
8 use Psr\Log\LogLevel;
9
10 /**
11  * A Logger instance for syslogging (fast, but simple)
12  * @see http://php.net/manual/en/function.syslog.php
13  */
14 class SyslogLogger implements LoggerInterface
15 {
16         const IDENT = 'Friendica';
17
18         /**
19          * Translates LogLevel log levels to syslog log priorities.
20          */
21         private $logLevels = [
22                 LogLevel::DEBUG     => LOG_DEBUG,
23                 LogLevel::INFO      => LOG_INFO,
24                 LogLevel::NOTICE    => LOG_NOTICE,
25                 LogLevel::WARNING   => LOG_WARNING,
26                 LogLevel::ERROR     => LOG_ERR,
27                 LogLevel::CRITICAL  => LOG_CRIT,
28                 LogLevel::ALERT     => LOG_ALERT,
29                 LogLevel::EMERGENCY => LOG_EMERG,
30         ];
31
32         /**
33          * The standard ident of the syslog (added to each message)
34          * @var string
35          */
36         private $channel;
37
38         /**
39          * Indicates what logging options will be used when generating a log message
40          * @see http://php.net/manual/en/function.openlog.php#refsect1-function.openlog-parameters
41          *
42          * @var int
43          */
44         private $logOpts;
45
46         /**
47          * Used to specify what type of program is logging the message
48          * @see http://php.net/manual/en/function.openlog.php#refsect1-function.openlog-parameters
49          *
50          * @var int
51          */
52         private $logFacility;
53
54         /**
55          * The minimum loglevel at which this logger will be triggered
56          * @var int
57          */
58         private $logLevel;
59
60         /**
61          * The Introspector for the current call
62          * @var Introspection
63          */
64         private $introspection;
65
66         /**
67          * @param string $channel     The output channel
68          * @param string $level    The minimum loglevel at which this logger will be triggered
69          * @param int    $logOpts     Indicates what logging options will be used when generating a log message
70          * @param int    $logFacility Used to specify what type of program is logging the message
71          *
72          * @throws InternalServerErrorException if the loglevel isn't valid
73          */
74         public function __construct($channel, Introspection $introspection, $level = LogLevel::NOTICE, $logOpts = LOG_PID, $logFacility = LOG_USER)
75         {
76                 $this->channel = $channel;
77                 $this->logOpts = $logOpts;
78                 $this->logFacility = $logFacility;
79                 $this->logLevel = $this->mapLevelToPriority($level);
80                 $this->introspection = $introspection;
81         }
82
83         /**
84          * Maps the LogLevel (@see LogLevel ) to a SysLog priority (@see http://php.net/manual/en/function.syslog.php#refsect1-function.syslog-parameters )
85          *
86          * @param string $level A LogLevel
87          *
88          * @return int The SysLog priority
89          *
90          * @throws \Psr\Log\InvalidArgumentException If the loglevel isn't valid
91          */
92         public function mapLevelToPriority($level)
93         {
94                 if (!array_key_exists($level, $this->logLevels)) {
95                         throw new InvalidArgumentException('LogLevel \'' . $level . '\' isn\'t valid.');
96                 }
97
98                 return $this->logLevels[$level];
99         }
100
101         /**
102          * Writes a message to the syslog
103          *
104          * @param int    $priority The Priority ( @see http://php.net/manual/en/function.syslog.php#refsect1-function.syslog-parameters )
105          * @param string $message The message of the log
106          * @throws InternalServerErrorException if syslog cannot be used
107          */
108         private function write($priority, $message)
109         {
110                 if (!openlog(self::IDENT, $this->logOpts, $this->logFacility)) {
111                         throw new InternalServerErrorException('Can\'t open syslog for ident "' . $this->channel . '" and facility "' . $this->logFacility . '""');
112                 }
113
114                 syslog($priority, $message);
115         }
116
117         /**
118          * Closes the Syslog
119          */
120         public function close()
121         {
122                 closelog();
123         }
124
125         /**
126          * Formats a log record for the syslog output
127          *
128          * @param int $level The loglevel/priority
129          * @param string $message The message
130          * @param array $context  The context of this call
131          *
132          * @return string the formatted syslog output
133          */
134         private function formatLog($level, $message, $context = [])
135         {
136                 $logMessage  = '';
137
138                 $logMessage .= $this->channel . ' ';
139                 $logMessage .= '[' . $level . ']: ';
140                 $logMessage .= $message . ' ';
141                 $logMessage .= json_encode($context) . ' - ';
142                 $logMessage .= json_encode($this->introspection->getRecord());
143
144                 return $logMessage;
145         }
146
147         private function addEntry($level, $message, $context = [])
148         {
149                 if ($level >= $this->logLevel) {
150                         return;
151                 }
152
153                 $formattedLog = $this->formatLog($level, $message, $context);
154                 $this->write($level, $formattedLog);
155         }
156
157         /**
158          * {@inheritdoc}
159          */
160         public function emergency($message, array $context = array())
161         {
162                 $this->addEntry(LOG_EMERG, $message, $context);
163         }
164
165         /**
166          * {@inheritdoc}
167          */
168         public function alert($message, array $context = array())
169         {
170                 $this->addEntry(LOG_ALERT, $message, $context);
171         }
172
173         /**
174          * {@inheritdoc}
175          */
176         public function critical($message, array $context = array())
177         {
178                 $this->addEntry(LOG_CRIT, $message, $context);
179         }
180
181         /**
182          * {@inheritdoc}
183          */
184         public function error($message, array $context = array())
185         {
186                 $this->addEntry(LOG_ERR, $message, $context);
187         }
188
189         /**
190          * {@inheritdoc}
191          */
192         public function warning($message, array $context = array())
193         {
194                 $this->addEntry(LOG_WARNING, $message, $context);
195         }
196
197         /**
198          * {@inheritdoc}
199          */
200         public function notice($message, array $context = array())
201         {
202                 $this->addEntry(LOG_NOTICE, $message, $context);
203         }
204
205         /**
206          * {@inheritdoc}
207          */
208         public function info($message, array $context = array())
209         {
210                 $this->addEntry(LOG_INFO, $message, $context);
211         }
212
213         /**
214          * {@inheritdoc}
215          */
216         public function debug($message, array $context = array())
217         {
218                 $this->addEntry(LOG_DEBUG, $message, $context);
219         }
220
221         /**
222          * {@inheritdoc}
223          */
224         public function log($level, $message, array $context = array())
225         {
226                 $logLevel = $this->mapLevelToPriority($level);
227                 $this->addEntry($logLevel, $message, $context);
228         }
229 }