1<?php 2 3use Psr\Container\ContainerInterface; 4use Monolog\Logger; 5use Piwik\Log; 6use Piwik\Plugins\Monolog\Handler\FileHandler; 7use Piwik\Plugins\Monolog\Handler\LogCaptureHandler; 8 9return array( 10 11 'Monolog\Logger' => DI\create('Monolog\Logger') 12 ->constructor('piwik', DI\get('log.handlers'), DI\get('log.processors')), 13 14 'Psr\Log\LoggerInterface' => DI\get('Monolog\Logger'), 15 16 'log.handler.classes' => array( 17 'file' => 'Piwik\Plugins\Monolog\Handler\FileHandler', 18 'screen' => 'Piwik\Plugins\Monolog\Handler\WebNotificationHandler', 19 'database' => 'Piwik\Plugins\Monolog\Handler\DatabaseHandler', 20 'errorlog' => '\Monolog\Handler\ErrorLogHandler', 21 'syslog' => '\Monolog\Handler\SyslogHandler', 22 ), 23 'log.handlers' => DI\factory(function (\DI\Container $c) { 24 if ($c->has('ini.log.log_writers')) { 25 $writerNames = $c->get('ini.log.log_writers'); 26 } else { 27 return array(); 28 } 29 30 $classes = $c->get('log.handler.classes'); 31 32 $logConfig = $c->get(\Piwik\Config::class)->log; 33 $enableFingersCrossed = isset($logConfig['enable_fingers_crossed_handler']) && $logConfig['enable_fingers_crossed_handler'] == 1; 34 $fingersCrossedStopBuffering = isset($logConfig['fingers_crossed_stop_buffering_on_activation']) && $logConfig['fingers_crossed_stop_buffering_on_activation'] == 1; 35 $enableLogCaptureHandler = isset($logConfig['enable_log_capture_handler']) && $logConfig['enable_log_capture_handler'] == 1; 36 37 $isLogBufferingAllowed = !\Piwik\Common::isPhpCliMode() 38 || \Piwik\SettingsServer::isArchivePhpTriggered() 39 || \Piwik\CliMulti::isCliMultiRequest(); 40 41 $writerNames = array_map('trim', $writerNames); 42 43 $writers = []; 44 foreach ($writerNames as $writerName) { 45 if ($writerName === 'screen' 46 && \Piwik\Common::isPhpCliMode() 47 && !defined('PIWIK_TEST_MODE') 48 && !\Piwik\SettingsServer::isTrackerApiRequest() 49 ) { 50 continue; // screen writer is only valid for web requests (except for tracker CLI requests) 51 } 52 53 if (isset($classes[$writerName])) { 54 // wrap the handler in FingersCrossedHandler if we can and this isn't the screen handler 55 56 /** @var \Monolog\Handler\HandlerInterface $handler */ 57 $handler = $c->make($classes[$writerName]); 58 if ($enableFingersCrossed 59 && $writerName !== 'screen' 60 && $handler instanceof \Monolog\Handler\AbstractHandler 61 && $isLogBufferingAllowed 62 ) { 63 $passthruLevel = $handler->getLevel(); 64 65 $handler->setLevel(Logger::DEBUG); 66 67 $handler = new \Monolog\Handler\FingersCrossedHandler($handler, $activationStrategy = null, $bufferSize = 0, 68 $bubble = true, $fingersCrossedStopBuffering, $passthruLevel); 69 } 70 71 $writers[$writerName] = $handler; 72 } 73 } 74 75 if ($enableLogCaptureHandler 76 && $isLogBufferingAllowed 77 ) { 78 $writers[] = $c->get(LogCaptureHandler::class); 79 } 80 81 // we always add the null handler to make sure there is at least one handler specified. otherwise Monolog will 82 // add a stream handler to stderr w/ a DEBUG log level, which will cause archiving requests to fail. 83 if (empty($writers)) { 84 $writers[] = $c->get(\Monolog\Handler\NullHandler::class); 85 } 86 87 return array_values($writers); 88 }), 89 90 'log.processors' => array( 91 DI\get('Piwik\Plugins\Monolog\Processor\SprintfProcessor'), 92 DI\get('Piwik\Plugins\Monolog\Processor\ClassNameProcessor'), 93 DI\get('Piwik\Plugins\Monolog\Processor\RequestIdProcessor'), 94 DI\get('Piwik\Plugins\Monolog\Processor\ExceptionToTextProcessor'), 95 DI\get('Monolog\Processor\PsrLogMessageProcessor'), 96 DI\get('Piwik\Plugins\Monolog\Processor\TokenProcessor'), 97 ), 98 99 'Piwik\Plugins\Monolog\Handler\FileHandler' => DI\create() 100 ->constructor(DI\get('log.file.filename'), DI\get('log.level.file')) 101 ->method('setFormatter', DI\get('log.lineMessageFormatter.file')), 102 103 '\Monolog\Handler\ErrorLogHandler' => DI\autowire() 104 ->constructorParameter('level', DI\get('log.level.errorlog')) 105 ->method('setFormatter', DI\get('log.lineMessageFormatter.file')), 106 107 '\Monolog\Handler\SyslogHandler' => DI\autowire() 108 ->constructorParameter('ident', DI\get('log.syslog.ident')) 109 ->constructorParameter('level', DI\get('log.level.syslog')) 110 ->method('setFormatter', DI\get('log.lineMessageFormatter.file')), 111 112 'Piwik\Plugins\Monolog\Handler\DatabaseHandler' => DI\create() 113 ->constructor(DI\get('log.level.database')) 114 ->method('setFormatter', DI\get('log.lineMessageFormatter')), 115 116 'Piwik\Plugins\Monolog\Handler\WebNotificationHandler' => DI\create() 117 ->constructor(DI\get('log.level.screen')) 118 ->method('setFormatter', DI\get('log.lineMessageFormatter')), 119 120 'log.level' => DI\factory(function (ContainerInterface $c) { 121 if ($c->has('ini.log.log_level')) { 122 $level = strtoupper($c->get('ini.log.log_level')); 123 if (!empty($level) && defined('Piwik\Log::'.strtoupper($level))) { 124 return Log::getMonologLevel(constant('Piwik\Log::'.strtoupper($level))); 125 } 126 } 127 128 return Logger::WARNING; 129 }), 130 131 'log.level.file' => DI\factory(function (ContainerInterface $c) { 132 if ($c->has('ini.log.log_level_file')) { 133 $level = Log::getMonologLevelIfValid($c->get('ini.log.log_level_file')); 134 if ($level !== null) { 135 return $level; 136 } 137 } 138 return $c->get('log.level'); 139 }), 140 141 'log.level.screen' => DI\factory(function (ContainerInterface $c) { 142 if ($c->has('ini.log.log_level_screen')) { 143 $level = Log::getMonologLevelIfValid($c->get('ini.log.log_level_screen')); 144 if ($level !== null) { 145 return $level; 146 } 147 } 148 return $c->get('log.level'); 149 }), 150 151 'log.level.database' => DI\factory(function (ContainerInterface $c) { 152 if ($c->has('ini.log.log_level_database')) { 153 $level = Log::getMonologLevelIfValid($c->get('ini.log.log_level_database')); 154 if ($level !== null) { 155 return $level; 156 } 157 } 158 return $c->get('log.level'); 159 }), 160 161 'log.level.syslog' => DI\factory(function (ContainerInterface $c) { 162 if ($c->has('ini.log.log_level_syslog')) { 163 $level = Log::getMonologLevelIfValid($c->get('ini.log.log_level_syslog')); 164 if ($level !== null) { 165 return $level; 166 } 167 } 168 return $c->get('log.level'); 169 }), 170 171 'log.level.errorlog' => DI\factory(function (ContainerInterface $c) { 172 if ($c->has('ini.log.log_level_errorlog')) { 173 $level = Log::getMonologLevelIfValid($c->get('ini.log.log_level_errorlog')); 174 if ($level !== null) { 175 return $level; 176 } 177 } 178 return $c->get('log.level'); 179 }), 180 181 'log.file.filename' => DI\factory(function (ContainerInterface $c) { 182 $logPath = $c->get('ini.log.logger_file_path'); 183 184 // Absolute path 185 if (strpos($logPath, '/') === 0) { 186 return $logPath; 187 } 188 189 // Remove 'tmp/' at the beginning 190 if (strpos($logPath, 'tmp/') === 0) { 191 $logPath = substr($logPath, strlen('tmp')); 192 } 193 194 if (empty($logPath)) { 195 // Default log file 196 $logPath = '/logs/piwik.log'; 197 } 198 199 $logPath = $c->get('path.tmp') . $logPath; 200 if (is_dir($logPath)) { 201 $logPath .= '/piwik.log'; 202 } 203 204 return $logPath; 205 }), 206 207 'log.syslog.ident' => DI\factory(function (ContainerInterface $c) { 208 $ident = $c->get('ini.log.logger_syslog_ident'); 209 if (empty($ident)) { 210 $ident = 'matomo'; 211 } 212 return $ident; 213 }), 214 215 'Piwik\Plugins\Monolog\Formatter\LineMessageFormatter' => DI\create('Piwik\Plugins\Monolog\Formatter\LineMessageFormatter') 216 ->constructor(DI\get('log.short.format')), 217 'log.lineMessageFormatter' => DI\create('Piwik\Plugins\Monolog\Formatter\LineMessageFormatter') 218 ->constructor(DI\get('log.short.format')), 219 220 'log.lineMessageFormatter.file' => DI\autowire('Piwik\Plugins\Monolog\Formatter\LineMessageFormatter') 221 ->constructor(DI\get('log.trace.format')) 222 ->constructorParameter('allowInlineLineBreaks', false), 223 224 'log.short.format' => DI\factory(function (ContainerInterface $c) { 225 if ($c->has('ini.log.string_message_format')) { 226 return $c->get('ini.log.string_message_format'); 227 } 228 return '%level% %tag%[%datetime%] %message%'; 229 }), 230 231 'log.trace.format' => DI\factory(function (ContainerInterface $c) { 232 if ($c->has('ini.log.string_message_format_trace')) { 233 return $c->get('ini.log.string_message_format_trace'); 234 } 235 return '%level% %tag%[%datetime%] %message% %trace%'; 236 }), 237 238 'archiving.performance.handlers' => function (ContainerInterface $c) { 239 $logFile = trim($c->get('ini.Debug.archive_profiling_log')); 240 if (empty($logFile)) { 241 return [new \Monolog\Handler\NullHandler()]; 242 } 243 244 $fileHandler = new FileHandler($logFile, \Psr\Log\LogLevel::INFO); 245 $fileHandler->setFormatter($c->get('log.lineMessageFormatter.file')); 246 return [$fileHandler]; 247 }, 248 249 'archiving.performance.logger' => DI\create(Logger::class) 250 ->constructor('matomo.archiving.performance', DI\get('archiving.performance.handlers'), DI\get('log.processors')), 251); 252