<?php |
<?php |
/** |
/** |
* Debug logging class |
* Debug logging class |
* |
* |
* @author Christopher Han <xiphux@gmail.com> |
* @author Christopher Han <xiphux@gmail.com> |
* @copyright Copyright (c) 2010 Christopher Han |
* @copyright Copyright (c) 2010 Christopher Han |
* @package GitPHP |
* @package GitPHP |
*/ |
*/ |
class GitPHP_DebugLog implements GitPHP_Observer_Interface |
class GitPHP_DebugLog implements GitPHP_Observer_Interface |
{ |
{ |
/** |
/** |
* Stores whether logging is enabled |
* Stores whether logging is enabled |
* |
* |
* @var boolean |
* @var boolean |
*/ |
*/ |
protected $enabled = false; |
protected $enabled = false; |
|
|
/** |
/** |
* Stores whether benchmarking is enabled |
* Stores whether benchmarking is enabled |
* |
* |
* @var boolean |
* @var boolean |
*/ |
*/ |
protected $benchmark = false; |
protected $benchmark = false; |
|
|
/** |
/** |
* Stores the starting instant |
* Stores the starting instant |
* |
* |
* @var float |
* @var float |
*/ |
*/ |
protected $startTime; |
protected $startTime; |
|
|
/** |
/** |
* Stores the starting memory |
* Stores the starting memory |
* |
* |
* @var int |
* @var int |
*/ |
*/ |
protected $startMem; |
protected $startMem; |
|
|
/** |
/** |
* Stores the log entries |
* Stores the log entries |
* |
* |
* @var string[] |
* @var string[] |
*/ |
*/ |
protected $entries = array(); |
protected $entries = array(); |
|
|
/** |
/** |
* Stores the timers |
* Stores the timers |
* |
* |
* @var float[] |
* @var float[] |
*/ |
*/ |
protected $timers = array(); |
protected $timers = array(); |
|
|
/** |
/** |
* @return GitPHP_DebugLog |
* @return GitPHP_DebugLog |
*/ |
*/ |
public static function GetInstance() |
public static function GetInstance() |
{ |
{ |
static $instance; |
static $instance; |
if (!$instance) $instance = new self(); |
if (!$instance) $instance = new self(); |
return $instance; |
return $instance; |
} |
} |
|
|
/** |
/** |
* You must use GetInstance() |
* You must use GetInstance() |
*/ |
*/ |
private function __construct() |
private function __construct() |
{ |
{ |
} |
} |
|
|
/** |
/** |
* Constructor |
* Constructor |
* |
* |
* @param boolean $enabled whether log should be enabled |
* @param boolean $enabled whether log should be enabled |
* @param boolean $benchmark whether benchmarking should be enabled |
* @param boolean $benchmark whether benchmarking should be enabled |
*/ |
*/ |
public function init($enabled = false, $benchmark = false) |
public function init($enabled = false, $benchmark = false) |
{ |
{ |
$this->startTime = microtime(true); |
$this->startTime = microtime(true); |
$this->startMem = memory_get_usage(); |
$this->startMem = memory_get_usage(); |
|
|
$this->enabled = $enabled; |
$this->enabled = $enabled; |
$this->benchmark = $benchmark; |
$this->benchmark = $benchmark; |
} |
} |
|
|
/** |
/** |
* Sets start time |
* Sets start time |
* |
* |
* @param float $start starting microtime |
* @param float $start starting microtime |
*/ |
*/ |
public function SetStartTime($start) |
public function SetStartTime($start) |
{ |
{ |
$this->startTime = $start; |
$this->startTime = $start; |
} |
} |
|
|
/** |
/** |
* Sets start memory |
* Sets start memory |
* |
* |
* @param integer $start starting memory |
* @param integer $start starting memory |
*/ |
*/ |
public function SetStartMemory($start) |
public function SetStartMemory($start) |
{ |
{ |
$this->startMem = $start; |
$this->startMem = $start; |
} |
} |
|
|
/** |
/** |
* Shortcut to start timer |
* Shortcut to start timer |
*/ |
*/ |
public function TimerStart() |
public function TimerStart() |
{ |
{ |
if (!$this->benchmark) return; |
if (!$this->benchmark) return; |
$this->Log('', '', 'start'); |
$this->Log('', '', 'start'); |
} |
} |
|
|
/** |
/** |
* Shortcut to stop timer |
* Shortcut to stop timer |
* |
* |
* @param $msg |
* @param $msg |
* @param $msg_data |
* @param $msg_data |
*/ |
*/ |
public function TimerStop($msg, $msg_data = '') |
public function TimerStop($msg, $msg_data = '') |
{ |
{ |
if (!$this->benchmark) return; |
if (!$this->benchmark) return; |
$this->Log($msg, $msg_data, 'stop'); |
$this->Log($msg, $msg_data, 'stop'); |
} |
} |
|
|
/** |
/** |
* Log an entry |
* Log an entry |
* |
* |
* @param string $msg message to log |
* @param string $msg message to log |
*/ |
*/ |
public function Log($msg, $msg_data = '', $type = 'ts') |
public function Log($msg, $msg_data = '', $type = 'ts') |
{ |
{ |
if (!$this->enabled) |
if (!$this->enabled) |
return; |
return; |
|
|
$entry = array(); |
$entry = array(); |
|
|
if ($type == 'start') { |
if ($type == 'start') { |
array_push($this->timers, microtime(true)); |
array_push($this->timers, microtime(true)); |
return; |
return; |
} else if ($type == 'stop') { |
} else if ($type == 'stop') { |
$timer = array_pop($this->timers); |
$timer = array_pop($this->timers); |
$entry['time'] = $duration = microtime(true) - $timer; |
$entry['time'] = $duration = microtime(true) - $timer; |
foreach ($this->timers as &$item) $item += $duration; |
foreach ($this->timers as &$item) $item += $duration; |
} else { |
} else { |
if ($this->benchmark) { |
if ($this->benchmark) { |
$entry['time'] = (microtime(true) - $this->startTime); |
$entry['time'] = (microtime(true) - $this->startTime); |
$entry['reltime'] = true; |
$entry['reltime'] = true; |
$entry['mem'] = memory_get_usage(); |
$entry['mem'] = memory_get_usage(); |
} |
} |
} |
} |
|
|
$entry['name'] = $msg; |
$entry['name'] = $msg; |
$entry['value'] = $msg_data; |
$entry['value'] = $msg_data; |
$bt = explode("\n", new Exception()); |
$bt = explode("\n", new Exception()); |
array_shift($bt); |
array_shift($bt); |
array_shift($bt); |
array_shift($bt); |
$entry['bt'] = implode("\n", $bt); |
$entry['bt'] = implode("\n", $bt); |
$this->entries[] = $entry; |
$this->entries[] = $entry; |
} |
} |
|
|
/** |
/** |
* Gets whether logging is enabled |
* Gets whether logging is enabled |
* |
* |
* @return boolean true if logging is enabled |
* @return boolean true if logging is enabled |
*/ |
*/ |
public function GetEnabled() |
public function GetEnabled() |
{ |
{ |
return $this->enabled; |
return $this->enabled; |
} |
} |
|
|
/** |
/** |
* Sets whether logging is enabled |
* Sets whether logging is enabled |
* |
* |
* @param boolean $enable true if logging is enabled |
* @param boolean $enable true if logging is enabled |
*/ |
*/ |
public function SetEnabled($enable) |
public function SetEnabled($enable) |
{ |
{ |
$this->enabled = $enable; |
$this->enabled = $enable; |
} |
} |
|
|
/** |
/** |
* Gets whether benchmarking is enabled |
* Gets whether benchmarking is enabled |
* |
* |
* @return boolean true if benchmarking is enabled |
* @return boolean true if benchmarking is enabled |
*/ |
*/ |
public function GetBenchmark() |
public function GetBenchmark() |
{ |
{ |
return $this->benchmark; |
return $this->benchmark; |
} |
} |
|
|
/** |
/** |
* Sets whether benchmarking is enabled |
* Sets whether benchmarking is enabled |
* |
* |
* @param boolean $bench true if benchmarking is enabled |
* @param boolean $bench true if benchmarking is enabled |
*/ |
*/ |
public function SetBenchmark($bench) |
public function SetBenchmark($bench) |
{ |
{ |
$this->benchmark = $bench; |
$this->benchmark = $bench; |
} |
} |
|
|
/** |
/** |
* Clears the log |
* Clears the log |
*/ |
*/ |
public function Clear() |
public function Clear() |
{ |
{ |
$this->entries = array(); |
$this->entries = array(); |
} |
} |
|
|
/** |
/** |
* Notify that observable object changed |
* Notify that observable object changed |
* |
* |
* @param GitPHP_Observable_Interface $object object |
* @param GitPHP_Observable_Interface $object object |
* @param int $changeType type of change |
* @param int $changeType type of change |
* @param array $args argument array |
* @param array $args argument array |
*/ |
*/ |
public function ObjectChanged($object, $changeType, $args = array()) |
public function ObjectChanged($object, $changeType, $args = array()) |
{ |
{ |
if ($changeType !== GitPHP_Observer_Interface::LoggableChange) |
if ($changeType !== GitPHP_Observer_Interface::LoggableChange) |
return; |
return; |
|
|
if (!$this->enabled) |
if (!$this->enabled) |
return; |
return; |
|
|
if (!isset($args[0]) || empty($args[0])) |
if (!isset($args[0]) || empty($args[0])) |
return; |
return; |
|
|
$msg = $args[0]; |
$msg = $args[0]; |
$msg_data = isset($args[1]) ? $args[1] : ''; |
$msg_data = isset($args[1]) ? $args[1] : ''; |
$type = isset($args[2]) ? $args[2] : 'ts'; |
$type = isset($args[2]) ? $args[2] : 'ts'; |
|
|
$this->Log($msg, $msg_data, $type); |
$this->Log($msg, $msg_data, $type); |
} |
} |
|
|
public function PrintHtml() |
public function PrintHtml() |
{ |
{ |
if (!$this->enabled) return; |
if (!$this->enabled) return; |
|
|
foreach ($this->entries as $i => $e) { |
foreach ($this->entries as $i => $e) { |
$bt_id = 'bt_' . $i; |
$bt_id = 'bt_' . $i; |
if (strlen($e['value']) > 512) { |
if (strlen($e['value']) > 512) { |
$contents = htmlspecialchars(substr($e['value'], 0, 512) . "..."); |
$contents = htmlspecialchars(substr($e['value'], 0, 512) . "..."); |
$contents .= "\n\n<i>" . (strlen($e['value']) - 512) . " bytes more in output</i>"; |
$contents .= "\n\n<i>" . (strlen($e['value']) - 512) . " bytes more in output</i>"; |
} else { |
} else { |
$contents = htmlspecialchars($e['value']); |
$contents = htmlspecialchars($e['value']); |
} |
} |
echo "<tr> |
echo "<tr> |
<td class='debug_key'>$e[name]</td> |
<td class='debug_key'>$e[name]</td> |
<td class='debug_value'> |
<td class='debug_value'> |
" . nl2br($contents) . ($contents != "" ? "<br§ />" : "") . " |
" . nl2br($contents) . ($contents != "" ? "<br§ />" : "") . " |
<span class='debug_toggle' onclick='bt_toggle(\"$bt_id\");'>trace</span> |
<span class='debug_toggle' onclick='bt_toggle(\"$bt_id\");'>trace</span> |
<div style='display: none;' class='debug_bt' id='$bt_id'>$e[bt]</div> |
<div style='display: none;' class='debug_bt' id='$bt_id'>$e[bt]</div> |
</td> |
</td> |
<td class='debug_time'> |
<td class='debug_time'> |
" . ($e['time'] ? sprintf("%.1f", $e['time'] * 1000) : '') . " |
" . ($e['time'] ? sprintf("%.1f", $e['time'] * 1000) : '') . " |
" . ($e['time'] ? (!empty($e['reltime']) ? " ms from start" : " ms") : '') . " |
" . ($e['time'] ? (!empty($e['reltime']) ? " ms from start" : " ms") : '') . " |
</td> |
</td> |
</tr>"; |
</tr>"; |
} |
} |
} |
} |
|
|
public function PrintHtmlHeader() |
public function PrintHtmlHeader() |
{ |
{ |
if (!$this->enabled) return; |
if (!$this->enabled) return; |
|
|
echo |
echo |
<<<HEREDOC |
<<<HEREDOC |
<script type="text/javascript"> |
<script type="text/javascript"> |
function bt_toggle(id) { |
function bt_toggle(id) { |
var el = document.getElementById(id); |
var el = document.getElementById(id); |
el.style.display = ((el.style.display == 'none') ? 'block' : 'none'); |
el.style.display = ((el.style.display == 'none') ? 'block' : 'none'); |
} |
} |
</script> |
</script> |
<style type="text/css"> |
|
.debug { |
|
border: 0; |
|
border-spacing: 0; |
|
width: 100%; |
|
} |
|
.debug_toggle { |
|
color: #88a; border-bottom: 1px dashed blue; |
|
display: inline-block; |
|
margin: 3px; |
|
cursor: pointer; |
|
} |
|
.debug_key { |
|
background: #ccf; border-bottom: 1px solid #888; |
|
max-width: 100px; |
|
word-wrap: break-word; |
|
} |
|
.debug_value { |
|
background: #ccc; border-bottom: 1px solid #888; |
|
max-width: 900px; |
|
word-wrap: break-word; |
|
} |
|
.debug_bt { |
|
white-space: pre; |
|
} |
|
.debug_time { |
|
background: #cff; border-bottom: 1px solid #888; |
|
} |
|
</style> |
|
<table class="debug"><tbody> |
<table class="debug"><tbody> |
HEREDOC; |
HEREDOC; |
} |
} |
|
|
public function PrintHtmlFooter() |
public function PrintHtmlFooter() |
{ |
{ |
if (!$this->enabled) return; |
if (!$this->enabled) return; |
echo '</tbody></table>'; |
echo '</tbody></table>'; |
} |
} |
} |
} |
|
|