]> git.mxchange.org Git - friendica.git/blob - src/Core/Logger/Type/StreamLogger.php
Fix: Pagination in search result works again
[friendica.git] / src / Core / Logger / Type / StreamLogger.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2023, the Friendica project
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  */
21
22 namespace Friendica\Core\Logger\Type;
23
24 use Friendica\Core\Logger\Capability\IHaveCallIntrospections;
25 use Friendica\Core\Logger\Exception\LoggerException;
26 use Friendica\Core\Logger\Exception\LogLevelException;
27 use Friendica\Util\DateTimeFormat;
28 use Psr\Log\LogLevel;
29
30 /**
31  * A Logger instance for logging into a stream (file, stdout, stderr)
32  */
33 class StreamLogger extends AbstractLogger
34 {
35         const NAME = 'stream';
36
37         /**
38          * The minimum loglevel at which this logger will be triggered
39          * @var string
40          */
41         private $logLevel;
42
43         /**
44          * The stream, where the current logger is writing into
45          * @var resource
46          */
47         private $stream;
48
49         /**
50          * The current process ID
51          * @var int
52          */
53         private $pid;
54
55         /**
56          * Translates LogLevel log levels to integer values
57          * @var array
58          */
59         public const levelToInt = [
60                 LogLevel::EMERGENCY => 0,
61                 LogLevel::ALERT     => 1,
62                 LogLevel::CRITICAL  => 2,
63                 LogLevel::ERROR     => 3,
64                 LogLevel::WARNING   => 4,
65                 LogLevel::NOTICE    => 5,
66                 LogLevel::INFO      => 6,
67                 LogLevel::DEBUG     => 7,
68         ];
69
70         /**
71          * {@inheritdoc}
72          * @param string          $level  The minimum loglevel at which this logger will be triggered
73          *
74          * @throws LoggerException
75          */
76         public function __construct(string $channel, IHaveCallIntrospections $introspection, $stream, int $logLevel, int $pid)
77         {
78                 parent::__construct($channel, $introspection);
79
80                 $this->stream   = $stream;
81                 $this->pid      = $pid;
82                 $this->logLevel = $logLevel;
83         }
84
85         public function close()
86         {
87                 if (is_resource($this->stream)) {
88                         fclose($this->stream);
89                 }
90
91                 $this->stream = null;
92         }
93
94         /**
95          * Adds a new entry to the log
96          *
97          * @param mixed  $level
98          * @param string $message
99          * @param array  $context
100          *
101          * @return void
102          *
103          * @throws LoggerException
104          * @throws LogLevelException
105          */
106         protected function addEntry($level, string $message, array $context = [])
107         {
108                 if (!array_key_exists($level, static::levelToInt)) {
109                         throw new LogLevelException(sprintf('The level "%s" is not valid.', $level));
110                 }
111
112                 $logLevel = static::levelToInt[$level];
113
114                 if ($logLevel > $this->logLevel) {
115                         return;
116                 }
117
118                 $formattedLog = $this->formatLog($level, $message, $context);
119                 fwrite($this->stream, $formattedLog);
120         }
121
122         /**
123          * Formats a log record for the syslog output
124          *
125          * @param mixed  $level   The loglevel/priority
126          * @param string $message The message
127          * @param array  $context The context of this call
128          *
129          * @return string the formatted syslog output
130          *
131          * @throws LoggerException
132          */
133         private function formatLog($level, string $message, array $context = []): string
134         {
135                 $record = $this->introspection->getRecord();
136                 $record = array_merge($record, ['uid' => $this->logUid, 'process_id' => $this->pid]);
137
138                 try {
139                         $logMessage = DateTimeFormat::utcNow(DateTimeFormat::ATOM) . ' ';
140                 } catch (\Exception $exception) {
141                         throw new LoggerException('Cannot get current datetime.', $exception);
142                 }
143                 $logMessage .= $this->channel . ' ';
144                 $logMessage .= '[' . strtoupper($level) . ']: ';
145                 $logMessage .= $this->psrInterpolate($message, $context) . ' ';
146                 $logMessage .= $this->jsonEncodeArray($context) . ' - ';
147                 $logMessage .= $this->jsonEncodeArray($record);
148                 $logMessage .= PHP_EOL;
149
150                 return $logMessage;
151         }
152 }