Don't mix data model and UI: move debug css to css files
[gitphp.git] / include / DebugLog.class.php
blob:a/include/DebugLog.class.php -> blob:b/include/DebugLog.class.php
<?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>&nbsp; <span class='debug_toggle' onclick='bt_toggle(\"$bt_id\");'>trace</span>&nbsp;
<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>';
} }
} }
   
comments