MAX_TIME && !defined('TIME_EXCEPTION')) {
$Reason[] = number_format($Micro, 3).' ms';
}
$Errors = count($this->get_errors());
if ($Errors > MAX_ERRORS && !defined('ERROR_EXCEPTION')) {
$Reason[] = $Errors.' PHP errors';
}
/*
$Queries = count($this->get_queries());
if ($Queries > MAX_QUERIES && !defined('QUERY_EXCEPTION')) {
$Reason[] = $Queries.' Queries';
}
*/
$Ram = memory_get_usage(true);
if ($Ram > MAX_MEMORY && !defined('MEMORY_EXCEPTION')) {
$Reason[] = Format::get_size($Ram).' RAM used';
}
G::$DB->warnings(); // See comment in MYSQL::query
/*
$Queries = $this->get_queries();
$DBWarningCount = 0;
foreach ($Queries as $Query) {
if (!empty($Query[2])) {
$DBWarningCount += count($Query[2]);
}
}
if ($DBWarningCount) {
$Reason[] = $DBWarningCount . ' DB warning(s)';
}
*/
$CacheStatus = G::$Cache->server_status();
if (in_array(0, $CacheStatus) && !G::$Cache->get_value('cache_fail_reported')) {
// Limit to max one report every 15 minutes to avoid massive debug spam
G::$Cache->cache_value('cache_fail_reported', true, 900);
$Reason[] = "Cache server error";
}
if (isset($_REQUEST['profile'])) {
$Reason[] = 'Requested by ' . G::$LoggedUser['Username'];
}
$this->Perf['Memory usage'] = (($Ram>>10) / 1024).' MB';
$this->Perf['Page process time'] = number_format($Micro / 1000, 3).' s';
$this->Perf['CPU time'] = number_format($this->get_cpu_time() / 1000000, 3).' s';
if (isset($Reason[0])) {
$this->log_var($CacheStatus, 'Cache server status');
$this->analysis(implode(', ', $Reason));
return true;
}
return false;
}
public function analysis($Message, $Report = '', $Time = 43200)
{
global $Document;
if (empty($Report)) {
$Report = $Message;
}
$Identifier = Users::make_secret(5);
G::$Cache->cache_value(
'analysis_'.$Identifier,
array(
'url' => $_SERVER['REQUEST_URI'],
'message' => $Report,
'errors' => $this->get_errors(true),
'queries' => $this->get_queries(),
'flags' => $this->get_flags(),
'includes' => $this->get_includes(),
'cache' => $this->get_cache_keys(),
'vars' => $this->get_logged_vars(),
'perf' => $this->get_perf(),
'ocelot' => $this->get_ocelot_requests()
),
$Time
);
$RequestURI = !empty($_SERVER['REQUEST_URI']) ? substr($_SERVER['REQUEST_URI'], 1) : '';
send_irc(DEBUG_CHAN, "$Message $Document ".site_url()."tools.php?action=analysis&case=$Identifier ".site_url().$RequestURI);
}
public function get_cpu_time()
{
if (!defined('PHP_WINDOWS_VERSION_MAJOR')) {
global $CPUTimeStart;
$RUsage = getrusage();
$CPUTime = $RUsage['ru_utime.tv_sec'] * 1000000 + $RUsage['ru_utime.tv_usec'] - $CPUTimeStart;
return $CPUTime;
}
return false;
}
public function log_var($Var, $VarName = false)
{
$BackTrace = debug_backtrace();
$ID = Users::make_secret(5);
if (!$VarName) {
$VarName = $ID;
}
$File = array('path' => substr($BackTrace[0]['file'], strlen(SERVER_ROOT)), 'line' => $BackTrace[0]['line']);
$this->LoggedVars[$ID] = array($VarName => array('bt' => $File, 'data' => $Var));
}
public function set_flag($Event)
{
global $ScriptStartTime;
$this->Flags[] = array($Event, (microtime(true) - $ScriptStartTime) * 1000, memory_get_usage(true), $this->get_cpu_time());
}
// This isn't in the constructor because $this is not available, and the function cannot be made static
public function handle_errors()
{
//error_reporting(E_ALL ^ E_STRICT | E_WARNING | E_DEPRECATED | E_ERROR | E_PARSE); //E_STRICT disabled
error_reporting(E_WARNING | E_ERROR | E_PARSE);
set_error_handler(array($this, 'php_error_handler'));
}
protected function format_args($Array)
{
$LastKey = -1;
$Return = [];
foreach ($Array as $Key => $Val) {
$Return[$Key] = '';
if (!is_int($Key) || !is_int($LastKey) || $Key != $LastKey + 1) {
$Return[$Key] .= "'$Key' => ";
}
if ($Val === true) {
$Return[$Key] .= 'true';
} elseif ($Val === false) {
$Return[$Key] .= 'false';
} elseif (is_string($Val)) {
$Return[$Key] .= "'$Val'";
} elseif (is_int($Val)) {
$Return[$Key] .= $Val;
} elseif (is_object($Val)) {
$Return[$Key] .= get_class($Val);
} elseif (is_array($Val)) {
$Return[$Key] .= 'array('.$this->format_args($Val).')';
}
$LastKey = $Key;
}
return implode(', ', $Return);
}
public function php_error_handler($Level, $Error, $File, $Line)
{
// Who added this, it's still something to pay attention to...
if (stripos('Undefined index', $Error) !== false) {
//return true;
}
$Steps = 1; // Steps to go up in backtrace, default one
$Call = '';
$Args = '';
$Tracer = debug_backtrace();
// This is in case something in this function goes wrong and we get stuck with an infinite loop
if (isset($Tracer[$Steps]['function'], $Tracer[$Steps]['class']) && $Tracer[$Steps]['function'] == 'php_error_handler' && $Tracer[$Steps]['class'] == 'DEBUG') {
return true;
}
// If this error was thrown, we return the function which threw it
if (isset($Tracer[$Steps]['function']) && $Tracer[$Steps]['function'] == 'trigger_error') {
$Steps++;
$File = $Tracer[$Steps]['file'];
$Line = $Tracer[$Steps]['line'];
}
// At this time ONLY Array strict typing is fully supported.
// Allow us to abuse strict typing (IE: function test(Array))
if (preg_match('/^Argument (\d+) passed to \S+ must be an (array), (array|string|integer|double|object) given, called in (\S+) on line (\d+) and defined$/', $Error, $Matches)) {
$Error = 'Type hinting failed on arg '.$Matches[1]. ', expected '.$Matches[2].' but found '.$Matches[3];
$File = $Matches[4];
$Line = $Matches[5];
}
// Let's not be repetative
if (($Tracer[$Steps]['function'] == 'include' || $Tracer[$Steps]['function'] == 'require') && isset($Tracer[$Steps]['args'][0]) && $Tracer[$Steps]['args'][0] == $File) {
unset($Tracer[$Steps]['args']);
}
// Class
if (isset($Tracer[$Steps]['class'])) {
$Call .= $Tracer[$Steps]['class'].'::';
}
// Function & args
if (isset($Tracer[$Steps]['function'])) {
$Call .= $Tracer[$Steps]['function'];
if (isset($Tracer[$Steps]['args'][0])) {
$Args = $this->format_args($Tracer[$Steps]['args']);
}
}
// Shorten the path & we're done
$File = str_replace(SERVER_ROOT, '', $File);
$Error = str_replace(SERVER_ROOT, '', $Error);
if (DEBUG_MODE) {
$this->Errors[] = array($Error, $File.':'.$Line, $Call, $Args);
}
return true;
}
/* Data wrappers */
public function get_perf()
{
if (empty($this->Perf)) {
global $ScriptStartTime;
$PageTime = (microtime(true) - $ScriptStartTime);
$CPUTime = $this->get_cpu_time();
$Perf = array(
'Memory usage' => Format::get_size(memory_get_usage(true)),
'Page process time' => number_format($PageTime, 3).' s');
if ($CPUTime) {
$Perf['CPU time'] = number_format($CPUTime / 1000000, 3).' s';
}
return $Perf;
}
return $this->Perf;
}
public function get_flags()
{
return $this->Flags;
}
public function get_errors($Light = false)
{
// Because the cache can't take some of these variables
if ($Light) {
foreach ($this->Errors as $Key => $Value) {
$this->Errors[$Key][3] = '';
}
}
return $this->Errors;
}
public function get_constants()
{
return get_defined_constants(true);
}
public function get_classes()
{
foreach (get_declared_classes() as $Class) {
$Classes[$Class]['Vars'] = get_class_vars($Class);
$Classes[$Class]['Functions'] = get_class_methods($Class);
}
return $Classes;
}
public function get_extensions()
{
foreach (get_loaded_extensions() as $Extension) {
$Extensions[$Extension]['Functions'] = get_extension_funcs($Extension);
}
return $Extensions;
}
public function get_includes()
{
return get_included_files();
}
public function get_cache_time()
{
return G::$Cache->Time;
}
public function get_cache_keys()
{
return array_keys(G::$Cache->CacheHits);
}
public function get_sphinxql_queries()
{
if (class_exists('Sphinxql')) {
return Sphinxql::$Queries;
}
}
public function get_sphinxql_time()
{
if (class_exists('Sphinxql')) {
return Sphinxql::$Time;
}
}
public function get_queries()
{
return G::$DB->Queries;
}
public function get_query_time()
{
return G::$DB->Time;
}
public function get_logged_vars()
{
return $this->LoggedVars;
}
public function get_ocelot_requests()
{
if (class_exists('Tracker')) {
return Tracker::$Requests;
}
}
/* Output Formatting */
public function perf_table($Perf = false)
{
if (!is_array($Perf)) {
$Perf = $this->get_perf();
}
if (empty($Perf)) {
return;
} ?>
View Performance Statistics: |
$Value) {
?>
=$Stat?>
|
=$Value?>
|
get_includes();
} ?>
View
=number_format(count($Includes))?>
Includes:
|
get_classes();
} ?>
get_extensions());
echo "\n"; ?>
|
get_flags();
}
if (empty($Flags)) {
return;
} ?>
Event |
Page time |
CPU time |
Memory |
=$Event?>
|
=number_format($MicroTime, 3)?> ms |
=number_format($CPUTime / 1000, 3)?> ms |
=Format::get_size($Memory)?>
|
get_constants();
} ?>
=display_str(print_r($Constants, true))?>
|
get_ocelot_requests();
}
if (empty($OcelotRequests)) {
return;
} ?>
View
=number_format(count($OcelotRequests))?>
Ocelot requests:
|
$Request) { ?>
=display_str($Request['path'])?>
=display_str($Request['response'])?>
|
=display_str($Request['status'])?>
|
=number_format($Request['time'], 5)?> ms
|
get_cache_keys();
$Header .= ' ('.number_format($this->get_cache_time(), 5).' ms)';
}
if (empty($CacheKeys)) {
return;
}
$Header = ' '.number_format(count($CacheKeys))." $Header:"; ?>
get_errors();
}
if (empty($Errors)) {
return;
} ?>
View
=number_format(count($Errors))?>
Errors:
|
=display_str($Call)?>(=display_str($Args)?>)
|
=display_str($Error)?>
|
=display_str($Location)?>
|
get_queries();
$Header .= ' ('.number_format($this->get_query_time(), 5).' ms)';
}
if (empty($Queries)) {
return;
}
$Header = ' '.number_format(count($Queries))." $Header:"; ?>
', $Warnings);
} ?>
=str_replace("\t", ' ', nl2br(display_str(trim($SQL))))?>
|
=number_format($Time, 5)?> ms |
=$Warnings?>
|
get_sphinxql_queries();
$Header .= ' ('.number_format($this->get_sphinxql_time(), 5).' ms)';
}
if (empty($Queries)) {
return;
}
$Header = ' '.number_format(count($Queries))." $Header:"; ?>
=str_replace("\t", ' ', $Params)?>
|
=number_format($Time, 5)?> ms |
LoggedVars)) {
return;
}
$Vars = $this->LoggedVars;
}
$Header = ' '.number_format(count($Vars))." $Header:"; ?>
$Var) {
$Key = key($Var);
$Data = current($Var);
$Size = count($Data['data']); ?>
=display_str($Key)?>
(=$Size . ($Size == 1 ? ' element' : ' elements')?>)
=$Data['bt']['path'].':'.$Data['bt']['line']; ?>
|
=display_str(print_r($Data['data'], true))?>
|