[Checkins] SVN: mongopersist/trunk/ Added quite detailed debug logging around collection methods

Adam Groszer cvs-admin at zope.org
Wed Mar 28 14:51:51 UTC 2012


Log message for revision 124772:
  Added quite detailed debug logging around collection methods

Changed:
  U   mongopersist/trunk/CHANGES.txt
  U   mongopersist/trunk/setup.py
  U   mongopersist/trunk/src/mongopersist/datamanager.py
  U   mongopersist/trunk/src/mongopersist/serialize.py

-=-
Modified: mongopersist/trunk/CHANGES.txt
===================================================================
--- mongopersist/trunk/CHANGES.txt	2012-03-28 14:46:09 UTC (rev 124771)
+++ mongopersist/trunk/CHANGES.txt	2012-03-28 14:51:47 UTC (rev 124772)
@@ -5,7 +5,7 @@
 0.6.1 (unreleased)
 ------------------
 
-- ...
+- Added quite detailed debug logging around collection methods
 
 0.6.0 (2012-03-12)
 ------------------

Modified: mongopersist/trunk/setup.py
===================================================================
--- mongopersist/trunk/setup.py	2012-03-28 14:46:09 UTC (rev 124771)
+++ mongopersist/trunk/setup.py	2012-03-28 14:51:47 UTC (rev 124772)
@@ -45,6 +45,7 @@
         'setuptools',
         'zope.dottedname',
         'zope.interface',
+        'zope.exceptions >=3.7.1', # required for extract_stack
     ],
     include_package_data = True,
     zip_safe = False,

Modified: mongopersist/trunk/src/mongopersist/datamanager.py
===================================================================
--- mongopersist/trunk/src/mongopersist/datamanager.py	2012-03-28 14:46:09 UTC (rev 124771)
+++ mongopersist/trunk/src/mongopersist/datamanager.py	2012-03-28 14:51:47 UTC (rev 124772)
@@ -14,14 +14,20 @@
 """Mongo Persistent Data Manager"""
 from __future__ import absolute_import
 import UserDict
+import logging
 import persistent
 import pymongo
 import pymongo.dbref
 import transaction
+import traceback
+import sys
 import zope.interface
 
+from zope.exceptions import exceptionformatter
 from mongopersist import interfaces, serialize
 
+COLLECTION_LOG = logging.getLogger('mongopersist.collection')
+
 def create_conflict_error(obj, new_doc):
     return interfaces.ConflictError(
         None, obj,
@@ -67,8 +73,39 @@
             kwargs['query'] = process_spec(self.collection, kwargs['query'])
         return self.function(*args, **kwargs)
 
+class LoggingDecorator(object):
+
+    # these are here to be easily patched
+    ADDTB = True
+    TB_LIMIT = 10 # 10 should be sufficient to figure
+
+    def __init__(self, collection, function):
+        self.collection = collection
+        self.function = function
+
+    def __call__(self, *args, **kwargs):
+        if self.ADDTB:
+            try:
+                raise ValueError('boom')
+            except:
+                # we need here exceptionformatter, otherwise __traceback_info__
+                # is not added
+                tb = ''.join(exceptionformatter.extract_stack(
+                    sys.exc_info()[2].tb_frame.f_back, limit=self.TB_LIMIT))
+        else:
+            tb = '<omitted>'
+
+        COLLECTION_LOG.debug(
+            "collection: %s.%s %s,\n args:%r,\n kwargs:%r, \n tb:\n%s",
+            self.collection.database.name, self.collection.name,
+            self.function.__name__, args, kwargs, tb)
+
+        return self.function(*args, **kwargs)
+
 class CollectionWrapper(object):
 
+    LOGGED_METHODS = ['insert', 'update', 'remove', 'save',
+                      'find_and_modify', 'find_one', 'find', 'count']
     QUERY_METHODS = ['group', 'map_reduce', 'inline_map_reduce', 'find_one',
                      'find', 'find_and_modify']
     PROCESS_SPEC_METHODS = ['find_and_modify', 'find_one', 'find']
@@ -79,6 +116,8 @@
 
     def __getattr__(self, name):
         attr = getattr(self.collection, name)
+        if name in self.LOGGED_METHODS:
+            attr = LoggingDecorator(self.collection, attr)
         if name in self.QUERY_METHODS:
             attr = FlushDecorator(self._datamanager, attr)
         if name in self.PROCESS_SPEC_METHODS:
@@ -254,7 +293,7 @@
         if obj._p_changed is None:
             self.setstate(obj)
         # Now we remove the object from Mongo.
-        coll = self._get_collection_from_object(obj)
+        coll = self.get_collection_from_object(obj)
         coll.remove({'_id': obj._p_oid.id})
         self._removed_objects.append(obj)
         # Just in case the object was modified before removal, let's remove it
@@ -291,16 +330,16 @@
         # Aborting the transaction requires three steps:
         # 1. Remove any inserted objects.
         for obj in self._inserted_objects:
-            coll = self._get_collection_from_object(obj)
+            coll = self.get_collection_from_object(obj)
             coll.remove({'_id': obj._p_oid.id})
         # 2. Re-insert any removed objects.
         for obj in self._removed_objects:
-            coll = self._get_collection_from_object(obj)
+            coll = self.get_collection_from_object(obj)
             coll.insert(self._original_states[obj._p_oid])
             del self._original_states[obj._p_oid]
         # 3. Reset any changed states.
         for db_ref, state in self._original_states.items():
-            coll = self._get_collection(db_ref.database, db_ref.collection)
+            coll = self.get_collection(db_ref.database, db_ref.collection)
             coll.update({'_id': db_ref.id}, state, True)
         self.reset()
 

Modified: mongopersist/trunk/src/mongopersist/serialize.py
===================================================================
--- mongopersist/trunk/src/mongopersist/serialize.py	2012-03-28 14:46:09 UTC (rev 124771)
+++ mongopersist/trunk/src/mongopersist/serialize.py	2012-03-28 14:51:47 UTC (rev 124772)
@@ -73,6 +73,7 @@
         self._jar = jar
 
     def get_collection_name(self, obj):
+        __traceback_info__ = obj
         db_name = getattr(obj, '_p_mongo_database', self._jar.default_database)
         try:
             coll_name = obj._p_mongo_collection
@@ -211,11 +212,13 @@
         return self.get_non_persistent_state(obj, seen)
 
     def store(self, obj, ref_only=False):
+        __traceback_info__ = (obj, ref_only)
+
         db_name, coll_name = self.get_collection_name(obj)
-        coll = self._jar._get_collection(db_name, coll_name)
+        coll = self._jar.get_collection(db_name, coll_name)
         if ref_only:
             # We only want to get OID quickly. Trying to reduce the full state
-            # might cause infinite recusrion loop. (Example: 2 new objects
+            # might cause infinite recursion loop. (Example: 2 new objects
             # reference each other.)
             doc = {}
             # Make sure that the object gets saved fully later.
@@ -255,6 +258,7 @@
         return resolve(path)
 
     def resolve(self, dbref):
+        __traceback_info__ = dbref
         try:
             return OID_CLASS_LRU[dbref.id]
         except KeyError:
@@ -282,7 +286,7 @@
             # Multiple object types are stored in the collection. We have to
             # look at the object to find out the type.
             obj_doc = self._jar\
-                ._get_collection(dbref.database, dbref.collection).find_one(
+                .get_collection(dbref.database, dbref.collection).find_one(
                     dbref.id, fields=('_py_persistent_type',))
             if '_py_persistent_type' in obj_doc:
                 klass = self.simple_resolve(obj_doc['_py_persistent_type'])
@@ -374,9 +378,10 @@
         return state
 
     def set_ghost_state(self, obj, doc=None):
+        __traceback_info__ = (obj, doc)
         # Look up the object state by coll_name and oid.
         if doc is None:
-            coll = self._jar._get_collection(
+            coll = self._jar.get_collection(
                 obj._p_oid.database, obj._p_oid.collection)
             doc = coll.find_one({'_id': obj._p_oid.id})
         # Remove unwanted attributes.



More information about the checkins mailing list