PDA

View Full Version : [FREE SCRIPT] Logger and script execution timer class



Floydian
04-09-2009, 08:30 AM
Yeah, I know, there are many scripts available for logging and script execution timing. I'm posting this script in the hopes that some folks find it useful.

The purpose of this script is: the script provides a simple logging interface that logs messages and sorts them into seperate categories. All log messages can be retrieved as an array which can then be easily displayed.

This script will be packaged with the next version of the Horizons Game Engine. [Click here for info on the Horizons Game Engine. (http://www.phphorizons.com) I personally didn't include anything to format log output because the Horizons Game Engine already has a function that takes an array and pretty prints it for you. Therefore, Horizons Game Owners should use the decho() function to format log data output.

As a convenience, this class also provides a simple timing facility that acts like a stopwatch. Each time you set the stopwatch the script will set a data point for that. When you finish timing the script, you can output script execution data in tabular format with the provided interface. It will give you the total execution time, the time interval between each data point, and a running tally of total time at each data point.

If you have any problems using the script, please post your questions here. This script does require php >= 5.0.0. If someone wants to make it php < 5 compatible, that's great. And if anyone wants to add or alter the script, that's great as well. All I ask is that you keep the main doc block and list any changes you make.



<?php
/**
* @author Floydian
* @link http://www.phphorizons.com
* @version 1.0.0
* @license Free to use, modify, and distribute so long as this doc block is maintained and present
* in any copies of this software and any modification, if made, must be noted.
* This software is provided as is and with no guarantees of anything
* at all. Use at your own risk ;)
*
* @desc
* A class for logging messages or any kind of data.
* Messages can be arrays, but will probably be strings
* most of the time.
*
* The ErrorCount property will count how
* many individual logs have been recorded
* across all instances of the Logger class.
*
* The BC_SCALE property allows the bc math function
* scale to be set across all instances of this class.
* Setting this also sets the scale used by the round()
* function within this class.
*/
class Logger {

static $ErrorCount = 0,
$BC_SCALE = 4;

protected $logs = array(),
$chrono = array();

/**
* Records messages into a set of arrays
* determined by the $types passed in.
* Each new $type sets a new array of logs.
* Therefore it's possible to log multiple
* types of things with one instance of the log
* class.
*
* @param string $type
* @param mixed $message
*/
function log($type, $message) {
if (is_null($type) or strlen($type) < 1) {
$type = 'General';
}
if (!isset($this->logs[$type])) {
$this->logs[$type] = array();
}
$count = array_push($this->logs[$type], $message);
$this->chrono[] = array('type' => $type, 'key' => $count - 1);
self::$ErrorCount++;
}

/**
* Gets the last log entry.
* It returns an array in the form of ('type' => $type, 'message' => $message)
*
* @return array
*/
function getLastLog() {
$count = count($this->chrono);
if ($count < 1) {
return array();
} else {
$type = $this->chrono[$count]['type'];
return array('type' => $type, 'message' => end($this->logs[$type]));
}
}

/**
* Gets the last log entry of a particular type.
* It returns an array in the form of ('type' => $type, 'message' => $message)
*
* @param string $type
* @return array
*/
function getLastLogByType($type) {
if (!isset($this->logs[$type])) {
return array();
} else {
return array('type' => $type, 'message' => end($this->logs[$type]));
}
}

/**
* Returns the raw array used to store log messages.
* This method and Logger::getLogsByType()
* are the only two methods that output log data in array form
* that don't do so in the ('type' => $type, 'message' => $message) format.
* The format is instead an array of types, each having an array of messages
* numerically indexed.
*
* @return array
*/
function getAllLogs() {
return $this->logs;
}

/**
* Returns an array of logs in chronological order. Logs are
* output as an array of ('type' => $type, 'message' => $message) arrays.
*
* @return array
*/
function getAllLogsChrono() {
$log_list = array();
foreach ($this->chrono as $log_address) {
$type = $log_address['type'];
$log_list[] = array('type' => $type, 'message' => $this->logs[$type][$log_address['key']]);
}
return $log_list;
}

/**
* Returns all logs that are of the type specified.
* This method and Logger::getAllLogs()
* are the only two methods that output log data in array form
* that don't do so in the ('type' => $type, 'message' => $message) format.
* The format is instead a numerically indexed array of messages.
*
* @param string $type
* @return unknown
*/
function getLogsByType($type) {
if (!isset($this->logs[$type])) {
return array();
} else {
return $this->logs[$type];
}
}

/**
* List the number of logs recorded
* in this instance of the Logger class.
*
* @return integer
*/
function getLogCount() {
return count($this->chrono);
}

/**
* Provides rudimentary script execution
* timing facilities. Executing this
* method more than once will set
* multiple data points.
*
* @param string $message
*/
function setTimer($message = '') {
$this->log('SCRIPT TIMER', array(microtime(true), $message));
}

/**
* Gather and format script execution
* timing data.
*
* @return string
*/
function getTimerResults() {
$timers = $this->getLogsByType('SCRIPT TIMER');
$timer_log = '';
$start_time = null;
$last_time = null;
$running_total = 0;
$count = 0;
bcscale(self::$BC_SCALE);
foreach ($timers as $data) {
if (is_array($data)) {
$count++;
$time = $data[0];
$message = $data[1];

if (is_null($start_time)) {
$start_time = $time;
$last_time = $time;
}
$diff = bcsub($time, $last_time);
$running_total = bcadd($running_total, $diff);
$timer_log .= <<<EOT
<tr>
<td style="text-align: right; padding-right: 10px">
$count
</td>
<td style="text-align: right; padding-right: 10px">
$diff
</td>
<td style="text-align: right; padding-right: 10px">
$running_total
</td>
<td style="text-align: left">
$message
</td>
</tr>
EOT;
$last_time = $time;
}
}

if ($count > 0) {
$total_time = round($last_time - $start_time, self::$BC_SCALE);
return <<<EOT
<table>
<tr>
<th>
Count
</th>
<th>
Increment
</th>
<th>
Total
</th>
<th>
Message
</th>
</tr>
$timer_log
<tr>
<td colspan="3">
Total execution time: $total_time seconds
</td>
</tr>
</table>
EOT;
} else {
return "No timing data found...";
}
}
}