| 
									
										
										
										
											2012-04-06 18:28:26 -07:00
										 |  |  | from django.core.exceptions import MiddlewareNotUsed | 
					
						
							|  |  |  | from django.conf import settings | 
					
						
							|  |  |  | from django.db import connection | 
					
						
							| 
									
										
										
										
											2013-05-30 10:39:41 -07:00
										 |  |  | from pymongo.mongo_client import MongoClient | 
					
						
							|  |  |  | from pymongo.mongo_replica_set_client import MongoReplicaSetClient | 
					
						
							| 
									
										
										
										
											2012-04-06 18:28:26 -07:00
										 |  |  | from time import time | 
					
						
							|  |  |  | import struct | 
					
						
							|  |  |  | import bson | 
					
						
							|  |  |  | from bson.errors import InvalidBSON | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-18 19:19:43 -07:00
										 |  |  | class MongoDumpMiddleware(object):     | 
					
						
							|  |  |  |     def activated(self, request): | 
					
						
							| 
									
										
										
										
											2014-05-20 12:21:17 -07:00
										 |  |  |         return (settings.DEBUG_QUERIES or  | 
					
						
							| 
									
										
										
										
											2014-03-19 14:59:07 -07:00
										 |  |  |                 (hasattr(request, 'activated_segments') and | 
					
						
							|  |  |  |                  'db_profiler' in request.activated_segments)) | 
					
						
							| 
									
										
										
										
											2014-03-18 19:19:43 -07:00
										 |  |  |      | 
					
						
							| 
									
										
										
										
											2012-04-06 18:28:26 -07:00
										 |  |  |     def process_view(self, request, callback, callback_args, callback_kwargs): | 
					
						
							| 
									
										
										
										
											2014-03-18 19:19:43 -07:00
										 |  |  |         if not self.activated(request): return | 
					
						
							| 
									
										
										
										
											2012-04-06 18:28:26 -07:00
										 |  |  |         self._used_msg_ids = [] | 
					
						
							| 
									
										
										
										
											2014-03-18 19:19:43 -07:00
										 |  |  |         if not getattr(MongoClient, '_logging', False): | 
					
						
							| 
									
										
										
										
											2012-04-06 18:28:26 -07:00
										 |  |  |             # save old methods | 
					
						
							| 
									
										
										
										
											2013-07-31 11:17:04 -07:00
										 |  |  |             setattr(MongoClient, '_logging', True) | 
					
						
							| 
									
										
										
										
											2013-05-30 10:39:41 -07:00
										 |  |  |             MongoClient._send_message_with_response = \ | 
					
						
							|  |  |  |                     self._instrument(MongoClient._send_message_with_response) | 
					
						
							| 
									
										
										
										
											2015-12-16 17:31:41 -08:00
										 |  |  |             MongoReplicaSetClient._send_message_with_response = \ | 
					
						
							|  |  |  |                     self._instrument(MongoReplicaSetClient._send_message_with_response) | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def process_celery(self, profiler): | 
					
						
							|  |  |  |         if not self.activated(profiler): return | 
					
						
							|  |  |  |         self._used_msg_ids = [] | 
					
						
							|  |  |  |         if not getattr(MongoClient, '_logging', False): | 
					
						
							|  |  |  |             # save old methods | 
					
						
							|  |  |  |             setattr(MongoClient, '_logging', True) | 
					
						
							|  |  |  |             MongoClient._send_message_with_response = \ | 
					
						
							|  |  |  |                     self._instrument(MongoClient._send_message_with_response) | 
					
						
							| 
									
										
										
										
											2013-05-30 10:39:41 -07:00
										 |  |  |             MongoReplicaSetClient._send_message_with_response = \ | 
					
						
							|  |  |  |                     self._instrument(MongoReplicaSetClient._send_message_with_response) | 
					
						
							| 
									
										
										
										
											2012-04-06 18:28:26 -07:00
										 |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def process_response(self, request, response): | 
					
						
							| 
									
										
										
										
											2013-07-31 11:17:04 -07:00
										 |  |  |         # if settings.DEBUG and hasattr(self, 'orig_send_message') and hasattr(self, 'orig_send_message_with_response'): | 
					
						
							|  |  |  |         #     # remove instrumentation from pymongo | 
					
						
							|  |  |  |         #     MongoClient._send_message = \ | 
					
						
							|  |  |  |         #             self.orig_send_message | 
					
						
							|  |  |  |         #     MongoClient._send_message_with_response = \ | 
					
						
							|  |  |  |         #             self.orig_send_message_with_response | 
					
						
							|  |  |  |         #     MongoReplicaSetClient._send_message = \ | 
					
						
							|  |  |  |         #             self.orig_rs_send_message | 
					
						
							|  |  |  |         #     MongoReplicaSetClient._send_message_with_response = \ | 
					
						
							|  |  |  |         #             self.orig_rs_send_message_with_response | 
					
						
							| 
									
										
										
										
											2012-04-06 18:28:26 -07:00
										 |  |  |         return response | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _instrument(self, original_method): | 
					
						
							|  |  |  |         def instrumented_method(*args, **kwargs): | 
					
						
							| 
									
										
										
										
											2016-11-10 10:11:46 -08:00
										 |  |  |             query = args[1].get_message(False, False) | 
					
						
							|  |  |  |             message = _mongodb_decode_wire_protocol(query[1]) | 
					
						
							|  |  |  |             # message = _mongodb_decode_wire_protocol(args[1][1]) | 
					
						
							| 
									
										
										
										
											2012-07-25 16:58:56 -07:00
										 |  |  |             if not message or message['msg_id'] in self._used_msg_ids: | 
					
						
							| 
									
										
										
										
											2012-04-06 18:28:26 -07:00
										 |  |  |                 return original_method(*args, **kwargs) | 
					
						
							|  |  |  |             self._used_msg_ids.append(message['msg_id']) | 
					
						
							|  |  |  |             start = time() | 
					
						
							|  |  |  |             result = original_method(*args, **kwargs) | 
					
						
							|  |  |  |             stop = time() | 
					
						
							|  |  |  |             duration = stop - start | 
					
						
							|  |  |  |             connection.queries.append({ | 
					
						
							|  |  |  |                 'mongo': message, | 
					
						
							|  |  |  |                 'time': '%.3f' % duration, | 
					
						
							|  |  |  |             }) | 
					
						
							|  |  |  |             return result | 
					
						
							|  |  |  |         return instrumented_method | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _mongodb_decode_wire_protocol(message): | 
					
						
							|  |  |  |     """ http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol """ | 
					
						
							|  |  |  |     MONGO_OPS = { | 
					
						
							| 
									
										
										
										
											2013-05-30 10:39:41 -07:00
										 |  |  |         1000: 'msg', | 
					
						
							|  |  |  |         2001: 'update', | 
					
						
							| 
									
										
										
										
											2012-04-06 18:28:26 -07:00
										 |  |  |         2002: 'insert', | 
					
						
							|  |  |  |         2003: 'reserved', | 
					
						
							|  |  |  |         2004: 'query', | 
					
						
							|  |  |  |         2005: 'get_more', | 
					
						
							|  |  |  |         2006: 'delete', | 
					
						
							|  |  |  |         2007: 'kill_cursors', | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     _, msg_id, _, opcode, _ = struct.unpack('<iiiii', message[:20]) | 
					
						
							|  |  |  |     op = MONGO_OPS.get(opcode, 'unknown') | 
					
						
							|  |  |  |     zidx = 20 | 
					
						
							|  |  |  |     collection_name_size = message[zidx:].find('\0') | 
					
						
							|  |  |  |     collection_name = message[zidx:zidx+collection_name_size] | 
					
						
							| 
									
										
										
										
											2012-07-25 16:58:56 -07:00
										 |  |  |     if '.system.' in collection_name: | 
					
						
							|  |  |  |         return | 
					
						
							| 
									
										
										
										
											2012-04-06 18:28:26 -07:00
										 |  |  |     zidx += collection_name_size + 1 | 
					
						
							|  |  |  |     skip, limit = struct.unpack('<ii', message[zidx:zidx+8]) | 
					
						
							|  |  |  |     zidx += 8 | 
					
						
							|  |  |  |     msg = "" | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         if message[zidx:]: | 
					
						
							| 
									
										
										
										
											2012-07-25 16:58:56 -07:00
										 |  |  |             msg = bson.decode_all(message[zidx:]) | 
					
						
							| 
									
										
										
										
											2012-10-30 08:31:37 -07:00
										 |  |  |     except: | 
					
						
							| 
									
										
										
										
											2012-04-06 18:28:26 -07:00
										 |  |  |         msg = 'invalid bson' | 
					
						
							|  |  |  |     return { 'op': op, 'collection': collection_name, | 
					
						
							|  |  |  |              'msg_id': msg_id, 'skip': skip, 'limit': limit, | 
					
						
							|  |  |  |              'query': msg } |