Moving Profiling to class
[friendica.git/.git] / src / Factory / LoggerFactory.php
1 <?php
2
3 namespace Friendica\Factory;
4
5 use Friendica\Core\Config\Configuration;
6 use Friendica\Core\Logger;
7 use Friendica\Network\HTTPException\InternalServerErrorException;
8 use Friendica\Util\Introspection;
9 use Friendica\Util\Logger\Monolog\FriendicaDevelopHandler;
10 use Friendica\Util\Logger\Monolog\FriendicaIntrospectionProcessor;
11 use Friendica\Util\Logger\SyslogLogger;
12 use Friendica\Util\Logger\VoidLogger;
13 use Friendica\Util\Profiler;
14 use Monolog;
15 use Psr\Log\LoggerInterface;
16 use Psr\Log\LogLevel;
17
18 /**
19  * A logger factory
20  *
21  * Currently only Monolog is supported
22  */
23 class LoggerFactory
24 {
25         /**
26          * Creates a new PSR-3 compliant logger instances
27          *
28          * @param string        $channel  The channel of the logger instance
29          * @param Configuration $config   The config
30          * @param Profiler      $profiler The profiler of the app
31          *
32          * @return LoggerInterface The PSR-3 compliant logger instance
33          *
34          * @throws \Exception
35          */
36         public static function create($channel, Configuration $config, Profiler $profiler)
37         {
38                 if(empty($config->get('system', 'debugging', false))) {
39                         $logger = new VoidLogger();
40                         Logger::init($logger);
41                         return $logger;
42                 }
43
44                 $introspection = new Introspection([Logger::class, Profiler::class]);
45
46                 switch ($config->get('system', 'logger_adapter', 'monolog')) {
47                         case 'syslog':
48                                 $level = $config->get('system', 'loglevel');
49
50                                 $logger = new SyslogLogger($channel, $introspection, $profiler, $level);
51                                 break;
52                         case 'monolog':
53                         default:
54                                 $logger = new Monolog\Logger($channel);
55                                 $logger->pushProcessor(new Monolog\Processor\PsrLogMessageProcessor());
56                                 $logger->pushProcessor(new Monolog\Processor\ProcessIdProcessor());
57                                 $logger->pushProcessor(new Monolog\Processor\UidProcessor());
58                                 $logger->pushProcessor(new FriendicaIntrospectionProcessor($introspection, LogLevel::DEBUG));
59
60                                 $stream = $config->get('system', 'logfile');
61                                 $level = $config->get('system', 'loglevel');
62
63                                 $loglevel = self::mapLegacyConfigDebugLevel((string)$level);
64                                 static::addStreamHandler($logger, $stream, $loglevel);
65                                 break;
66                 }
67
68                 Logger::init($logger);
69
70                 return $logger;
71         }
72
73         /**
74          * Creates a new PSR-3 compliant develop logger
75          *
76          * If you want to debug only interactions from your IP or the IP of a remote server for federation debug,
77          * you'll use this logger instance for the duration of your work.
78          *
79          * It should never get filled during normal usage of Friendica
80          *
81          * @param string        $channel The channel of the logger instance
82          * @param Configuration $config  The config
83          *
84          * @return LoggerInterface The PSR-3 compliant logger instance
85          */
86         public static function createDev($channel, Configuration $config)
87         {
88                 $debugging   = $config->get('system', 'debugging');
89                 $stream      = $config->get('system', 'dlogfile');
90                 $developerIp = $config->get('system', 'dlogip');
91
92                 if (!isset($developerIp) || !$debugging) {
93                         return null;
94                 }
95
96                 $introspection = new Introspection([Logger::class, SyslogLogger::class, Profiler::class]);
97
98                 $logger = new Monolog\Logger($channel);
99                 $logger->pushProcessor(new Monolog\Processor\PsrLogMessageProcessor());
100                 $logger->pushProcessor(new Monolog\Processor\ProcessIdProcessor());
101                 $logger->pushProcessor(new Monolog\Processor\UidProcessor());
102                 $logger->pushProcessor(new FriendicaIntrospectionProcessor($introspection, LogLevel::DEBUG));
103
104                 $logger->pushHandler(new FriendicaDevelopHandler($developerIp));
105
106                 static::addStreamHandler($logger, $stream, LogLevel::DEBUG);
107
108                 Logger::setDevLogger($logger);
109
110                 return $logger;
111         }
112
113         /**
114          * Mapping a legacy level to the PSR-3 compliant levels
115          * @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md#5-psrlogloglevel
116          *
117          * @param string $level the level to be mapped
118          *
119          * @return string the PSR-3 compliant level
120          */
121         private static function mapLegacyConfigDebugLevel($level)
122         {
123                 switch ($level) {
124                         // legacy WARNING
125                         case "0":
126                                 return LogLevel::ERROR;
127                         // legacy INFO
128                         case "1":
129                                 return LogLevel::WARNING;
130                         // legacy TRACE
131                         case "2":
132                                 return LogLevel::NOTICE;
133                         // legacy DEBUG
134                         case "3":
135                                 return LogLevel::INFO;
136                         // legacy DATA
137                         case "4":
138                                 return LogLevel::DEBUG;
139                         // legacy ALL
140                         case "5":
141                                 return LogLevel::DEBUG;
142                         // default if nothing set
143                         default:
144                                 return $level;
145                 }
146         }
147
148         /**
149          * Adding a handler to a given logger instance
150          *
151          * @param LoggerInterface $logger  The logger instance
152          * @param mixed           $stream  The stream which handles the logger output
153          * @param string          $level   The level, for which this handler at least should handle logging
154          *
155          * @return void
156          *
157          * @throws InternalServerErrorException if the logger is incompatible to the logger factory
158          * @throws \Exception in case of general failures
159          */
160         public static function addStreamHandler($logger, $stream, $level = LogLevel::NOTICE)
161         {
162                 if ($logger instanceof Monolog\Logger) {
163                         $loglevel = Monolog\Logger::toMonologLevel($level);
164
165                         // fallback to notice if an invalid loglevel is set
166                         if (!is_int($loglevel)) {
167                                 $loglevel = LogLevel::NOTICE;
168                         }
169                         $fileHandler = new Monolog\Handler\StreamHandler($stream, $loglevel);
170
171                         $formatter = new Monolog\Formatter\LineFormatter("%datetime% %channel% [%level_name%]: %message% %context% %extra%\n");
172                         $fileHandler->setFormatter($formatter);
173
174                         $logger->pushHandler($fileHandler);
175                 } else {
176                         throw new InternalServerErrorException('Logger instance incompatible for MonologFactory');
177                 }
178         }
179
180         public static function addVoidHandler($logger)
181         {
182                 if ($logger instanceof Monolog\Logger) {
183                         $logger->pushHandler(new Monolog\Handler\NullHandler());
184                 }
185         }
186 }