'', args => array(), caller => '', target => '', time => 0), * array(query => '', args => array(), caller => '', target => '', time => 0), * ), * ); * * @var array */ protected $queryLog = array(); /** * The connection key for which this object is logging. * * @var string */ protected $connectionKey = 'default'; /** * Constructor. * * @param $key * The database connection key for which to enable logging. */ public function __construct($key = 'default') { $this->connectionKey = $key; } /** * Begin logging queries to the specified connection and logging key. * * If the specified logging key is already running this method does nothing. * * @param $logging_key * The identification key for this log request. By specifying different * logging keys we are able to start and stop multiple logging runs * simultaneously without them colliding. */ public function start($logging_key) { if (empty($this->queryLog[$logging_key])) { $this->clear($logging_key); } } /** * Retrieve the query log for the specified logging key so far. * * @param $logging_key * The logging key to fetch. * @return * An indexed array of all query records for this logging key. */ public function get($logging_key) { return $this->queryLog[$logging_key]; } /** * Empty the query log for the specified logging key. * * This method does not stop logging, it simply clears the log. To stop * logging, use the end() method. * * @param $logging_key * The logging key to empty. */ public function clear($logging_key) { $this->queryLog[$logging_key] = array(); } /** * Stop logging for the specified logging key. * * @param $logging_key * The logging key to stop. */ public function end($logging_key) { unset($this->queryLog[$logging_key]); } /** * Log a query to all active logging keys. * * @param $statement * The prepared statement object to log. * @param $args * The arguments passed to the statement object. * @param $time * The time in milliseconds the query took to execute. */ public function log(DatabaseStatementInterface $statement, $args, $time) { foreach (array_keys($this->queryLog) as $key) { $this->queryLog[$key][] = array( 'query' => $statement->getQueryString(), 'args' => $args, 'target' => $statement->dbh->getTarget(), 'caller' => $this->findCaller(), 'time' => $time, ); } } /** * Determine the routine that called this query. * * We define "the routine that called this query" as the first entry in * the call stack that is not inside includes/database and does have a file * (which excludes call_user_func_array(), anonymous functions and similar). * That makes the climbing logic very simple, and handles the variable stack * depth caused by the query builders. * * @link http://www.php.net/debug_backtrace * @return * This method returns a stack trace entry similar to that generated by * debug_backtrace(). However, it flattens the trace entry and the trace * entry before it so that we get the function and args of the function that * called into the database system, not the function and args of the * database call itself. */ public function findCaller() { $stack = debug_backtrace(); $stack_count = count($stack); for ($i = 0; $i < $stack_count; ++$i) { if (!empty($stack[$i]['file']) && strpos($stack[$i]['file'], 'includes' . DIRECTORY_SEPARATOR . 'database') === FALSE) { $stack[$i] += array('args' => array()); return array( 'file' => $stack[$i]['file'], 'line' => $stack[$i]['line'], 'function' => $stack[$i + 1]['function'], 'class' => isset($stack[$i + 1]['class']) ? $stack[$i + 1]['class'] : NULL, 'type' => isset($stack[$i + 1]['type']) ? $stack[$i + 1]['type'] : NULL, 'args' => $stack[$i + 1]['args'], ); } } } }