* @copyright James PIC
* @version 1.0
* @package Logger
*/
/**
* Logging API.
*
This is a singleton class, this means that you can access the instance with : Logger::GetInstance().
* For example :
* {@example /mnt/data/workspace/TemplateShop/examples/logger.example.php}
* Note that this class is used in NiceLogin to take care of the user interface, and to assure security in {@element NiceLogin::SecureClass()}.
* @author James PIC
* @copyright James PIC
* @version 1.0
* @global array $aLoggerConfig
* @uses DBLayer
* @uses NiceLogin
* @todo Remove the line argumnent
*/
function get_microtime()
{
list($usec, $sec) = explode(' ', microtime());
return ((float)$usec + (float)$sec);
}
class Logger
{
/**
* Logger instance
* @access private
* @var object
*/
private static $_instance;
/**
* Instance of the database abstraction layer
* @access private
* @var object
*/
private $_oDBLayer;
/**
* NiceLogin instance
* @access private
* @var object
*/
public $_oUserLayer;
/**
* Event counter
* @access public
* @var integer
*/
public $iEvent = 0;
/**
* Array where messages are stored in chronological order
* @access public
* @var array
*/
public $aLogChrono;
/**
* Array where messages are stored in levels order
* @access public
* @var array
*/
public $aLogLevels;
/**
* Array where messages are stored by function
* @access public
* @var array
*/
public $aLogFunction;
/**
* Local microtimestamp
* @access public
* @var integer
*/
public $micronow;
/**
* Local timestamp
* @access private
* @var integer
*/
public $now;
/**
* User possible Ip
* @access public
* @var string
*/
public $sUserIP;
/**
* Class constructor
* @uses DBLayer
* @uses NiceLogin
* @uses $now
*/
function __construct()
{
global $db, $now, $aLoggerConfig;
$this->_oDBLayer =& $db;
list($usec, $sec) = explode(' ', microtime());
$this->micronow = ((float)$usec + (float)$sec);
$this->now =& time();
$now =& $this->now;
$this->sUserIP = (!empty($_SERVER['X_FORWARDED_FOR'])) ? $_SERVER['X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];
// Error id ir used in databse, because this kind of table grow very fast
$aLoggerConfig['aErrorLevelIds'] = array_flip($aLoggerConfig['aErrorLevels']);
}
/**
* Return the logger instance
* @uses Logger::$_instance
*/
public static function GetInstance()
{
if (!isset(self::$_instance))
{
self::$_instance = new Logger() ;
}
return self::$_instance;
}
/**
* Main method to log messages and data.
* If the title of the event level to log is in $aLoggerConfig['aLogLevels'], database log occurs.
* Logger::$aLogChrono is increment
* @param array Executed function arguments
* @param string Event label (for example function name)
* @param integer Line Number
* @param string Additionnal description
* @param int|string Level id or label (default : debug_notice)
* @uses $aLoggerConfig
* @uses DBLayer
* @uses Logger::$aLogChrono
* @uses Logger::$aLogLevels
* @uses Logger::$aLogFunction
* @uses Logger::$iEvent
* @uses Logger::$_instance
*/
public function Log($r_func_args, $s_event_label, $str_line, $str_description='Begin', $m_level=NULL)
{
global $aLoggerConfig, $NLC;
if (is_null($m_level)) $i_level = $aLoggerConfig['aErrorLevelIds']['debug_notice'];
elseif (!is_numeric($m_level)) $i_level = $aLoggerConfig['aErrorLevelIds'][$m_level];
else $i_level = $m_level;
if (in_array($aLoggerConfig['aErrorLevels'][$i_level], $aLoggerConfig['aLogLevels']))
$this->_oDBLayer->query('INSERT INTO `'.$this->_oDBLayer->prefix.'log` SET
`sUserIP` = \''.$this->_oDBLayer->escape($this->sUserIP).'\' ,
`iDateEvent` = '.$this->_oDBLayer->escape($this->now).' ,
`sFunction` = \''.$this->_oDBLayer->escape($s_event_label).'\' ,
`iLevel` = \''.$this->_oDBLayer->escape($i_level).'\' ,
`sDescription` = \''.$str_description.'\'') or $this->Log(func_get_args(), __FUNCTION__, __LINE__, $this->_oDBLayer->error());
$this->aLogChrono[$this->iEvent][$s_event_label][$i_level]['description'] = $str_description;
$this->aLogChrono[$this->iEvent][$s_event_label][$i_level]['level'] = $aLoggerConfig['aErrorLevels'][$i_level];
if ($str_description=='Begin' && $r_func_args)
$this->aLogChrono[$this->iEvent][$s_event_label][$i_level]['arguments'] = $r_func_args;
if (is_object($NLC)&&$NLC->aUserData)
$this->aLogChrono[$this->iEvent][$s_event_label][$i_level]['user data'] = $this->_oUserLayer->aUserData;
if (is_object($NLC)&&$NLC->aCookie)
$this->aLogChrono[$this->iEvent][$s_event_label][$i_level]['cookie data'] = $this->_oUserLayer->aCookie;
$this->aLogChrono[$this->iEvent][$s_event_label][$i_level]['time'] = $this->now;
$this->aLogChrono[$this->iEvent][$s_event_label][$i_level]['microtime'] = get_microtime();
if ($this->iEvent)
{
$a = array_keys($this->aLogChrono[$this->iEvent-1]);
$this->aLogChrono[$this->iEvent][$s_event_label][$i_level]['microtime_since_previous']
= $this->aLogChrono[$this->iEvent][$s_event_label][$i_level]['microtime']
-$this->aLogChrono[$this->iEvent-1][$s_event_label][$i_level]['microtime'];
}
if ($this->iEvent)
$this->aLogChrono[$this->iEvent][$s_event_label][$i_level]['microtime_since_beginning'] = $this->micronow-$this->aLogChrono[$this->iEvent-1][$s_event_label][$i_level]['microtime'];
if (!isset($this->aLogLevels[$i_level]) || !isset($this->aLogLevels[$i_level][$s_event_label]) || !in_array($str_description, $this->aLogLevels[$i_level][$s_event_label]))
$this->aLogLevels[$i_level][$s_event_label][] = $str_description;
$this->aLogFunction[$s_event_label][$i_level][] = $str_description;
$this->iEvent++;
}
/**
* Returns true if $str_function casted a log with level $i_level
* @param integer Level Id
* @param string Function name
* @uses Logger::$aLogFunction
* @return bool
*/
public function ErrorLogged($i_level, $str_function)
{
if (isset($this->aLogFunction[$str_function])&&isset($this->aLogFunction[$str_function][$i_level])&&is_array($this->aLogFunction[$str_function][$i_level]))
return true;
else
return false;
}
/**
* Prints chronologic log
* @param string Error level string
* @uses Logger::$aLogFunction
* @return bool
*/
public function ShowLog($s_error_level='any')
{
$i_total_time = get_microtime() - $this->micronow;
$str_output = '';
$str_output .= "| Logger |
";
$str_output .= "| Call Stack |
";
$str_output .= "| # | Percent of script | Memory | Function | Location |
";
foreach ($this->aLogChrono as $i_event => $a_events)
{
foreach ($a_events as $s_event => $a_event)
{
foreach ($a_event as $i_level => $a_logged)
{
if ($a_logged['microtime_since_previous']!=$i_total_time)
$str_output .= "| ".$i_event." | ".(round(($a_logged['microtime_since_previous']/$i_total_time)*100,2))." | ".$a_logged['microtime_since_previous']." : ".$a_logged['microtime_since_previous']." | ".$a_logged['description']." | ".$s_event." |
";
}
}
}
$str_output .= '
';
echo $str_output;
//print_r($this->aLogChrono);
}
/**
* Function to return notices if there are any.
* If function returns false, it's a good idea to to use Logger::ReturnSuccessNotices().
* Default : [ error, user_notice, user_error ], all functions
* @param array Array of interresting levels, default are error levels
* @uses Logger::$aLogLevels
* @uses $aLoggerConfig
* @return bool
*/
public function ReturnNotices($r_levels = NULL)
{
global $aLoggerConfig;
if (!is_null($r_levels) && is_numeric($r_levels))
$r_levels = array($r_levels);
if (is_null($r_levels) || !is_array($r_levels) || (is_array($r_levels) && count($r_levels)<1))
$r_levels = array($aLoggerConfig['aErrorLevelIds']['error'], $aLoggerConfig['aErrorLevelIds']['user_notice'], $aLoggerConfig['aErrorLevelIds']['user_error']);
$a_logs = array();
foreach ($r_levels as $i_level)
{
if (isset($this->aLogLevels[$i_level]))
$a_logs += $this->aLogLevels[$i_level];
}
if (is_array($a_logs) && count($a_logs)>0)
return $a_logs;
return false;
}
/**
* Function to return success notices if there are any.
* @uses Logger::$aLogLevels
* @uses $aLoggerConfig
* @return bool
*/
public function ReturnSuccessNotices()
{
global $aLoggerConfig;
return $this->ReturnNotices($aLoggerConfig['aErrorLevelIds']['success_notice']);
}
}
?>