Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Better query logging capabilities - implementation #153

Open
wants to merge 6 commits into from

4 participants

@woodworker

First implementation for #151 - Better query logging capabilities

  • normal callback logging is still possible
  • added QueryLogger interface
  • added QueryLogger call in LoggableDatabase, LoggableCollection and LoggableCursor
  • added EchoQueryLogger and ChainLogger sample implementations
@woodworker

so 2 solution to the build problem on php 5.3

  1. set minimum php version to 5.4 - good for me and the rest of the world :smile:
  2. i'll try to get this working on 5.3 tomorrow(tm)
lib/Doctrine/MongoDB/LoggableCollection.php
((11 lines not shown))
- return parent::insert($a, $options);
+ return $this->logMethod($log, function () use (&$a, $options) {
+ return parent::insert($a, $options);
@jmikola Owner
jmikola added a note

This appears to be one of the build failures for 5.3. Even on 5.4+, should a closure really be calling parent::?

i'll reworki it to be not a closure anymore

@jmikola Owner
jmikola added a note

I'm more surprised that this was even supported and wondering if it has something to do with PHP 5.4 allowing $this to be bound on closures. Did you find documentation or prior code that was doing such a thing?

afaik since 5.4 closures are called in the context of the object/class so parent:: is nothing strange

see http://www.php.net/manual/en/closure.bind.php

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@woodworker

anything more needed to merge this?

lib/Doctrine/MongoDB/LoggableCollection.php
@@ -65,7 +72,19 @@ public function log(array $log)
{
$log['db'] = $this->database->getName();
$log['collection'] = $this->getName();
- call_user_func_array($this->loggerCallable, array($log));
+ if($this->loggerCallable){
+ call_user_func_array($this->loggerCallable, array($log));
+ }
+
+ if($this->queryLogger instanceof Logging\QueryLogger){
+ $this->queryLogger->startQuery($log);
+ }
+ }
+
+ private function logAfter() {
@jwage Owner
jwage added a note

Move the { to the next line.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/MongoDB/Logging/QueryLogger.php
((12 lines not shown))
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\MongoDB\Logging;
+
+/**
+ * QueryLogger interface.
+ *
+ * @author Martin Holzhauer <martin@holzhauer.eu>
+ */
+interface QueryLogger {
@jwage Owner
jwage added a note

Move { to the next line.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/MongoDB/Logging/LoggerChain.php
((39 lines not shown))
+ public function addLogger(QueryLogger $queryLogger){
+ $this->logger[] = $queryLogger;
+ }
+
+ public function startQuery($parameter)
+ {
+ foreach($this->logger as $logger)
+ {
+ $logger->startQuery($parameter);
+ }
+ }
+
+ public function stopQuery()
+ {
+ foreach($this->logger as $logger)
+ {
@jwage Owner
jwage added a note

Move { to the line above at the end.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/MongoDB/Logging/LoggerChain.php
((31 lines not shown))
+ */
+ private $logger = array();
+
+ /**
+ * add logger to chain
+ *
+ * @param QueryLogger $queryLogger
+ */
+ public function addLogger(QueryLogger $queryLogger){
+ $this->logger[] = $queryLogger;
+ }
+
+ public function startQuery($parameter)
+ {
+ foreach($this->logger as $logger)
+ {
@jwage Owner
jwage added a note

Move { to the line above at the end.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/MongoDB/Logging/LoggerChain.php
((24 lines not shown))
+ *
+ * @author Martin Holzhauer <martin@holzhauer.eu>
+ */
+class LoggerChain implements QueryLogger {
+
+ /**
+ * @var array|QueryLogger[]
+ */
+ private $logger = array();
+
+ /**
+ * add logger to chain
+ *
+ * @param QueryLogger $queryLogger
+ */
+ public function addLogger(QueryLogger $queryLogger){
@jwage Owner
jwage added a note

Move { to the line below.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/MongoDB/Logging/LoggerChain.php
((12 lines not shown))
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\MongoDB\Logging;
+
+/**
+ * QueryLogger chain implementation.
+ *
+ * @author Martin Holzhauer <martin@holzhauer.eu>
+ */
+class LoggerChain implements QueryLogger {
@jwage Owner
jwage added a note

Move the { to the line below.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/MongoDB/Logging/EchoQueryLogger.php
((12 lines not shown))
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\MongoDB\Logging;
+
+/**
+ * EchoLogger implementation.
+ *
+ * @author Martin Holzhauer <martin@holzhauer.eu>
+ */
+class EchoQueryLogger implements QueryLogger {
@jwage Owner
jwage added a note

Move { to the next line and remove the extra space.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@jwage jwage commented on the diff
lib/Doctrine/MongoDB/Logging/EchoQueryLogger.php
((20 lines not shown))
+namespace Doctrine\MongoDB\Logging;
+
+/**
+ * EchoLogger implementation.
+ *
+ * @author Martin Holzhauer <martin@holzhauer.eu>
+ */
+class EchoQueryLogger implements QueryLogger {
+
+ public function startQuery($parameter)
+ {
+ var_dump($parameter);
+ echo PHP_EOL;
+ }
+
+ public function stopQuery()
@jwage Owner
jwage added a note

What more do we have to do here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/MongoDB/LoggableCollection.php
@@ -65,7 +72,19 @@ public function log(array $log)
{
$log['db'] = $this->database->getName();
$log['collection'] = $this->getName();
- call_user_func_array($this->loggerCallable, array($log));
+ if($this->loggerCallable){
@jwage Owner
jwage added a note

This should be if ($this->loggerCallable) {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/MongoDB/LoggableCollection.php
@@ -65,7 +72,19 @@ public function log(array $log)
{
$log['db'] = $this->database->getName();
$log['collection'] = $this->getName();
- call_user_func_array($this->loggerCallable, array($log));
+ if($this->loggerCallable){
+ call_user_func_array($this->loggerCallable, array($log));
+ }
+
+ if($this->queryLogger instanceof Logging\QueryLogger){
@jwage Owner
jwage added a note

This should be if ($this->queryLogger instanceof Logging\QueryLogger) {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/MongoDB/LoggableCursor.php
@@ -63,7 +70,19 @@ public function log(array $data)
{
$data['query'] = $this->query;
$data['fields'] = $this->fields;
- call_user_func($this->loggerCallable, $data);
+ if ($this->loggerCallable) {
+ call_user_func($this->loggerCallable, $data);
+ }
+
+ if($this->queryLogger instanceof Logging\QueryLogger){
@jwage Owner
jwage added a note
if ($this->queryLogger instanceof Logging\QueryLogger) {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/MongoDB/LoggableDatabase.php
@@ -64,7 +71,19 @@ public function __construct(Connection $connection, \MongoDB $mongoDB, EventMana
public function log(array $log)
{
$log['db'] = $this->getName();
- call_user_func_array($this->loggerCallable, array($log));
+ if($this->loggerCallable){
@jwage Owner
jwage added a note
if ($this->loggerCallable) {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/MongoDB/LoggableDatabase.php
@@ -64,7 +71,19 @@ public function __construct(Connection $connection, \MongoDB $mongoDB, EventMana
public function log(array $log)
{
$log['db'] = $this->getName();
- call_user_func_array($this->loggerCallable, array($log));
+ if($this->loggerCallable){
+ call_user_func_array($this->loggerCallable, array($log));
+ }
+
+ if($this->queryLogger instanceof Logging\QueryLogger){
@jwage Owner
jwage added a note
if ($this->queryLogger instanceof Logging\QueryLogger) {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/MongoDB/LoggableDatabase.php
@@ -64,7 +71,19 @@ public function __construct(Connection $connection, \MongoDB $mongoDB, EventMana
public function log(array $log)
{
$log['db'] = $this->getName();
- call_user_func_array($this->loggerCallable, array($log));
+ if($this->loggerCallable){
+ call_user_func_array($this->loggerCallable, array($log));
+ }
+
+ if($this->queryLogger instanceof Logging\QueryLogger){
+ $this->queryLogger->startQuery($log);
+ }
+ }
+
+ private function logAfter() {
@jwage Owner
jwage added a note

Move { to the next line.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/Doctrine/MongoDB/LoggableDatabase.php
@@ -64,7 +71,19 @@ public function __construct(Connection $connection, \MongoDB $mongoDB, EventMana
public function log(array $log)
{
$log['db'] = $this->getName();
- call_user_func_array($this->loggerCallable, array($log));
+ if($this->loggerCallable){
+ call_user_func_array($this->loggerCallable, array($log));
+ }
+
+ if($this->queryLogger instanceof Logging\QueryLogger){
+ $this->queryLogger->startQuery($log);
+ }
+ }
+
+ private function logAfter() {
+ if($this->queryLogger instanceof Logging\QueryLogger){
@jwage Owner
jwage added a note
if ($this->queryLogger instanceof Logging\QueryLogger) {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@jmikola
Owner

I'm out for the weekend but hope to review this early in the coming week.

@woodworker

anything new?

@igorw

Bump.

@jmikola
Owner

I will review this within 8 hours, after I leave the office tonight.

@jmikola jmikola commented on the diff
lib/Doctrine/MongoDB/LoggableCollection.php
((8 lines not shown))
{
- if ( ! is_callable($loggerCallable)) {
- throw new \InvalidArgumentException('$loggerCallable must be a valid callback');
+ if ( ! is_callable($loggerCallable) && !($queryLogger instanceof Logging\QueryLogger)) {
+ throw new \InvalidArgumentException('$loggerCallable must be a valid callback or $queryLogger must be an instance of Doctrine\MongoDB\Logging\QueryLogger');
@jmikola Owner
jmikola added a note

You're already type-hinting $queryLogger, so does it matter if it's null?

@jmikola Owner
jmikola added a note

Ah, just saw the testNoLoggerGivenThrowsException() test below. Since you've changed the log() method to conditionally invoke $this->loggerCallable or the QueryLogger, I wonder if this constructor exception even matters anymore. If the class has neither a callable or QueryLogger set, we do nothing. On its own, the library shouldn't even construct the class based on Connection::doSelectDatabase().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@jmikola jmikola commented on the diff
lib/Doctrine/MongoDB/LoggableCursor.php
((8 lines not shown))
{
- if ( ! is_callable($loggerCallable)) {
- throw new \InvalidArgumentException('$loggerCallable must be a valid callback');
+ if ( ! is_callable($loggerCallable) && !($queryLogger instanceof Logging\QueryLogger)) {
+ throw new \InvalidArgumentException('$loggerCallable must be a valid callback or $queryLogger must be an instance of Doctrine\MongoDB\Logging\QueryLogger');
@jmikola Owner
jmikola added a note

Same comment as https://github.com/doctrine/mongodb/pull/153/files#r9897431. I think we can just remove this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@jmikola jmikola commented on the diff
lib/Doctrine/MongoDB/Configuration.php
@@ -59,6 +59,26 @@ public function setLoggerCallable($loggerCallable)
}
/**
+ * Set QueryLogger
+ *
+ * @param Logging\QueryLogger $queryLogger
@jmikola Owner
jmikola added a note

Can you add a use statement for the QueryLogger class? That makes it easier to see at a glance what the file is using.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@jmikola jmikola commented on the diff
lib/Doctrine/MongoDB/LoggableCollection.php
@@ -45,13 +50,15 @@ class LoggableCollection extends Collection implements Loggable
* @param EventManager $evm EventManager instance
* @param integer $numRetries Number of times to retry queries
* @param callable $loggerCallable The logger callable
+ * @param Logging\QueryLogger $queryLogger The QueryLogger object
@jmikola Owner
jmikola added a note

Same comment as earlier regarding a use statement for Logging\QueryLogger. That would also shorten this to QueryLogger and avoid the alignment issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@jmikola jmikola commented on the diff
lib/Doctrine/MongoDB/Logging/LoggerChain.php
((36 lines not shown))
+ * add logger to chain
+ *
+ * @param QueryLogger $queryLogger
+ */
+ public function addLogger(QueryLogger $queryLogger)
+ {
+ $this->logger[] = $queryLogger;
+ }
+
+ /**
+ * @param $parameter
+ */
+ public function startQuery($parameter)
+ {
+ foreach($this->logger as $logger)
+ {
@jmikola Owner
jmikola added a note

foreach gets { on the same line.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@jmikola jmikola commented on the diff
lib/Doctrine/MongoDB/Logging/QueryLogger.php
((14 lines not shown))
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\MongoDB\Logging;
+
+/**
+ * QueryLogger interface.
+ *
+ * @author Martin Holzhauer <martin@holzhauer.eu>
+ */
+interface QueryLogger
+{
+ public function startQuery($parameter);
@jmikola Owner
jmikola added a note

I think the comments from https://github.com/doctrine/dbal/blob/master/lib/Doctrine/DBAL/Logging/SQLLogger.php would be valuable here. For instance, it let's users know that stopQuery() can be used for timing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@jmikola jmikola commented on the diff
lib/Doctrine/MongoDB/Logging/QueryLogger.php
((12 lines not shown))
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\MongoDB\Logging;
+
+/**
+ * QueryLogger interface.
+ *
+ * @author Martin Holzhauer <martin@holzhauer.eu>
+ */
+interface QueryLogger
@jmikola Owner
jmikola added a note

Since the DBAL class is SQLLogger, I'm wondering if this should be MongoLogger or BSONLogger for the name of the protocol or syntax we're logging. The name "query" seems very generic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@jmikola
Owner

@woodworker: Do you have an example of how stopQuery() is used for timing? I didn't find anything in DBAL for that, but I'm curious if the QueryLogger would be responsible for nesting state and timers each time startQuery() is called, and unwrapping on each stopQuery().

@jmikola jmikola commented on the diff
lib/Doctrine/MongoDB/LoggableCollection.php
((5 lines not shown))
*/
- public function __construct(Database $database, \MongoCollection $mongoCollection, EventManager $evm, $numRetries, $loggerCallable)
+ public function __construct(Database $database, \MongoCollection $mongoCollection, EventManager $evm, $numRetries, $loggerCallable = null, Logging\QueryLogger $queryLogger = null)
@jmikola Owner
jmikola added a note

@jwage: I'm worried about adding more constructor arguments here, since it's a change that then has to be implemented whenever we extend the class (to ensure we accept the argument with the same default value, and then pass it along to the parent). Assuming we allow both $loggerCallable and the QueryLogger to be optional (as I suggest here)., what do you think about having setter methods for each? We'd naturally leave the $loggerCallable argument in place with a null default value for BC.

@jwage Owner
jwage added a note

Makes sense to me. :+1:

i'll move it to a setter

but best solution would be to remove everything starting at $numRetries and just inject the configuration object so future config params will not be injected seperate

@jmikola Owner
jmikola added a note

Agreed. This is something I've thought about for a while. I changed the constructor order of some of these core classes for 1.1.0 via 39a2b7c, so perhaps we can consider this for 1.2.0? Otherwise, it'd be something for 2.0 if we acknowledge it's a BC break. I didn't before, as I assumed most users access these classes through the Connection, so that was the public API to preserve. Thoughts, @jwage?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@woodworker

@jmikola
nested querylogger is in PHP not needed - because singlethreaded
start timer in startQuery method and then stop that timer in stopQuery
nothing will happen in between

and it's realy simple just a microtime(true) in startQuery adn a microtime(true) in stopQuery and then log to statsd or whatever

@jmikola
Owner

@woodworker: I was thinking it's quite possible that a higher level method (e.g. something in GridFS, which doesn't yet have logging -- todo in #37) might call underlying collection methods. That higher level method might start/stop on its own, but internally the collection methods would log as well.

@jmikola jmikola added this to the 1.2.0 milestone
@jmikola
Owner

@woodworker: After our discussion last month in Berlin, can this be closed? I recall you said that the driver's stream context logging proved more useful to you.

@jmikola jmikola added the feature label
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
20 lib/Doctrine/MongoDB/Configuration.php
@@ -59,6 +59,26 @@ public function setLoggerCallable($loggerCallable)
}
/**
+ * Set QueryLogger
+ *
+ * @param Logging\QueryLogger $queryLogger
@jmikola Owner
jmikola added a note

Can you add a use statement for the QueryLogger class? That makes it easier to see at a glance what the file is using.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ */
+ public function setQueryLogger(Logging\QueryLogger $queryLogger)
+ {
+ $this->attributes['queryLogger'] = $queryLogger;
+ }
+
+ /**
+ * Get QueryLogger
+ *
+ * @return null|Logging\QueryLogger
+ */
+ public function getQueryLogger()
+ {
+ return isset($this->attributes['queryLogger']) ? $this->attributes['queryLogger'] : null;
+ }
+
+ /**
* Get the MongoDB command prefix.
*
* @deprecated 1.1 No longer supported; will be removed for 1.2
View
5 lib/Doctrine/MongoDB/Connection.php
@@ -404,9 +404,10 @@ protected function doSelectDatabase($name)
$mongoDB = $this->mongoClient->selectDB($name);
$numRetries = $this->config->getRetryQuery();
$loggerCallable = $this->config->getLoggerCallable();
+ $queryLogger = $this->config->getQueryLogger();
- return $loggerCallable !== null
- ? new LoggableDatabase($this, $mongoDB, $this->eventManager, $numRetries, $loggerCallable)
+ return ($loggerCallable !== null || $queryLogger!== null)
+ ? new LoggableDatabase($this, $mongoDB, $this->eventManager, $numRetries, $loggerCallable, $queryLogger)
: new Database($this, $mongoDB, $this->eventManager, $numRetries);
}
View
161 lib/Doctrine/MongoDB/LoggableCollection.php
@@ -38,6 +38,11 @@ class LoggableCollection extends Collection implements Loggable
protected $loggerCallable;
/**
+ * @var Logging\QueryLogger
+ */
+ protected $queryLogger;
+
+ /**
* Constructor.
*
* @param Database $database Database to which this collection belongs
@@ -45,13 +50,15 @@ class LoggableCollection extends Collection implements Loggable
* @param EventManager $evm EventManager instance
* @param integer $numRetries Number of times to retry queries
* @param callable $loggerCallable The logger callable
+ * @param Logging\QueryLogger $queryLogger The QueryLogger object
@jmikola Owner
jmikola added a note

Same comment as earlier regarding a use statement for Logging\QueryLogger. That would also shorten this to QueryLogger and avoid the alignment issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
*/
- public function __construct(Database $database, \MongoCollection $mongoCollection, EventManager $evm, $numRetries, $loggerCallable)
+ public function __construct(Database $database, \MongoCollection $mongoCollection, EventManager $evm, $numRetries, $loggerCallable = null, Logging\QueryLogger $queryLogger = null)
@jmikola Owner
jmikola added a note

@jwage: I'm worried about adding more constructor arguments here, since it's a change that then has to be implemented whenever we extend the class (to ensure we accept the argument with the same default value, and then pass it along to the parent). Assuming we allow both $loggerCallable and the QueryLogger to be optional (as I suggest here)., what do you think about having setter methods for each? We'd naturally leave the $loggerCallable argument in place with a null default value for BC.

@jwage Owner
jwage added a note

Makes sense to me. :+1:

i'll move it to a setter

but best solution would be to remove everything starting at $numRetries and just inject the configuration object so future config params will not be injected seperate

@jmikola Owner
jmikola added a note

Agreed. This is something I've thought about for a while. I changed the constructor order of some of these core classes for 1.1.0 via 39a2b7c, so perhaps we can consider this for 1.2.0? Otherwise, it'd be something for 2.0 if we acknowledge it's a BC break. I didn't before, as I assumed most users access these classes through the Connection, so that was the public API to preserve. Thoughts, @jwage?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
{
- if ( ! is_callable($loggerCallable)) {
- throw new \InvalidArgumentException('$loggerCallable must be a valid callback');
+ if ( ! is_callable($loggerCallable) && !($queryLogger instanceof Logging\QueryLogger)) {
+ throw new \InvalidArgumentException('$loggerCallable must be a valid callback or $queryLogger must be an instance of Doctrine\MongoDB\Logging\QueryLogger');
@jmikola Owner
jmikola added a note

You're already type-hinting $queryLogger, so does it matter if it's null?

@jmikola Owner
jmikola added a note

Ah, just saw the testNoLoggerGivenThrowsException() test below. Since you've changed the log() method to conditionally invoke $this->loggerCallable or the QueryLogger, I wonder if this constructor exception even matters anymore. If the class has neither a callable or QueryLogger set, we do nothing. On its own, the library shouldn't even construct the class based on Connection::doSelectDatabase().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
}
$this->loggerCallable = $loggerCallable;
+ $this->queryLogger = $queryLogger;
parent::__construct($database, $mongoCollection, $evm, $numRetries);
}
@@ -65,7 +72,20 @@ public function log(array $log)
{
$log['db'] = $this->database->getName();
$log['collection'] = $this->getName();
- call_user_func_array($this->loggerCallable, array($log));
+ if ($this->loggerCallable) {
+ call_user_func_array($this->loggerCallable, array($log));
+ }
+
+ if ($this->queryLogger instanceof Logging\QueryLogger) {
+ $this->queryLogger->startQuery($log);
+ }
+ }
+
+ private function logAfter()
+ {
+ if ($this->queryLogger instanceof Logging\QueryLogger) {
+ $this->queryLogger->stopQuery();
+ }
}
/**
@@ -73,14 +93,17 @@ public function log(array $log)
*/
public function batchInsert(array &$a, array $options = array())
{
- $this->log(array(
+ $log = array(
'batchInsert' => true,
'num' => count($a),
'data' => $a,
'options' => $options,
- ));
+ );
- return parent::batchInsert($a, $options);
+ $this->log($log);
+ $data = parent::batchInsert($a, $options);
+ $this->logAfter();
+ return $data;
}
/**
@@ -88,14 +111,17 @@ public function batchInsert(array &$a, array $options = array())
*/
public function count(array $query = array(), $limit = 0, $skip = 0)
{
- $this->log(array(
+ $log = array(
'count' => true,
'query' => $query,
'limit' => $limit,
'skip' => $skip,
- ));
+ );
- return parent::count($query, $limit, $skip);
+ $this->log($log);
+ $data = parent::count($query, $limit, $skip);
+ $this->logAfter();
+ return $data;
}
/**
@@ -103,12 +129,15 @@ public function count(array $query = array(), $limit = 0, $skip = 0)
*/
public function deleteIndex($keys)
{
- $this->log(array(
+ $log = array(
'deleteIndex' => true,
'keys' => $keys,
- ));
+ );
- return parent::deleteIndex($keys);
+ $this->log($log);
+ $data = parent::deleteIndex($keys);
+ $this->logAfter();
+ return $data;
}
/**
@@ -116,9 +145,12 @@ public function deleteIndex($keys)
*/
public function deleteIndexes()
{
- $this->log(array('deleteIndexes' => true));
+ $log = array('deleteIndexes' => true);
- return parent::deleteIndexes();
+ $this->log($log);
+ $data = parent::deleteIndexes();
+ $this->logAfter();
+ return $data;
}
/**
@@ -126,9 +158,12 @@ public function deleteIndexes()
*/
public function drop()
{
- $this->log(array('drop' => true));
+ $log = array('drop' => true);
- return parent::drop();
+ $this->log($log);
+ $data = parent::drop();
+ $this->logAfter();
+ return $data;
}
/**
@@ -136,13 +171,16 @@ public function drop()
*/
public function ensureIndex(array $keys, array $options = array())
{
- $this->log(array(
+ $log = array(
'ensureIndex' => true,
'keys' => $keys,
'options' => $options,
- ));
+ );
- return parent::ensureIndex($keys, $options);
+ $this->log($log);
+ $data = parent::ensureIndex($keys, $options);
+ $this->logAfter();
+ return $data;
}
/**
@@ -150,13 +188,16 @@ public function ensureIndex(array $keys, array $options = array())
*/
public function find(array $query = array(), array $fields = array())
{
- $this->log(array(
+ $log = array(
'find' => true,
'query' => $query,
'fields' => $fields,
- ));
+ );
- return parent::find($query, $fields);
+ $this->log($log);
+ $data = parent::find($query, $fields);
+ $this->logAfter();
+ return $data;
}
/**
@@ -164,13 +205,16 @@ public function find(array $query = array(), array $fields = array())
*/
public function findOne(array $query = array(), array $fields = array())
{
- $this->log(array(
+ $log = array(
'findOne' => true,
'query' => $query,
'fields' => $fields,
- ));
+ );
- return parent::findOne($query, $fields);
+ $this->log($log);
+ $data = parent::findOne($query, $fields);
+ $this->logAfter();
+ return $data;
}
/**
@@ -178,12 +222,15 @@ public function findOne(array $query = array(), array $fields = array())
*/
public function getDBRef(array $reference)
{
- $this->log(array(
+ $log = array(
'getDBRef' => true,
'reference' => $reference,
- ));
+ );
- return parent::getDBRef($reference);
+ $this->log($log);
+ $data = parent::getDBRef($reference);
+ $this->logAfter();
+ return $data;
}
/**
@@ -191,15 +238,18 @@ public function getDBRef(array $reference)
*/
public function group($keys, array $initial, $reduce, array $options = array())
{
- $this->log(array(
+ $log = array(
'group' => true,
'keys' => $keys,
'initial' => $initial,
'reduce' => $reduce,
'options' => $options,
- ));
+ );
- return parent::group($keys, $initial, $reduce, $options);
+ $this->log($log);
+ $data = parent::group($keys, $initial, $reduce, $options);
+ $this->logAfter();
+ return $data;
}
/**
@@ -207,13 +257,16 @@ public function group($keys, array $initial, $reduce, array $options = array())
*/
public function insert(array &$a, array $options = array())
{
- $this->log(array(
+ $log = array(
'insert' => true,
'document' => $a,
'options' => $options,
- ));
+ );
- return parent::insert($a, $options);
+ $this->log($log);
+ $data = parent::insert($a, $options);
+ $this->logAfter();
+ return $data;
}
/**
@@ -221,13 +274,16 @@ public function insert(array &$a, array $options = array())
*/
public function remove(array $query, array $options = array())
{
- $this->log(array(
+ $log = array(
'remove' => true,
'query' => $query,
'options' => $options,
- ));
+ );
- return parent::remove($query, $options);
+ $this->log($log);
+ $data = parent::remove($query, $options);
+ $this->logAfter();
+ return $data;
}
/**
@@ -235,13 +291,16 @@ public function remove(array $query, array $options = array())
*/
public function save(array &$a, array $options = array())
{
- $this->log(array(
+ $log = array(
'save' => true,
'document' => $a,
'options' => $options,
- ));
+ );
- return parent::save($a, $options);
+ $this->log($log);
+ $data = parent::save($a, $options);
+ $this->logAfter();
+ return $data;
}
/**
@@ -249,14 +308,17 @@ public function save(array &$a, array $options = array())
*/
public function update($query, array $newObj, array $options = array())
{
- $this->log(array(
+ $log = array(
'update' => true,
'query' => $query,
'newObj' => $newObj,
'options' => $options,
- ));
+ );
- return parent::update($query, $newObj, $options);
+ $this->log($log);
+ $data = parent::update($query, $newObj, $options);
+ $this->logAfter();
+ return $data;
}
/**
@@ -264,12 +326,15 @@ public function update($query, array $newObj, array $options = array())
*/
public function validate($scanData = false)
{
- $this->log(array(
+ $log = array(
'validate' => true,
'scanData' => $scanData,
- ));
+ );
- return parent::validate($scanData);
+ $this->log($log);
+ $data = parent::validate($scanData);
+ $this->logAfter();
+ return $data;
}
/**
@@ -283,6 +348,6 @@ public function validate($scanData = false)
*/
protected function wrapCursor(\MongoCursor $cursor, $query, $fields)
{
- return new LoggableCursor($this, $cursor, $query, $fields, $this->numRetries, $this->loggerCallable);
+ return new LoggableCursor($this, $cursor, $query, $fields, $this->numRetries, $this->loggerCallable, $this->queryLogger);
}
}
View
73 lib/Doctrine/MongoDB/LoggableCursor.php
@@ -35,6 +35,11 @@ class LoggableCursor extends Cursor implements Loggable
protected $loggerCallable;
/**
+ * @var Logging\QueryLogger
+ */
+ protected $queryLogger;
+
+ /**
* Constructor.
*
* @param Collection $collection Collection used to create this Cursor
@@ -43,14 +48,16 @@ class LoggableCursor extends Cursor implements Loggable
* @param array $fields Selected fields (projection)
* @param integer $numRetries Number of times to retry queries
* @param callable $loggerCallable Logger callable
+ * @param Logging\QueryLogger $queryLogger QueryLogger object
*/
- public function __construct(Collection $collection, \MongoCursor $mongoCursor, array $query, array $fields, $numRetries, $loggerCallable)
+ public function __construct(Collection $collection, \MongoCursor $mongoCursor, array $query, array $fields, $numRetries, $loggerCallable = null, Logging\QueryLogger $queryLogger = null)
{
- if ( ! is_callable($loggerCallable)) {
- throw new \InvalidArgumentException('$loggerCallable must be a valid callback');
+ if ( ! is_callable($loggerCallable) && !($queryLogger instanceof Logging\QueryLogger)) {
+ throw new \InvalidArgumentException('$loggerCallable must be a valid callback or $queryLogger must be an instance of Doctrine\MongoDB\Logging\QueryLogger');
@jmikola Owner
jmikola added a note

Same comment as https://github.com/doctrine/mongodb/pull/153/files#r9897431. I think we can just remove this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
}
$this->loggerCallable = $loggerCallable;
parent::__construct($collection, $mongoCursor, $query, $fields, $numRetries);
+ $this->queryLogger = $queryLogger;
}
/**
@@ -63,7 +70,20 @@ public function log(array $data)
{
$data['query'] = $this->query;
$data['fields'] = $this->fields;
- call_user_func($this->loggerCallable, $data);
+ if ($this->loggerCallable) {
+ call_user_func($this->loggerCallable, $data);
+ }
+
+ if ($this->queryLogger instanceof Logging\QueryLogger) {
+ $this->queryLogger->startQuery($data);
+ }
+ }
+
+ private function logAfter()
+ {
+ if ($this->queryLogger instanceof Logging\QueryLogger) {
+ $this->queryLogger->stopQuery();
+ }
}
/**
@@ -81,12 +101,15 @@ public function getLoggerCallable()
*/
public function hint(array $keyPattern)
{
- $this->log(array(
+ $log = array(
'hint' => true,
'keyPattern' => $keyPattern,
- ));
+ );
- return parent::hint($keyPattern);
+ $this->log($log);
+ $data = parent::hint($keyPattern);
+ $this->logAfter();
+ return $data;
}
/**
@@ -94,12 +117,15 @@ public function hint(array $keyPattern)
*/
public function limit($num)
{
- $this->log(array(
+ $log = array(
'limit' => true,
'limitNum' => $num,
- ));
+ );
- return parent::limit($num);
+ $this->log($log);
+ $data = parent::limit($num);
+ $this->logAfter();
+ return $data;
}
/**
@@ -107,12 +133,15 @@ public function limit($num)
*/
public function skip($num)
{
- $this->log(array(
+ $log = array(
'skip' => true,
'skipNum' => $num,
- ));
+ );
- return parent::skip($num);
+ $this->log($log);
+ $data = parent::skip($num);
+ $this->logAfter();
+ return $data;
}
/**
@@ -120,11 +149,14 @@ public function skip($num)
*/
public function snapshot()
{
- $this->log(array(
+ $log = array(
'snapshot' => true,
- ));
+ );
- return parent::snapshot();
+ $this->log($log);
+ $data = parent::snapshot();
+ $this->logAfter();
+ return $data;
}
/**
@@ -132,11 +164,14 @@ public function snapshot()
*/
public function sort($fields)
{
- $this->log(array(
+ $log = array(
'sort' => true,
'sortFields' => $fields,
- ));
+ );
- return parent::sort($fields);
+ $this->log($log);
+ $data = parent::sort($fields);
+ $this->logAfter();
+ return $data;
}
}
View
82 lib/Doctrine/MongoDB/LoggableDatabase.php
@@ -38,6 +38,11 @@ class LoggableDatabase extends Database implements Loggable
protected $loggerCallable;
/**
+ * @var Logging\QueryLogger
+ */
+ protected $queryLogger;
+
+ /**
* Constructor.
*
* @param Connection $connection Connection used to create Collections
@@ -45,14 +50,16 @@ class LoggableDatabase extends Database implements Loggable
* @param EventManager $evm EventManager instance
* @param integer $numRetries Number of times to retry queries
* @param callable $loggerCallable The logger callable
+ * @param Logging\QueryLogger $queryLogger The QueryLogger object
*/
- public function __construct(Connection $connection, \MongoDB $mongoDB, EventManager $evm, $numRetries, $loggerCallable)
+ public function __construct(Connection $connection, \MongoDB $mongoDB, EventManager $evm, $numRetries, $loggerCallable = null, Logging\QueryLogger $queryLogger = null)
{
- if ( ! is_callable($loggerCallable)) {
- throw new \InvalidArgumentException('$loggerCallable must be a valid callback');
+ if ( ! is_callable($loggerCallable) && !($queryLogger instanceof Logging\QueryLogger)) {
+ throw new \InvalidArgumentException('$loggerCallable must be a valid callback or $queryLogger must be an instance of Doctrine\MongoDB\Logging\QueryLogger');
}
parent::__construct($connection, $mongoDB, $evm, $numRetries);
$this->loggerCallable = $loggerCallable;
+ $this->queryLogger = $queryLogger;
}
/**
@@ -64,7 +71,20 @@ public function __construct(Connection $connection, \MongoDB $mongoDB, EventMana
public function log(array $log)
{
$log['db'] = $this->getName();
- call_user_func_array($this->loggerCallable, array($log));
+ if ($this->loggerCallable) {
+ call_user_func_array($this->loggerCallable, array($log));
+ }
+
+ if ($this->queryLogger instanceof Logging\QueryLogger) {
+ $this->queryLogger->startQuery($log);
+ }
+ }
+
+ private function logAfter()
+ {
+ if ($this->queryLogger instanceof Logging\QueryLogger) {
+ $this->queryLogger->stopQuery();
+ }
}
/**
@@ -72,13 +92,16 @@ public function log(array $log)
*/
public function authenticate($username, $password)
{
- $this->log(array(
+ $log = array(
'authenticate' => true,
'username' => $username,
'password' => $password,
- ));
+ );
- return parent::authenticate($username, $password);
+ $this->log($log);
+ $data = parent::authenticate($username, $password);
+ $this->logAfter();
+ return $data;
}
/**
@@ -86,13 +109,16 @@ public function authenticate($username, $password)
*/
public function command(array $data, array $options = array())
{
- $this->log(array(
+ $log = array(
'command' => true,
'data' => $data,
'options' => $options,
- ));
+ );
- return parent::command($data, $options);
+ $this->log($log);
+ $data = parent::command($data, $options);
+ $this->logAfter();
+ return $data;
}
/**
@@ -104,7 +130,7 @@ public function createCollection($name, $cappedOrOptions = false, $size = 0, $ma
? array_merge(array('capped' => false, 'size' => 0, 'max' => 0), $cappedOrOptions)
: array('capped' => $cappedOrOptions, 'size' => $size, 'max' => $max);
- $this->log(array(
+ $log = array(
'createCollection' => true,
'name' => $name,
'options' => $options,
@@ -112,9 +138,12 @@ public function createCollection($name, $cappedOrOptions = false, $size = 0, $ma
'capped' => $options['capped'],
'size' => $options['size'],
'max' => $options['max'],
- ));
+ );
- return parent::createCollection($name, $options);
+ $this->log($log);
+ $data = parent::createCollection($name, $options);
+ $this->logAfter();
+ return $data;
}
/**
@@ -122,9 +151,12 @@ public function createCollection($name, $cappedOrOptions = false, $size = 0, $ma
*/
public function drop()
{
- $this->log(array('dropDatabase' => true));
+ $log = array('dropDatabase' => true);
- return parent::drop();
+ $this->log($log);
+ $data = parent::drop();
+ $this->logAfter();
+ return $data;
}
/**
@@ -132,13 +164,16 @@ public function drop()
*/
public function execute($code, array $args = array())
{
- $this->log(array(
+ $log = array(
'execute' => true,
'code' => $code,
'args' => $args,
- ));
+ );
- return parent::execute($code, $args);
+ $this->log($log);
+ $data = parent::execute($code, $args);
+ $this->logAfter();
+ return $data;
}
/**
@@ -146,12 +181,15 @@ public function execute($code, array $args = array())
*/
public function getDBRef(array $ref)
{
- $this->log(array(
+ $log = array(
'getDBRef' => true,
'reference' => $ref,
- ));
+ );
- return parent::getDBRef($ref);
+ $this->log($log);
+ $data = parent::getDBRef($ref);
+ $this->logAfter();
+ return $data;
}
/**
@@ -165,6 +203,6 @@ protected function doSelectCollection($name)
{
$mongoCollection = $this->mongoDB->selectCollection($name);
- return new LoggableCollection($this, $mongoCollection, $this->eventManager, $this->numRetries, $this->loggerCallable);
+ return new LoggableCollection($this, $mongoCollection, $this->eventManager, $this->numRetries, $this->loggerCallable, $this->queryLogger);
}
}
View
40 lib/Doctrine/MongoDB/Logging/EchoQueryLogger.php
@@ -0,0 +1,40 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\MongoDB\Logging;
+
+/**
+ * EchoLogger implementation.
+ *
+ * @author Martin Holzhauer <martin@holzhauer.eu>
+ */
+class EchoQueryLogger implements QueryLogger
+{
+
+ public function startQuery($parameter)
+ {
+ var_dump($parameter);
+ echo PHP_EOL;
+ }
+
+ public function stopQuery()
@jwage Owner
jwage added a note

What more do we have to do here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ {
+ // not needed in this case
+ }
+}
View
66 lib/Doctrine/MongoDB/Logging/LoggerChain.php
@@ -0,0 +1,66 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\MongoDB\Logging;
+
+/**
+ * QueryLogger chain implementation.
+ *
+ * @author Martin Holzhauer <martin@holzhauer.eu>
+ */
+class LoggerChain implements QueryLogger
+{
+
+ /**
+ * @var array|QueryLogger[]
+ */
+ private $logger = array();
+
+ /**
+ * add logger to chain
+ *
+ * @param QueryLogger $queryLogger
+ */
+ public function addLogger(QueryLogger $queryLogger)
+ {
+ $this->logger[] = $queryLogger;
+ }
+
+ /**
+ * @param $parameter
+ */
+ public function startQuery($parameter)
+ {
+ foreach($this->logger as $logger)
+ {
@jmikola Owner
jmikola added a note

foreach gets { on the same line.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ $logger->startQuery($parameter);
+ }
+ }
+
+ /**
+ *
+ */
+ public function stopQuery()
+ {
+ foreach($this->logger as $logger)
+ {
+ $logger->stopQuery();
+ }
+ }
+}
View
32 lib/Doctrine/MongoDB/Logging/QueryLogger.php
@@ -0,0 +1,32 @@
+<?php
+/*
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * and is licensed under the MIT license. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\MongoDB\Logging;
+
+/**
+ * QueryLogger interface.
+ *
+ * @author Martin Holzhauer <martin@holzhauer.eu>
+ */
+interface QueryLogger
@jmikola Owner
jmikola added a note

Since the DBAL class is SQLLogger, I'm wondering if this should be MongoLogger or BSONLogger for the name of the protocol or syntax we're logging. The name "query" seems very generic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+{
+ public function startQuery($parameter);
@jmikola Owner
jmikola added a note

I think the comments from https://github.com/doctrine/dbal/blob/master/lib/Doctrine/DBAL/Logging/SQLLogger.php would be valuable here. For instance, it let's users know that stopQuery() can be used for timing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+
+ public function stopQuery();
+}
View
83 tests/Doctrine/MongoDB/Tests/LoggableDatabaseTest.php
@@ -22,6 +22,66 @@ public function testLog()
$this->assertEquals(array('db' => self::databaseName, 'test' => 'test'), $called);
}
+ public function testClosureLogging()
+ {
+ $called = false;
+
+ $loggerCallable = function($msg) use (&$called) {
+ $called = $msg;
+ };
+
+ $db = $this->getTestLoggableDatabase($loggerCallable);
+ $db->execute('{}');
+
+ $this->assertInternalType('array', $called);
+ $this->assertArrayHasKey('execute', $called);
+ $this->assertArrayHasKey('code', $called);
+ $this->assertArrayHasKey('args', $called);
+ $this->assertArrayHasKey('db', $called);
+
+ $this->assertEquals('{}', $called['code']);
+ $this->assertEquals(self::databaseName, $called['db']);
+ }
+
+ public function testQueryLogger()
+ {
+ $logger = $this->getMockBuilder('Doctrine\MongoDB\Logging\QueryLogger')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $db = $this->getTestQueryLoggerEnabledLoggableDatabase($logger);
+
+ $called = null;
+
+ $logger->expects($this->once())
+ ->method('startQuery')
+ ->will($this->returnCallback(function($log)use(&$called){
+ $called = $log;
+ }));
+
+ $logger->expects($this->once())
+ ->method('stopQuery');
+
+ $db->execute('{}');
+
+ $this->assertInternalType('array', $called);
+ $this->assertArrayHasKey('execute', $called);
+ $this->assertArrayHasKey('code', $called);
+ $this->assertArrayHasKey('args', $called);
+ $this->assertArrayHasKey('db', $called);
+
+ $this->assertEquals('{}', $called['code']);
+ $this->assertEquals(self::databaseName, $called['db']);
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testNoLoggerGivenThrowsException()
+ {
+ $db = $this->getTestLoggableDatabase(null);
+ }
+
private function getTestLoggableDatabase($loggerCallable)
{
$connection = $this->getMockBuilder('Doctrine\MongoDB\Connection')
@@ -42,4 +102,25 @@ private function getTestLoggableDatabase($loggerCallable)
return new LoggableDatabase($connection, $mongoDB, $eventManager, 0, $loggerCallable);
}
-}
+
+ private function getTestQueryLoggerEnabledLoggableDatabase($logger)
+ {
+ $connection = $this->getMockBuilder('Doctrine\MongoDB\Connection')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $mongoDB = $this->getMockBuilder('MongoDB')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $mongoDB->expects($this->any())
+ ->method('__toString')
+ ->will($this->returnValue(self::databaseName));
+
+ $eventManager = $this->getMockBuilder('Doctrine\Common\EventManager')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ return new LoggableDatabase($connection, $mongoDB, $eventManager, 0, null, $logger);
+ }
+}
Something went wrong with that request. Please try again.