<?php
/**
* @package Pygalle
* @copyright Copyright (C) 2008 Erik Finnegan. All rights reserved.
* @license GNU/GPL, see LICENSE.php
* @author hide@address.com
* Joomla! and Pygalle EVE Corporate Intranet are free software.
* This version may have been modified pursuant
* to the GNU General Public License, and as distributed it includes or
* is derivative of works licensed under the GNU General Public License or
* other free or open source software licenses.
* See COPYRIGHT.php for copyright notices and details.
*/
jimport('joomla.error.log');
define( '_PY_LEVEL_TRACE', 4);
define( '_PY_LEVEL_DEBUG', 3);
define( '_PY_LEVEL_INFO', 3);
define( '_PY_LEVEL_WARN', 2);
define( '_PY_LEVEL_ERROR', 1);
class PyLog extends JLog {
function & getInstance( $logLevel=null, $logFilename="pygalle_debug.log") {
static $instances;
$config =& JFactory::getConfig();
$path = $config->getValue('config.log_path');
jimport('joomla.filesystem.path');
$path = JPath :: clean($path . DS . $logFilename);
$sig = md5($path);
if (!isset ($instances)) {
$instances = array ();
}
if ( $logLevel === null) {
$params = JComponentHelper::getParams( 'com_pygalle');
if ( $params) {
$logLevel = $params->get( 'log_level', _PY_LEVEL_TRACE);
$logLevel = min( _PY_LEVEL_TRACE, max( _PY_LEVEL_ERROR, $logLevel));
} else {
$logLevel = _PY_LEVEL_TRACE;
}
}
if (empty ($instances[$sig])) {
$instances[$sig] = new PyLog($path, array( '_level' => $logLevel));
}
return $instances[$sig];
}
function setOptions( $options) {
if (parent::setOptions( $options)) {
//FIXME remove 'format' value from array
}
$this->setProperties( $options);
}
private function log( $level) {
if ($level <= $this->_level) {
$args = @func_get_args();
// throw away the $level argument
$args = array_slice( $args, 1);
$args = $args[0];
if ( count($args) == 0) {
$args[] = 'touch';
}
// make a prefix of either calling class->method name or executing file and the previous call
$prefix = '';
$stack = debug_backtrace();
if ( isset($stack[2]['class'])) {
$prefix = $stack[2]['class'].$stack[2]['type'].$stack[2]['function'];
} else {
$currentFile = $stack[1]['file'];
$pathDelimeter = strrpos( $currentFile, DS);
if ( !$pathDelimeter) $pathDelimeter = -1;
$prefix .= substr( $currentFile, $pathDelimeter + 1);
// retrieve calling object/file from stack trace
$stackDepth = count( $stack);
$i = 3;
// iterate through stack until object found
do {
$lastCall = $stack[$i];
$i++;
} while ( empty( $lastCall['class']) && $i < $stackDepth);
$class = $lastCall['class'];
$prefix .= " (";
$prefix .= ($class.$lastCall['type'].$lastCall['function']);
$prefix .= ')';
}
// trunkate and pad prefix to 55 chars
$prefix = substr( str_pad( $prefix, 40, ' ', STR_PAD_LEFT), 0, 55 );
// create output for log arguments
foreach( $args as $output) {
$message = $prefix."\t".$this->printRecursive($output);
$this->addEntry( array( 'level' => $level, 'comment' => $message));
}
}
}
/**
* Log all parameters with priority _PY_LEVEL_TRACE
*
* @param mixed arg List of arguments
*/
function trace() {
$args = func_get_args();
$this->log( _PY_LEVEL_TRACE, $args);
}
/**
* Log all parameters with priority _PY_LEVEL_DEBUG
*
* @param mixed arg List of arguments
*/
function debug() {
$args = func_get_args();
$this->log( _PY_LEVEL_DEBUG, $args);
}
/**
* Log all parameters with priority _PY_LEVEL_ERROR
*
* @param mixed arg List of arguments
*/
function error() {
$args = func_get_args();
$this->log( _PY_LEVEL_ERROR, $args);
}
/**
* Log all parameters with priority _PY_LEVEL_INFO
*
* @param mixed arg List of arguments
*/
function info() {
$args = func_get_args();
$this->log( _PY_LEVEL_INFO, $args);
}
function is_tracing () {
return $this->_level == _PY_LEVEL_TRACE;
}
/**
* Creates a string representation of the object given.
* Depth should not be specified when calling the function. It is used internally to
* end recursion.
*
* @param object $object
* @param int $depth
* @return String
* @static
*/
static function printRecursive( $object, $depth=4) {
// ripcord
if ( !$depth) return gettype( $object);
$returnVal = '';
if ( $object instanceof JDatabase || $object instanceof JDatabaseMySQL) {
$returnVal = "Current database state... \n"."last query: ".$object->getQuery()."\nresult rows: ".@$object->getNumRows()."\nError (if any): ".$object->getErrorMsg();
} else if ( $object instanceof RuntimeException || $object instanceof JException) {
$returnVal = '('.$object->getCode().') '.$object->getMessage();
} else if ( $object instanceof JDate) {
$returnVal = " <JDate> [" . $object->toMySQL() . ", " . $object->toUnix() . "]";
} else if ( is_object( $object)) {
$returnVal = " <" . get_class( $object) . "> [\n";
foreach ( $vars = get_object_vars( $object) as $k => $v) {
$returnVal .= $k . ' => '.PyLog::printRecursive($v, $depth - 1)."\n";
}
$returnVal .= "]";
$returnVal .= "\n" ;
} else if ( is_array( $object)) {
$returnVal .= " <Array> {\n";
foreach ( $object as $k => $v) {
$returnVal .= $k . ' => '.PyLog::printRecursive($v, $depth - 1)."\n";
}
$returnVal .= "}";
$returnVal .= "\n";
} else if ( $object === false) {
$returnVal = 'false';
} else if ( $object === true) {
$returnVal = 'true';
} else if ( $object === null) {
$returnVal = 'null';
} else {
$returnVal = $object;
}
return $returnVal;
}
function outputIsComplex( $output) {
return is_object( $output) || is_array( $output) || is_a( $output, 'JDatabase');
}
function printStackTrace() {
$this->trace( $this->_buildStackTrace());
}
private static function _buildStackTrace() {
$stack = debug_backtrace();
$output = '';
for ( $i = 1; $i < 10 && $stack[$i] != null; $i++) {
$lastCall = $stack[$i];
$class = $lastCall['class'];
if ( $class) {
$prefix = $class.$lastCall['type'].$lastCall['function'];
} else {
$pathDelimeter = strrpos( $lastCall['file'], DS);
if ( !$pathDelimeter) $pathDelimeter = -1;
$prefix = substr( $lastCall['file'], $pathDelimeter + 1);
}
$output .= $prefix;
$output .= PyLog::printRecursive( $lastCall, 2);
$output .= "\n";
}
return $output;
}
}