Refactored Logging environment (cleaned up)
authorPhilipp Holzer <admin@philipp.info>
Thu, 28 Feb 2019 07:56:28 +0000 (08:56 +0100)
committerPhilipp Holzer <admin@philipp.info>
Sun, 3 Mar 2019 13:32:51 +0000 (14:32 +0100)
src/Factory/LoggerFactory.php
src/Util/Introspection.php [new file with mode: 0644]
src/Util/Logger/FriendicaDevelopHandler.php [deleted file]
src/Util/Logger/Introspection.php [deleted file]
src/Util/Logger/Monolog/FriendicaDevelopHandler.php [new file with mode: 0644]
src/Util/Logger/Monolog/FriendicaIntrospectionProcessor.php [new file with mode: 0644]
src/Util/Logger/StreamLogger.php [new file with mode: 0644]
src/Util/Logger/SyslogLogger.php

index d36cebd..c337e01 100644 (file)
@@ -5,8 +5,9 @@ namespace Friendica\Factory;
 use Friendica\Core\Config\Configuration;
 use Friendica\Core\Logger;
 use Friendica\Network\HTTPException\InternalServerErrorException;
-use Friendica\Util\Logger\FriendicaDevelopHandler;
-use Friendica\Util\Logger\Introspection;
+use Friendica\Util\Introspection;
+use Friendica\Util\Logger\Monolog\FriendicaDevelopHandler;
+use Friendica\Util\Logger\Monolog\FriendicaIntrospectionProcessor;
 use Friendica\Util\Logger\SyslogLogger;
 use Friendica\Util\Logger\VoidLogger;
 use Friendica\Util\Profiler;
@@ -24,10 +25,12 @@ class LoggerFactory
        /**
         * Creates a new PSR-3 compliant logger instances
         *
-        * @param string        $channel The channel of the logger instance
-        * @param Configuration $config  The config
+        * @param string        $channel  The channel of the logger instance
+        * @param Configuration $config   The config
         *
         * @return LoggerInterface The PSR-3 compliant logger instance
+        *
+        * @throws \Exception
         */
        public static function create($channel, Configuration $config)
        {
@@ -37,12 +40,13 @@ class LoggerFactory
                        return $logger;
                }
 
+               $introspection = new Introspection([Logger::class, SyslogLogger::class, Profiler::class]);
+
                switch ($config->get('system', 'logger_adapter', 'monolog')) {
                        case 'syslog':
-                               $intorspector = new Introspection(LOG_DEBUG, [Logger::class, SyslogLogger::class, Profiler::class]);
                                $level = $config->get('system', 'loglevel');
 
-                               $logger = new SyslogLogger($channel, $intorspector, $level);
+                               $logger = new SyslogLogger($channel, $introspection, $level);
                                break;
                        case 'monolog':
                        default:
@@ -50,7 +54,7 @@ class LoggerFactory
                                $logger->pushProcessor(new Monolog\Processor\PsrLogMessageProcessor());
                                $logger->pushProcessor(new Monolog\Processor\ProcessIdProcessor());
                                $logger->pushProcessor(new Monolog\Processor\UidProcessor());
-                               $logger->pushProcessor(new Introspection(LogLevel::DEBUG, [Logger::class, Profiler::class]));
+                               $logger->pushProcessor(new FriendicaIntrospectionProcessor($introspection, LogLevel::DEBUG));
 
                                $stream = $config->get('system', 'logfile');
                                $level = $config->get('system', 'loglevel');
@@ -88,11 +92,13 @@ class LoggerFactory
                        return null;
                }
 
+               $introspection = new Introspection([Logger::class, SyslogLogger::class, Profiler::class]);
+
                $logger = new Monolog\Logger($channel);
                $logger->pushProcessor(new Monolog\Processor\PsrLogMessageProcessor());
                $logger->pushProcessor(new Monolog\Processor\ProcessIdProcessor());
                $logger->pushProcessor(new Monolog\Processor\UidProcessor());
-               $logger->pushProcessor(new Introspection(LogLevel::DEBUG, ['Friendica\\Core\\Logger']));
+               $logger->pushProcessor(new FriendicaIntrospectionProcessor($introspection, LogLevel::DEBUG));
 
                $logger->pushHandler(new FriendicaDevelopHandler($developerIp));
 
diff --git a/src/Util/Introspection.php b/src/Util/Introspection.php
new file mode 100644 (file)
index 0000000..aa8dce4
--- /dev/null
@@ -0,0 +1,87 @@
+<?php
+
+namespace Friendica\Util;
+
+/**
+ * Get Introspection information about the current call
+ */
+class Introspection
+{
+       private $skipStackFramesCount;
+
+       private $skipClassesPartials;
+
+       private $skipFunctions = [
+               'call_user_func',
+               'call_user_func_array',
+       ];
+
+       /**
+        * @param array $skipClassesPartials  An array of classes to skip during logging
+        * @param int   $skipStackFramesCount If the logger should use information from other hierarchy levels of the call
+        */
+       public function __construct($skipClassesPartials = array(), $skipStackFramesCount = 0)
+       {
+               $this->skipClassesPartials  = $skipClassesPartials;
+               $this->skipStackFramesCount = $skipStackFramesCount;
+       }
+
+       /**
+        * Adds new classes to get skipped
+        * @param array $classNames
+        */
+       public function addClasses(array $classNames)
+       {
+               $this->skipClassesPartials = array_merge($this->skipClassesPartials, $classNames);
+       }
+
+       /**
+        * Returns the introspection record of the current call
+        *
+        * @return array
+        */
+       public function getRecord()
+       {
+               $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
+
+               $i = 1;
+
+               while ($this->isTraceClassOrSkippedFunction($trace, $i)) {
+                       $i++;
+               }
+
+               $i += $this->skipStackFramesCount;
+
+               return [
+                       'file'     => isset($trace[$i - 1]['file']) ? basename($trace[$i - 1]['file']) : null,
+                       'line'     => isset($trace[$i - 1]['line']) ? $trace[$i - 1]['line'] : null,
+                       'function' => isset($trace[$i]['function']) ? $trace[$i]['function'] : null,
+               ];
+       }
+
+       /**
+        * Checks if the current trace class or function has to be skipped
+        *
+        * @param array $trace The current trace array
+        * @param int $index The index of the current hierarchy level
+        * @return bool True if the class or function should get skipped, otherwise false
+        */
+       private function isTraceClassOrSkippedFunction(array $trace, $index)
+       {
+               if (!isset($trace[$index])) {
+                       return false;
+               }
+
+               if (isset($trace[$index]['class'])) {
+                       foreach ($this->skipClassesPartials as $part) {
+                               if (strpos($trace[$index]['class'], $part) !== false) {
+                                       return true;
+                               }
+                       }
+               } elseif (in_array($trace[$index]['function'], $this->skipFunctions)) {
+                       return true;
+               }
+
+               return false;
+       }
+}
diff --git a/src/Util/Logger/FriendicaDevelopHandler.php b/src/Util/Logger/FriendicaDevelopHandler.php
deleted file mode 100644 (file)
index 908d705..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-<?php
-
-namespace Friendica\Util\Logger;
-
-use Monolog\Handler;
-use Monolog\Logger;
-
-/**
- * Simple handler for Friendica developers to use for deeper logging
- *
- * If you want to debug only interactions from your IP or the IP of a remote server for federation debug,
- * you'll use Logger::develop() for the duration of your work, and you clean it up when you're done before submitting your PR.
- */
-class FriendicaDevelopHandler extends Handler\AbstractHandler
-{
-       /**
-        * @var string The IP of the developer who wants to debug
-        */
-       private $developerIp;
-
-       /**
-        * @param string $developerIp  The IP of the developer who wants to debug
-        * @param int    $level        The minimum logging level at which this handler will be triggered
-        * @param bool   $bubble       Whether the messages that are handled can bubble up the stack or not
-        */
-       public function __construct($developerIp, $level = Logger::DEBUG, $bubble = true)
-       {
-               parent::__construct($level, $bubble);
-
-               $this->developerIp = $developerIp;
-       }
-
-       /**
-        * {@inheritdoc}
-        */
-       public function handle(array $record)
-       {
-               if (!$this->isHandling($record)) {
-                       return false;
-               }
-
-               /// Just in case the remote IP is the same as the developer IP log the output
-               if (!is_null($this->developerIp) && $_SERVER['REMOTE_ADDR'] != $this->developerIp)
-               {
-                       return false;
-               }
-
-               return false === $this->bubble;
-       }
-}
diff --git a/src/Util/Logger/Introspection.php b/src/Util/Logger/Introspection.php
deleted file mode 100644 (file)
index f99225f..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-<?php
-
-namespace Friendica\Util\Logger;
-
-use Monolog\Logger;
-use Monolog\Processor\ProcessorInterface;
-
-/**
- * Injects line/file//function where the log message came from
- *
- * Based on the class IntrospectionProcessor without the "class" information
- * @see IntrospectionProcessor
- */
-class Introspection implements ProcessorInterface
-{
-       private $level;
-
-       private $skipStackFramesCount;
-
-       private $skipClassesPartials;
-
-       private $skipFunctions = [
-               'call_user_func',
-               'call_user_func_array',
-       ];
-
-       /**
-        * @param string|int $level The minimum logging level at which this Processor will be triggered
-        * @param array $skipClassesPartials An array of classes to skip during logging
-        * @param int $skipStackFramesCount If the logger should use information from other hierarchy levels of the call
-        */
-       public function __construct($level = Logger::DEBUG, $skipClassesPartials = array(), $skipStackFramesCount = 0)
-       {
-               $this->level = Logger::toMonologLevel($level);
-               $this->skipClassesPartials = array_merge(array('Monolog\\'), $skipClassesPartials);
-               $this->skipStackFramesCount = $skipStackFramesCount;
-       }
-
-       public function __invoke(array $record)
-       {
-               // return if the level is not high enough
-               if ($record['level'] < $this->level) {
-                       return $record;
-               }
-               // we should have the call source now
-               $record['extra'] = array_merge(
-                       $record['extra'],
-                       $this->getRecord()
-               );
-
-               return $record;
-       }
-
-       /**
-        * Returns the introspection record of the current call
-        *
-        * @return array
-        */
-       public function getRecord()
-       {
-               $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
-
-               $i = 1;
-
-               while ($this->isTraceClassOrSkippedFunction($trace, $i)) {
-                       $i++;
-               }
-
-               $i += $this->skipStackFramesCount;
-
-               return [
-                       'file'     => isset($trace[$i - 1]['file']) ? basename($trace[$i - 1]['file']) : null,
-                       'line'     => isset($trace[$i - 1]['line']) ? $trace[$i - 1]['line'] : null,
-                       'function' => isset($trace[$i]['function']) ? $trace[$i]['function'] : null,
-               ];
-       }
-
-       /**
-        * Checks if the current trace class or function has to be skipped
-        *
-        * @param array $trace The current trace array
-        * @param int   $index The index of the current hierarchy level
-        * @return bool True if the class or function should get skipped, otherwise false
-        */
-       private function isTraceClassOrSkippedFunction(array $trace, $index)
-       {
-               if (!isset($trace[$index])) {
-                       return false;
-               }
-
-               if (isset($trace[$index]['class'])) {
-                       foreach ($this->skipClassesPartials as $part) {
-                               if (strpos($trace[$index]['class'], $part) !== false) {
-                                       return true;
-                               }
-                       }
-               } elseif (in_array($trace[$index]['function'], $this->skipFunctions)) {
-                       return true;
-               }
-
-               return false;
-       }
-}
diff --git a/src/Util/Logger/Monolog/FriendicaDevelopHandler.php b/src/Util/Logger/Monolog/FriendicaDevelopHandler.php
new file mode 100644 (file)
index 0000000..13a4645
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+
+namespace Friendica\Util\Logger\Monolog;
+
+use Monolog\Handler;
+use Monolog\Logger;
+
+/**
+ * Simple handler for Friendica developers to use for deeper logging
+ *
+ * If you want to debug only interactions from your IP or the IP of a remote server for federation debug,
+ * you'll use Logger::develop() for the duration of your work, and you clean it up when you're done before submitting your PR.
+ */
+class FriendicaDevelopHandler extends Handler\AbstractHandler
+{
+       /**
+        * @var string The IP of the developer who wants to debug
+        */
+       private $developerIp;
+
+       /**
+        * @param string $developerIp  The IP of the developer who wants to debug
+        * @param int    $level        The minimum logging level at which this handler will be triggered
+        * @param bool   $bubble       Whether the messages that are handled can bubble up the stack or not
+        */
+       public function __construct($developerIp, $level = Logger::DEBUG, $bubble = true)
+       {
+               parent::__construct($level, $bubble);
+
+               $this->developerIp = $developerIp;
+       }
+
+       /**
+        * {@inheritdoc}
+        */
+       public function handle(array $record)
+       {
+               if (!$this->isHandling($record)) {
+                       return false;
+               }
+
+               /// Just in case the remote IP is the same as the developer IP log the output
+               if (!is_null($this->developerIp) && $_SERVER['REMOTE_ADDR'] != $this->developerIp)
+               {
+                       return false;
+               }
+
+               return false === $this->bubble;
+       }
+}
diff --git a/src/Util/Logger/Monolog/FriendicaIntrospectionProcessor.php b/src/Util/Logger/Monolog/FriendicaIntrospectionProcessor.php
new file mode 100644 (file)
index 0000000..b8e7f5e
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+
+namespace Friendica\Util\Logger\Monolog;
+
+use Friendica\Util\Introspection;
+use Monolog\Logger;
+use Monolog\Processor\ProcessorInterface;
+
+/**
+ * Injects line/file//function where the log message came from
+ */
+class FriendicaIntrospectionProcessor implements ProcessorInterface
+{
+       private $level;
+
+       private $introspection;
+
+       /**
+        * @param Introspection $introspection Holds the Introspection of the current call
+        * @param string|int    $level         The minimum logging level at which this Processor will be triggered
+        */
+       public function __construct(Introspection $introspection, $level = Logger::DEBUG)
+       {
+               $this->level = Logger::toMonologLevel($level);
+               $introspection->addClasses(array('Monolog\\'));
+               $this->introspection = $introspection;
+       }
+
+       public function __invoke(array $record)
+       {
+               // return if the level is not high enough
+               if ($record['level'] < $this->level) {
+                       return $record;
+               }
+               // we should have the call source now
+               $record['extra'] = array_merge(
+                       $record['extra'],
+                       $this->introspection->getRecord()
+               );
+
+               return $record;
+       }
+}
diff --git a/src/Util/Logger/StreamLogger.php b/src/Util/Logger/StreamLogger.php
new file mode 100644 (file)
index 0000000..7b9bbb3
--- /dev/null
@@ -0,0 +1,301 @@
+<?php
+
+namespace Friendica\Util\Logger;
+
+use Friendica\Network\HTTPException\InternalServerErrorException;
+use Friendica\Util\Introspection;
+use Friendica\Util\Strings;
+use Psr\Log\InvalidArgumentException;
+use Psr\Log\LoggerInterface;
+use Psr\Log\LogLevel;
+
+/**
+ * A Logger instance for logging into a stream
+ * @see http://php.net/manual/en/function.syslog.php
+ */
+class StreamLogger implements LoggerInterface
+{
+       const IDENT = 'Friendica';
+
+       /**
+        * Translates LogLevel log levels to syslog log priorities.
+        * @var array
+        */
+       private $logLevels = [
+               LogLevel::DEBUG     => LOG_DEBUG,
+               LogLevel::INFO      => LOG_INFO,
+               LogLevel::NOTICE    => LOG_NOTICE,
+               LogLevel::WARNING   => LOG_WARNING,
+               LogLevel::ERROR     => LOG_ERR,
+               LogLevel::CRITICAL  => LOG_CRIT,
+               LogLevel::ALERT     => LOG_ALERT,
+               LogLevel::EMERGENCY => LOG_EMERG,
+       ];
+
+       /**
+        * Translates log priorities to string outputs
+        * @var array
+        */
+       private $logToString = [
+               LOG_DEBUG   => 'DEBUG',
+               LOG_INFO    => 'INFO',
+               LOG_NOTICE  => 'NOTICE',
+               LOG_WARNING => 'WARNING',
+               LOG_ERR     => 'ERROR',
+               LOG_CRIT    => 'CRITICAL',
+               LOG_ALERT   => 'ALERT',
+               LOG_EMERG   => 'EMERGENCY'
+       ];
+
+       /**
+        * The channel of the current process (added to each message)
+        * @var string
+        */
+       private $channel;
+
+       /**
+        * Indicates what logging options will be used when generating a log message
+        * @see http://php.net/manual/en/function.openlog.php#refsect1-function.openlog-parameters
+        *
+        * @var int
+        */
+       private $logOpts;
+
+       /**
+        * Used to specify what type of program is logging the message
+        * @see http://php.net/manual/en/function.openlog.php#refsect1-function.openlog-parameters
+        *
+        * @var int
+        */
+       private $logFacility;
+
+       /**
+        * The minimum loglevel at which this logger will be triggered
+        * @var int
+        */
+       private $logLevel;
+
+       /**
+        * The Introspection for the current call
+        * @var Introspection
+        */
+       private $introspection;
+
+       /**
+        * The UID of the current call
+        * @var string
+        */
+       private $logUid;
+
+       /**
+        * @param string        $channel       The output channel
+        * @param Introspection $introspection The introspection of the current call
+        * @param string        $level         The minimum loglevel at which this logger will be triggered
+        * @param int           $logOpts       Indicates what logging options will be used when generating a log message
+        * @param int           $logFacility   Used to specify what type of program is logging the message
+        *
+        * @throws \Exception
+        */
+       public function __construct($channel, Introspection $introspection, $level = LogLevel::NOTICE, $logOpts = LOG_PID, $logFacility = LOG_USER)
+       {
+               $this->logUid = Strings::getRandomHex(6);
+               $this->channel = $channel;
+               $this->logOpts = $logOpts;
+               $this->logFacility = $logFacility;
+               $this->logLevel = $this->mapLevelToPriority($level);
+               $this->introspection = $introspection;
+       }
+
+       /**
+        * Maps the LogLevel (@see LogLevel ) to a SysLog priority (@see http://php.net/manual/en/function.syslog.php#refsect1-function.syslog-parameters )
+        *
+        * @param string $level A LogLevel
+        *
+        * @return int The SysLog priority
+        *
+        * @throws \Psr\Log\InvalidArgumentException If the loglevel isn't valid
+        */
+       public function mapLevelToPriority($level)
+       {
+               if (!array_key_exists($level, $this->logLevels)) {
+                       throw new InvalidArgumentException('LogLevel \'' . $level . '\' isn\'t valid.');
+               }
+
+               return $this->logLevels[$level];
+       }
+
+       /**
+        * Writes a message to the syslog
+        * @see http://php.net/manual/en/function.syslog.php#refsect1-function.syslog-parameters
+        *
+        * @param int    $priority The Priority
+        * @param string $message  The message of the log
+        *
+        * @throws InternalServerErrorException if syslog cannot be used
+        */
+       private function write($priority, $message)
+       {
+               if (!openlog(self::IDENT, $this->logOpts, $this->logFacility)) {
+                       throw new InternalServerErrorException('Can\'t open syslog for ident "' . $this->channel . '" and facility "' . $this->logFacility . '""');
+               }
+
+               syslog($priority, $message);
+       }
+
+       /**
+        * Closes the Syslog
+        */
+       public function close()
+       {
+               closelog();
+       }
+
+       /**
+        * Formats a log record for the syslog output
+        *
+        * @param int    $level   The loglevel/priority
+        * @param string $message The message
+        * @param array  $context The context of this call
+        *
+        * @return string the formatted syslog output
+        */
+       private function formatLog($level, $message, $context = [])
+       {
+               $record = $this->introspection->getRecord();
+               $record = array_merge($record, ['uid' => $this->logUid]);
+               $logMessage = '';
+
+               $logMessage .= $this->channel . ' ';
+               $logMessage .= '[' . $this->logToString[$level] . ']: ';
+               $logMessage .= $this->psrInterpolate($message, $context) . ' ';
+               $logMessage .= @json_encode($context) . ' - ';
+               $logMessage .= @json_encode($record);
+
+               return $logMessage;
+       }
+
+       /**
+        * Simple interpolation of PSR-3 compliant replacements ( variables between '{' and '}' )
+        * @see https://www.php-fig.org/psr/psr-3/#12-message
+        *
+        * @param string $message
+        * @param array  $context
+        *
+        * @return string the interpolated message
+        */
+       private function psrInterpolate($message, array $context = array())
+       {
+               $replace = [];
+               foreach ($context as $key => $value) {
+                       // check that the value can be casted to string
+                       if (!is_array($value) && (!is_object($value) || method_exists($value, '__toString'))) {
+                               $replace['{' . $key . '}'] = $value;
+                       } elseif (is_array($value)) {
+                               $replace['{' . $key . '}'] = @json_encode($value);
+                       }
+               }
+
+               return strtr($message, $replace);
+       }
+
+       /**
+        * Adds a new entry to the syslog
+        *
+        * @param int    $level
+        * @param string $message
+        * @param array  $context
+        *
+        * @throws InternalServerErrorException if the syslog isn't available
+        */
+       private function addEntry($level, $message, $context = [])
+       {
+               if ($level >= $this->logLevel) {
+                       return;
+               }
+
+               $formattedLog = $this->formatLog($level, $message, $context);
+               $this->write($level, $formattedLog);
+       }
+
+       /**
+        * {@inheritdoc}
+        * @throws InternalServerErrorException if the syslog isn't available
+        */
+       public function emergency($message, array $context = array())
+       {
+               $this->addEntry(LOG_EMERG, $message, $context);
+       }
+
+       /**
+        * {@inheritdoc}
+        * @throws InternalServerErrorException if the syslog isn't available
+        */
+       public function alert($message, array $context = array())
+       {
+               $this->addEntry(LOG_ALERT, $message, $context);
+       }
+
+       /**
+        * {@inheritdoc}
+        * @throws InternalServerErrorException if the syslog isn't available
+        */
+       public function critical($message, array $context = array())
+       {
+               $this->addEntry(LOG_CRIT, $message, $context);
+       }
+
+       /**
+        * {@inheritdoc}
+        * @throws InternalServerErrorException if the syslog isn't available
+        */
+       public function error($message, array $context = array())
+       {
+               $this->addEntry(LOG_ERR, $message, $context);
+       }
+
+       /**
+        * {@inheritdoc}
+        * @throws InternalServerErrorException if the syslog isn't available
+        */
+       public function warning($message, array $context = array())
+       {
+               $this->addEntry(LOG_WARNING, $message, $context);
+       }
+
+       /**
+        * {@inheritdoc}
+        * @throws InternalServerErrorException if the syslog isn't available
+        */
+       public function notice($message, array $context = array())
+       {
+               $this->addEntry(LOG_NOTICE, $message, $context);
+       }
+
+       /**
+        * {@inheritdoc}
+        * @throws InternalServerErrorException if the syslog isn't available
+        */
+       public function info($message, array $context = array())
+       {
+               $this->addEntry(LOG_INFO, $message, $context);
+       }
+
+       /**
+        * {@inheritdoc}
+        * @throws InternalServerErrorException if the syslog isn't available
+        */
+       public function debug($message, array $context = array())
+       {
+               $this->addEntry(LOG_DEBUG, $message, $context);
+       }
+
+       /**
+        * {@inheritdoc}
+        * @throws InternalServerErrorException if the syslog isn't available
+        */
+       public function log($level, $message, array $context = array())
+       {
+               $logLevel = $this->mapLevelToPriority($level);
+               $this->addEntry($logLevel, $message, $context);
+       }
+}
index 1939515..5cb1f8c 100644 (file)
@@ -3,6 +3,7 @@
 namespace Friendica\Util\Logger;
 
 use Friendica\Network\HTTPException\InternalServerErrorException;
+use Friendica\Util\Introspection;
 use Friendica\Util\Strings;
 use Psr\Log\InvalidArgumentException;
 use Psr\Log\LoggerInterface;
@@ -75,7 +76,7 @@ class SyslogLogger implements LoggerInterface
        private $logLevel;
 
        /**
-        * The Introspector for the current call
+        * The Introspection for the current call
         * @var Introspection
         */
        private $introspection;
@@ -87,10 +88,13 @@ class SyslogLogger implements LoggerInterface
        private $logUid;
 
        /**
-        * @param string $channel     The output channel
-        * @param string $level       The minimum loglevel at which this logger will be triggered
-        * @param int    $logOpts     Indicates what logging options will be used when generating a log message
-        * @param int    $logFacility Used to specify what type of program is logging the message
+        * @param string        $channel       The output channel
+        * @param Introspection $introspection The introspection of the current call
+        * @param string        $level         The minimum loglevel at which this logger will be triggered
+        * @param int           $logOpts       Indicates what logging options will be used when generating a log message
+        * @param int           $logFacility   Used to specify what type of program is logging the message
+        *
+        * @throws \Exception
         */
        public function __construct($channel, Introspection $introspection, $level = LogLevel::NOTICE, $logOpts = LOG_PID, $logFacility = LOG_USER)
        {