diff --git a/core/config.class.inc.php b/core/config.class.inc.php index b39f505470..163eedf492 100644 --- a/core/config.class.inc.php +++ b/core/config.class.inc.php @@ -99,6 +99,14 @@ class Config * @since 2.7.0 export_pdf_font param */ protected $m_aSettings = array( + 'min_log_level' => array( + 'type' => 'array', + 'description' => 'min log level', + 'default' => 'Ok', + 'value' => 'Ok', + 'source_of_value' => '', + 'show_in_conf_sample' => false, + ), 'app_env_label' => array( 'type' => 'string', 'description' => 'Label displayed to describe the current application environment, defaults to the environment name (e.g. "production")', diff --git a/core/log.class.inc.php b/core/log.class.inc.php index b57c6ec7b6..2a36d6170e 100644 --- a/core/log.class.inc.php +++ b/core/log.class.inc.php @@ -199,27 +199,42 @@ class FileLog } } - public function Error($sText) + public function Error($sText, $sChannel = '', $aContext = array()) { - $this->Write('Error | '.$sText); + $sLevel = str_pad(__FUNCTION__, 7).' | '; + $sChannel = empty($sChannel) ? '' : " | $sChannel"; + $this->Write("{$sLevel}{$sText}{$sChannel}", $aContext); } - public function Warning($sText) + public function Warning($sText, $sChannel = '', $aContext = array()) { - $this->Write('Warning | '.$sText); + $sLevel = str_pad(__FUNCTION__, 7).' | '; + $sChannel = empty($sChannel) ? '' : " | $sChannel"; + $this->Write("{$sLevel}{$sText}{$sChannel}", $aContext); } - public function Info($sText) + public function Info($sText, $sChannel = '', $aContext = array()) { - $this->Write('Info | '.$sText); + $sLevel = str_pad(__FUNCTION__, 7).' | '; + $sChannel = empty($sChannel) ? '' : " | $sChannel"; + $this->Write("{$sLevel}{$sText}{$sChannel}", $aContext); } - public function Ok($sText) + public function Ok($sText, $sChannel = '', $aContext = array()) { - $this->Write('Ok | '.$sText); + $sLevel = str_pad(__FUNCTION__, 7).' | '; + $sChannel = empty($sChannel) ? '' : " | $sChannel"; + $this->Write("{$sLevel}{$sText}{$sChannel}", $aContext); } - protected function Write($sText) + public function Debug($sText, $sChannel = '', $aContext = array()) + { + $sLevel = str_pad(__FUNCTION__, 7).' | '; + $sChannel = empty($sChannel) ? '' : " | $sChannel"; + $this->Write("{$sLevel}{$sText}{$sChannel}", $aContext); + } + + protected function Write($sText, $aContext = array()) { $sLogFilePath = $this->oFileNameBuilder->GetLogFilePath(); @@ -233,6 +248,15 @@ class FileLog { flock($hLogFile, LOCK_EX); $sDate = date('Y-m-d H:i:s'); + if (empty($aContext)) + { + fwrite($hLogFile, "$sDate | $sText\n"); + } + else + { + $sContext = var_export($aContext, true); + fwrite($hLogFile, "$sDate | $sText\n$sContext\n"); + } fwrite($hLogFile, "$sDate | $sText\n"); fflush($hLogFile); flock($hLogFile, LOCK_UN); @@ -243,53 +267,147 @@ class FileLog abstract class LogAPI { + const CHANNEL_DEFAULT = ''; + + const LEVEL_DEBUG = 'Debug'; + const LEVEL_OK = 'Ok'; + const LEVEL_INFO = 'Info'; + const LEVEL_WARNING = 'Warning'; + const LEVEL_ERROR = 'Error'; +// const LEVEL_CRITICAL = 'Critical'; +// const LEVEL_ALERT = 'Alert'; +// const LEVEL_EMERGENCY = 'Emergency'; + + protected static $aLevelsPriority = array( + self::LEVEL_DEBUG => 100, + self::LEVEL_OK => 150, + self::LEVEL_INFO => 200, + self::LEVEL_WARNING => 300, + self::LEVEL_ERROR => 400, + ); + public static function Enable($sTargetFile) { // m_oFileLog is not defined as a class attribute so that each impl will have its own static::$m_oFileLog = new FileLog($sTargetFile); } - public static function Error($sText) + public static function Error($sMessage, $sChannel = null, $aContext = array()) { - if (static::$m_oFileLog) - { - static::$m_oFileLog->Error($sText); - } + static::Log(self::LEVEL_ERROR, $sMessage, $sChannel, $aContext); } - public static function Warning($sText) + + public static function Warning($sMessage, $sChannel = null, $aContext = array()) { - if (static::$m_oFileLog) - { - static::$m_oFileLog->Warning($sText); - } + static::Log(self::LEVEL_WARNING, $sMessage, $sChannel, $aContext); } - public static function Info($sText) + + public static function Info($sMessage, $sChannel = null, $aContext = array()) { - if (static::$m_oFileLog) - { - static::$m_oFileLog->Info($sText); - } + static::Log(self::LEVEL_INFO, $sMessage, $sChannel, $aContext); } - public static function Ok($sText) + + public static function Ok($sMessage, $sChannel = null, $aContext = array()) { - if (static::$m_oFileLog) - { - static::$m_oFileLog->Ok($sText); - } + static::Log(self::LEVEL_OK, $sMessage, $sChannel, $aContext); } + + public static function Debug($sMessage, $sChannel = null, $aContext = array()) + { + static::Log(self::LEVEL_DEBUG, $sMessage, $sChannel, $aContext); + } + + public static function Log($sLevel, $sMessage, $sChannel = null, $aContext = array()) + { + if (! static::$m_oFileLog) + { + return; + } + + if (! isset(self::$aLevelsPriority[$sLevel])) + { + IssueLog::Error("invalid log level '{$sLevel}'"); + return; + } + + if (is_null($sChannel)) + { + $sChannel = static::CHANNEL_DEFAULT; + } + + $sMinLogLevel = self::GetMinLogLevel($sChannel); + + if ($sMinLogLevel === false || $sMinLogLevel === 'false') + { + return; + } + if (is_string($sMinLogLevel)) + { + if (! isset(self::$aLevelsPriority[$sMinLogLevel])) + { + throw new Exception("invalid configuration for log_level '{$sMinLogLevel}' is not within the list: ".implode(',', array_keys(self::$aLevelsPriority))); + } + elseif (self::$aLevelsPriority[$sLevel] < self::$aLevelsPriority[$sMinLogLevel]) + { + //priority too low regarding the conf, do not log this + return; + } + } + + static::$m_oFileLog->$sLevel($sMessage, $sChannel, $aContext); + } + + /** + * @param $sChannel + * + * @return mixed|null + */ + private static function GetMinLogLevel($sChannel) + { + $oConfig = \MetaModel::GetConfig(); + if (! $oConfig instanceof Config) + { + return self::LEVEL_OK; + } + + $sMinLogLevel = $oConfig->Get('min_log_level'); + if (! is_array($sMinLogLevel)) + { + return $sMinLogLevel; + } + + if (isset($sMinLogLevel[$sChannel])) + { + return $sMinLogLevel[$sChannel]; + } + + if (isset($sMinLogLevel[static::CHANNEL_DEFAULT])) + { + return $sMinLogLevel[$sChannel]; + } + + return self::LEVEL_OK; + } + } class SetupLog extends LogAPI { + const CHANNEL_DEFAULT = 'SetupLog'; + protected static $m_oFileLog = null; } class IssueLog extends LogAPI { + const CHANNEL_DEFAULT = 'IssueLog'; + protected static $m_oFileLog = null; } class ToolsLog extends LogAPI { + const CHANNEL_DEFAULT = 'ToolsLog'; + protected static $m_oFileLog = null; }