12
12
namespace Symfony \Bundle \DoctrineMongoDBBundle \Logger ;
13
13
14
14
use Symfony \Component \HttpKernel \Log \LoggerInterface ;
15
- use Symfony \Component \Yaml \Yaml ;
16
15
17
16
/**
18
17
* Logger for the Doctrine MongoDB ODM.
19
18
*
19
+ * The {@link logQuery()} method is configured as the logger callable in the
20
+ * service container.
21
+ *
20
22
* @author Kris Wallsmith <kris.wallsmith@symfony.com>
21
23
*/
22
24
class DoctrineMongoDBLogger
23
25
{
24
- const LOG_PREFIX = 'MongoDB query: ' ;
25
-
26
26
protected $ logger ;
27
- protected $ nbQueries ;
28
27
29
- public function __construct (LoggerInterface $ logger = null )
28
+ protected $ prefix ;
29
+ protected $ queries ;
30
+
31
+ protected $ processed ;
32
+ protected $ formattedQueries ;
33
+ protected $ nbRealQueries ;
34
+
35
+ /**
36
+ * Constructor.
37
+ *
38
+ * @param LoggerInterface $logger The Symfony logger
39
+ * @param string $prefix A prefix for messages sent to the Symfony logger
40
+ */
41
+ public function __construct (LoggerInterface $ logger = null , $ prefix = 'MongoDB query: ' )
30
42
{
31
43
$ this ->logger = $ logger ;
32
- $ this ->nbQueries = 0 ;
44
+ $ this ->prefix = $ prefix ;
45
+ $ this ->queries = array ();
46
+ $ this ->processed = false ;
33
47
}
34
48
49
+ /**
50
+ * Logs a query.
51
+ *
52
+ * This method is configured as the logger callable in the service
53
+ * container.
54
+ *
55
+ * @param array $query A query log array from Doctrine
56
+ */
35
57
public function logQuery ($ query )
36
58
{
37
- ++$ this ->nbQueries ;
59
+ $ this ->queries [] = $ query ;
60
+ $ this ->processed = false ;
38
61
39
62
if (null !== $ this ->logger ) {
40
- $ this ->logger ->info (static :: LOG_PREFIX .static ::formatQuery ($ query ));
63
+ $ this ->logger ->info ($ this -> prefix .static ::bsonEncode ($ query ));
41
64
}
42
65
}
43
66
67
+ /**
68
+ * Returns the number of queries that have been logged.
69
+ *
70
+ * @return integer The number of queries logged
71
+ */
44
72
public function getNbQueries ()
45
73
{
46
- return $ this ->nbQueries ;
74
+ if (!$ this ->processed ) {
75
+ $ this ->processQueries ();
76
+ }
77
+
78
+ return $ this ->nbRealQueries ;
47
79
}
48
80
81
+ /**
82
+ * Returns a human-readable array of queries logged.
83
+ *
84
+ * @return array An array of queries
85
+ */
49
86
public function getQueries ()
50
87
{
51
- if (null === $ this ->logger ) {
52
- return false ;
88
+ if (! $ this ->processed ) {
89
+ $ this -> processQueries () ;
53
90
}
54
91
55
- $ logger = $ this ->logger ->getDebugLogger ();
56
-
57
- if (!$ logger ) {
58
- return false ;
59
- }
60
-
61
- $ offset = strlen (static ::LOG_PREFIX );
62
- $ mapper = function ($ log ) use ($ offset )
63
- {
64
- if (0 === strpos ($ log ['message ' ], DoctrineMongoDBLogger::LOG_PREFIX )) {
65
- return substr ($ log ['message ' ], $ offset );
66
- }
67
- };
68
-
69
- // map queries from logs, remove empty entries and re-index the array
70
- return array_values (array_filter (array_map ($ mapper , $ logger ->getLogs ())));
92
+ return $ this ->formattedQueries ;
71
93
}
72
94
73
95
/**
74
- * Formats the supplied query array recursively .
96
+ * Groups and formats query arrays .
75
97
*
76
- * @param array $query All or part of a query array
98
+ * @param array $queries An array of query arrays
77
99
*
78
- * @return string A serialized object for the log
100
+ * @return array An array of human-readable queries
79
101
*/
80
- static protected function formatQuery (array $ query , $ array = true )
102
+ protected function processQueries ()
103
+ {
104
+ $ this ->formattedQueries = array ();
105
+ $ this ->nbRealQueries = 0 ;
106
+
107
+ $ grouped = array ();
108
+ $ ordered = array ();
109
+ foreach ($ this ->queries as $ query ) {
110
+ $ cursor = serialize ($ query ['query ' ]).serialize ($ query ['fields ' ]);
111
+
112
+ // append if issued from cursor (currently just "sort")
113
+ if (isset ($ query ['sort ' ])) {
114
+ unset($ query ['query ' ], $ query ['fields ' ]);
115
+ $ grouped [$ cursor ][count ($ grouped [$ cursor ]) - 1 ][] = $ query ;
116
+ } else {
117
+ $ grouped [$ cursor ][] = array ($ query );
118
+ $ ordered [] =& $ grouped [$ cursor ][count ($ grouped [$ cursor ]) - 1 ];
119
+ }
120
+ }
121
+
122
+ $ i = 0 ;
123
+ $ db = '' ;
124
+ $ query = '' ;
125
+ foreach ($ ordered as $ logs ) {
126
+ foreach ($ logs as $ log ) {
127
+ if (isset ($ log ['db ' ]) && $ db != $ log ['db ' ]) {
128
+ // for readability
129
+ $ this ->formattedQueries [$ i ++] = 'use ' .$ log ['db ' ].'; ' ;
130
+ $ db = $ log ['db ' ];
131
+ }
132
+
133
+ if (isset ($ log ['collection ' ])) {
134
+ // flush the previous and start a new query
135
+ if (!empty ($ query )) {
136
+ if ('. ' == $ query [0 ]) {
137
+ $ query = 'db ' .$ query ;
138
+ }
139
+
140
+ $ this ->formattedQueries [$ i ++] = $ query .'; ' ;
141
+ ++$ this ->nbRealQueries ;
142
+ }
143
+
144
+ $ query = 'db. ' .$ log ['collection ' ];
145
+ }
146
+
147
+ // format the method call
148
+ if (isset ($ log ['authenticate ' ])) {
149
+ $ query .= '.authenticate() ' ;
150
+ } elseif (isset ($ log ['batchInsert ' ])) {
151
+ $ query .= '.batchInsert(** ' .$ log ['num ' ].' item(s)**) ' ;
152
+ } elseif (isset ($ log ['command ' ])) {
153
+ $ query .= '.command() ' ;
154
+ } elseif (isset ($ log ['count ' ])) {
155
+ $ query .= '.count( ' ;
156
+ if ($ log ['query ' ] || $ log ['limit ' ] || $ log ['skip ' ]) {
157
+ $ query .= static ::bsonEncode ($ log ['query ' ]);
158
+ if ($ log ['limit ' ] || $ log ['skip ' ]) {
159
+ $ query .= ', ' .static ::bsonEncode ($ log ['limit ' ]);
160
+ if ($ log ['skip ' ]) {
161
+ $ query .= ', ' .static ::bsonEncode ($ log ['skip ' ]);
162
+ }
163
+ }
164
+ }
165
+ $ query .= ') ' ;
166
+ } elseif (isset ($ log ['createCollection ' ])) {
167
+ $ query .= '.createCollection() ' ;
168
+ } elseif (isset ($ log ['createDBRef ' ])) {
169
+ $ query .= '.createDBRef() ' ;
170
+ } elseif (isset ($ log ['deleteIndex ' ])) {
171
+ $ query .= '.dropIndex( ' .static ::bsonEncode ($ log ['keys ' ]).') ' ;
172
+ } elseif (isset ($ log ['deleteIndexes ' ])) {
173
+ $ query .= '.dropIndexes() ' ;
174
+ } elseif (isset ($ log ['drop ' ])) {
175
+ $ query .= '.drop() ' ;
176
+ } elseif (isset ($ log ['dropDatabase ' ])) {
177
+ $ query .= '.dropDatabase() ' ;
178
+ } elseif (isset ($ log ['ensureIndex ' ])) {
179
+ $ query .= '.ensureIndex( ' .static ::bsonEncode ($ log ['keys ' ]).', ' .static ::bsonEncode ($ log ['options ' ]).') ' ;
180
+ } elseif (isset ($ log ['execute ' ])) {
181
+ $ query .= '.execute() ' ;
182
+ } elseif (isset ($ log ['find ' ])) {
183
+ $ query .= '.find( ' .static ::bsonEncode ($ log ['query ' ]);
184
+ if (!empty ($ log ['fields ' ])) {
185
+ $ query .= ', ' .static ::bsonEncode ($ log ['fields ' ]);
186
+ }
187
+ $ query .= ') ' ;
188
+ } elseif (isset ($ log ['findOne ' ])) {
189
+ $ query .= '.findOne( ' .static ::bsonEncode ($ log ['query ' ]);
190
+ if (!empty ($ log ['fields ' ])) {
191
+ $ query .= ', ' .static ::bsonEncode ($ log ['fields ' ]);
192
+ }
193
+ $ query .= ') ' ;
194
+ } elseif (isset ($ log ['getDBRef ' ])) {
195
+ $ query .= '.getDBRef() ' ;
196
+ } elseif (isset ($ log ['group ' ])) {
197
+ $ query .= '.group( ' .static ::bsonEncode (array (
198
+ 'keys ' => $ log ['keys ' ],
199
+ 'initial ' => $ log ['initial ' ],
200
+ 'reduce ' => $ log ['reduce ' ],
201
+ )).') ' ;
202
+ } elseif (isset ($ log ['insert ' ])) {
203
+ $ query .= '.insert( ' .static ::bsonEncode ($ log ['document ' ]).') ' ;
204
+ } elseif (isset ($ log ['remove ' ])) {
205
+ $ query .= '.remove( ' .static ::bsonEncode ($ log ['query ' ]).') ' ;
206
+ } elseif (isset ($ log ['save ' ])) {
207
+ $ query .= '.save( ' .static ::bsonEncode ($ log ['document ' ]).') ' ;
208
+ } elseif (isset ($ log ['sort ' ])) {
209
+ $ query .= '.sort( ' .static ::bsonEncode ($ log ['sortFields ' ]).') ' ;
210
+ } elseif (isset ($ log ['update ' ])) {
211
+ // todo: include $log['options']
212
+ $ query .= '.update( ' .static ::bsonEncode ($ log ['query ' ]).', ' .static ::bsonEncode ($ log ['newObj ' ]).') ' ;
213
+ } elseif (isset ($ log ['validate ' ])) {
214
+ $ query .= '.validate() ' ;
215
+ }
216
+ }
217
+ }
218
+ }
219
+
220
+ static protected function bsonEncode ($ query , $ array = true )
81
221
{
82
222
$ parts = array ();
83
223
@@ -91,7 +231,7 @@ static protected function formatQuery(array $query, $array = true)
91
231
} elseif (is_scalar ($ value )) {
92
232
$ formatted = '" ' .$ value .'" ' ;
93
233
} elseif (is_array ($ value )) {
94
- $ formatted = static ::formatQuery ($ value );
234
+ $ formatted = static ::bsonEncode ($ value );
95
235
} elseif ($ value instanceof \MongoId) {
96
236
$ formatted = 'ObjectId(" ' .$ value .'") ' ;
97
237
} elseif ($ value instanceof \MongoDate) {
@@ -107,7 +247,7 @@ static protected function formatQuery(array $query, $array = true)
107
247
} elseif ($ value instanceof \MongoBinData) {
108
248
$ formatted = 'new BinData(" ' .$ value ->bin .'", " ' .$ value ->type .'") ' ;
109
249
} elseif ($ value instanceof \stdClass) {
110
- $ formatted = static ::formatQuery ((array ) $ value, false );
250
+ $ formatted = static ::bsonEncode ((array ) $ value );
111
251
} else {
112
252
$ formatted = (string ) $ value ;
113
253
}
0 commit comments