| <?php |
| /** |
| * File containing the ezcDebug class. |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| * @package Debug |
| * @version //autogentag// |
| * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 |
| */ |
| |
| /** |
| * The ezcDebug class provides functionality to format and store debug messages and timers. |
| * |
| * The functionality of the Debug component is two folded: |
| * - Debug log messages |
| * - Timers |
| * |
| * The log messages are heavily based on the {@link EventLog} log messages. In fact |
| * internally the EventLog is used with its own log writer. The {@link log()} method |
| * is almost the same as from the EventLog. The next example demonstrates how to instantiate the |
| * ezcDebug class and write some log messages: |
| * <code> |
| * $debug = ezcDebug::getInstance(); |
| * $debug->log( "Connecting with the paynet server", 2 ); |
| * // ... |
| * $debug->log( "Connection failed, retrying in 5 seconds", 1 ); |
| * // ... |
| * $debug->log( "Could not connect with the server", 0 ); |
| * </code> |
| * |
| * The second parameter of the log method is the verbosity. This is a number that |
| * specifies the importance of the log message. That makes it easier to sort out messages of less importance. |
| * In this example, we assumed the more important the message, the lower the |
| * verbosity number. |
| * |
| * The ezcDebug timer is designed to allow the next two timing methods: |
| * - Timers, the time between two points in the program. |
| * - Accumulators, gets the relative time after the script started. |
| * |
| * The "Timers" are simply set with the methods {@link startTimer()} and {@link stopTimer()}. The next example |
| * demonstrates the timing of a simple calculation: |
| * <code> |
| * $debug = ezcDebug::getInstance(); |
| * $debug->startTimer( "Simple calculation" ); |
| * |
| * // Simple calculation |
| * $result = 4 + 6; |
| * |
| * $debug->stopTimer( "Simple calculation" ); // Parameter can be omitted. |
| * </code> |
| * |
| * To get timing points, accumulators, use the {@link switchTimer()} method. This is shown in the next example: |
| * <code> |
| * $debug = ezcDebug::getInstance(); |
| * $debug->startTimer( "My script" ); |
| * // ... |
| * $debug->switchTimer( "Reading ini file" ); |
| * // ... |
| * $debug->switchTimer( "Initializing template parser" ); |
| * // ... |
| * $debug->switchTimer( "Parsing" ); |
| * // ... |
| * $debug->stopTimer(); |
| * </code> |
| * |
| * @property ezcDebugOptions $options |
| * Options to configure the behaviour of ezcDebug, including stack |
| * trace behaviours. |
| * |
| * @package Debug |
| * @version //autogentag// |
| * @mainclass |
| */ |
| class ezcDebug |
| { |
| /** |
| * Properties. |
| * |
| * @var array(string=>mixed) |
| */ |
| protected $properties = array(); |
| |
| /** |
| * Instance of the singleton ezcDebug object. |
| * |
| * Use the getInstance() method to retrieve the instance. |
| * |
| * @var ezcDebug |
| */ |
| private static $instance = null; |
| |
| /** |
| * The formatter that generates the debug output. |
| * |
| * @var ezcDebugFormatter |
| */ |
| private $formatter = null; |
| |
| /** |
| * A pointer to the logging system. |
| * |
| * @var ezcLog |
| */ |
| private $log = null; |
| |
| /** |
| * The timing object used to store timing information. |
| * |
| * @var ezcDebugTimer |
| */ |
| private $timer = null; |
| |
| /** |
| * The writer that holds debug output. |
| * |
| * @var ezcLogWriter |
| */ |
| private $writer = null; |
| |
| /** |
| * Constructs a new debug object and attaches it to the log object. |
| * |
| * This method is private because the getInstance() should be called. |
| */ |
| private function __construct() |
| { |
| $this->options = new ezcDebugOptions(); |
| |
| $original = ezcLog::getInstance(); |
| |
| $this->log = clone( $original ); |
| $this->log->reset(); |
| $this->log->setMapper( new ezcLogFilterSet() ); |
| |
| // Set the writer. |
| $this->writer = new ezcDebugMemoryWriter(); |
| |
| $filter = new ezcLogFilter(); |
| $filter->severity = ezcLog::DEBUG; |
| $this->log->getMapper()->appendRule( new ezcLogFilterRule( $filter, $this->writer, true ) ); |
| |
| $this->reset(); |
| } |
| |
| |
| /** |
| * Property get access. |
| * |
| * @throws ezcBasePropertyNotFoundException |
| * If the given property could not be found. |
| * @param string $propertyName |
| * @ignore |
| */ |
| public function __get( $propertyName ) |
| { |
| if ( $this->__isset( $propertyName ) ) |
| { |
| return $this->properties[$propertyName]; |
| } |
| throw new ezcBasePropertyNotFoundException( $propertyName ); |
| } |
| |
| /** |
| * Property set access. |
| * |
| * @throws ezcBasePropertyNotFoundException |
| * @param string $propertyName |
| * @param string $propertyValue |
| * @ignore |
| */ |
| public function __set( $propertyName, $propertyValue ) |
| { |
| switch ( $propertyName ) |
| { |
| case 'options': |
| if ( !( $propertyValue instanceof ezcDebugOptions ) ) |
| { |
| throw new ezcBaseValueException( |
| $propertyName, |
| $propertyValue, |
| 'ezcDebugOptions' |
| ); |
| } |
| break; |
| default: |
| throw new ezcBasePropertyNotFoundException( $propertyName ); |
| } |
| $this->properties[$propertyName] = $propertyValue; |
| } |
| |
| /** |
| * Property isset access. |
| * |
| * @param string $propertyName |
| * @return bool |
| * @ignore |
| */ |
| public function __isset( $propertyName ) |
| { |
| return array_key_exists( $propertyName, $this->properties ); |
| } |
| |
| |
| /** |
| * Resets the log messages and timer information. |
| * |
| * @return void |
| */ |
| public function reset() |
| { |
| $this->writer->reset(); |
| $this->timer = new ezcDebugTimer(); |
| } |
| |
| /** |
| * Returns the instance of this class. |
| * |
| * When the ezcDebug instance is created it is automatically added to the instance |
| * of ezcLog. |
| * |
| * @return ezcDebug |
| */ |
| public static function getInstance() |
| { |
| if ( is_null( self::$instance )) |
| { |
| self::$instance = new ezcDebug(); |
| ezcBaseInit::fetchConfig( 'ezcInitDebug', self::$instance ); |
| } |
| |
| return self::$instance; |
| } |
| |
| /** |
| * Returns the instance of the EventLog used in this class. |
| * |
| * The returned instance is not the same as retrieved via the |
| * ezcLog::getInstance() method. |
| * |
| * @return ezcLog |
| */ |
| public function getEventLog() |
| { |
| return $this->log; |
| } |
| |
| /** |
| * Sets the formatter $reporter for the output. |
| * |
| * If no formatter is set {@link ezcDebugHtmlReporter} will be used by default. |
| * |
| * @param ezcDebugOutputFormatter $formatter |
| * @return void |
| */ |
| public function setOutputFormatter( ezcDebugOutputFormatter $formatter ) |
| { |
| $this->formatter = $formatter; |
| } |
| |
| /** |
| * Returns the formatted debug output. |
| * |
| * @return string |
| */ |
| public function generateOutput() |
| { |
| if ( is_null( $this->formatter ) ) |
| $this->formatter = new ezcDebugHtmlFormatter(); |
| |
| return $this->formatter->generateOutput( $this->writer->getStructure(), $this->timer->getTimeData() ); |
| } |
| |
| |
| /** |
| * Starts the timer with the identifier $name. |
| * |
| * Optionally, a timer group can be given with the $group parameter. |
| * |
| * @param string $name |
| * @param string $group |
| */ |
| public function startTimer( $name, $group = null ) |
| { |
| $this->timer->startTimer( $name, $group ); |
| } |
| |
| /** |
| * Stores the time from the running timer, and starts a new timer. |
| * |
| * Stores the time for $oldTimer (maybe omitted if only 1 timer is running) |
| * and starts a new timer with $newName. |
| * |
| * @param string $newName |
| * @param string|bool $oldName |
| */ |
| public function switchTimer( $newName, $oldName = false ) |
| { |
| $this->timer->switchTimer( $newName, $oldName ); |
| } |
| |
| /** |
| * Stops the timer identified by $name. |
| * |
| * $name can be omitted (false) if only one timer is running. |
| * |
| * @param string|bool $name |
| */ |
| public function stopTimer( $name = false ) |
| { |
| $this->timer->stopTimer( $name ); |
| } |
| |
| /** |
| * Writes the debug message $message with verbosity $verbosity. |
| * |
| * Arbitrary $extraInfo can be submitted. If $stackTrace is set to true, a |
| * stack trace will be stored at the current program position. |
| * |
| * @param string $message |
| * @param int $verbosity |
| * @param array(string=>string) $extraInfo |
| * @param bool $stackTrace |
| */ |
| public function log( $message, $verbosity, array $extraInfo = array(), $stackTrace = false ) |
| { |
| // Add the verbosity |
| $extraInfo = array_merge( array( "verbosity" => $verbosity ), $extraInfo ); |
| if ( $this->options->stackTrace === true || $stackTrace === true ) |
| { |
| $extraInfo['stackTrace'] = $this->getStackTrace(); |
| } |
| $this->log->log( $message, ezcLog::DEBUG, $extraInfo ); |
| } |
| |
| /** |
| * Returns a stack trace iterator for the current call. |
| * |
| * Returns a |
| * - {@link ezcDebugXdebugStacktraceIterator} if Xdebug is available |
| * - {@link ezcDebugPhpStacktraceIterator} otherwise |
| * representing a stack trace of the current function environment. |
| * |
| * @return ezcDebugStacktraceIterator |
| */ |
| private function getStackTrace() |
| { |
| if ( extension_loaded( 'xdebug' ) ) |
| { |
| return new ezcDebugXdebugStacktraceIterator( |
| xdebug_get_function_stack(), |
| 2, |
| $this->options |
| ); |
| } |
| else |
| { |
| return new ezcDebugPhpStacktraceIterator( |
| debug_backtrace(), |
| 2, |
| $this->options |
| ); |
| } |
| } |
| |
| /** |
| * Dispatches the message and error type to the correct debug or log |
| * function. |
| * |
| * This function should be used as the set_error_handler from the |
| * trigger_error function. |
| * |
| * Use for example the following code in your application: |
| * |
| * <code> |
| * function debugHandler( $a, $b, $c, $d ) |
| * { |
| * ezcDebug::debugHandler( $a, $b, $c, $d ); |
| * } |
| * |
| * set_error_handler( "debugHandler" ); |
| * </code> |
| * |
| * Use trigger_error() to log warning, error, etc: |
| * |
| * <code> |
| * trigger_error( "[Paynet, templates] Cannot load template", E_USER_WARNING ); |
| * </code> |
| * |
| * See the PHP documentation of |
| * {@link http://php.net/trigger_error trigger_error} for more information. |
| * |
| * @param int $errno |
| * @param string $errstr |
| * @param string $errfile |
| * @param int $errline |
| * @return void |
| */ |
| public static function debugHandler( $errno, $errstr, $errfile, $errline ) |
| { |
| $debug = ezcDebug::getInstance(); |
| $log = $debug->getEventLog(); |
| |
| preg_match( |
| '/^\s*(?:\[([^,\]]*)(?:,\s(.*))?\])?\s*(?:(\d+):)?\s*(.*)$/', |
| $errstr, |
| $matches |
| ); |
| |
| $message = ( $matches[4] === '' ? false : $matches[4] ); |
| $verbosity = ( $matches[3] === '' ? false : $matches[3] ); |
| |
| if ( strlen( $matches[2] ) == 0 ) |
| { |
| $category = ( $matches[1] === '' ? $log->category : $matches[1] ); |
| $source = $log->source; |
| } |
| else |
| { |
| $category = $matches[2]; |
| $source = $matches[1]; |
| } |
| |
| $severity = false; |
| switch ( $errno ) |
| { |
| case E_USER_NOTICE: |
| $severity = ezcLog::NOTICE; |
| break; |
| case E_USER_WARNING: |
| $severity = ezcLog::WARNING; |
| break; |
| case E_USER_ERROR: |
| $severity = ezcLog::ERROR; |
| break; |
| } |
| |
| $debug->log( |
| $message, |
| $severity, |
| array( |
| 'source' => $source, |
| 'category' => $category, |
| 'verbosity' => $verbosity, |
| 'file' => $errfile, |
| 'line' => $errline |
| ) |
| ); |
| } |
| } |
| ?> |