diff --git a/product/ERP5Type/LoggerStorage.py b/product/ERP5Type/LoggerStorage.py
new file mode 100644
index 0000000000000000000000000000000000000000..3cbf259ef017dfc5f394dbcba2c53477a47821f0
--- /dev/null
+++ b/product/ERP5Type/LoggerStorage.py
@@ -0,0 +1,89 @@
+# XXX license
+
+# from Products.ERP5Type.LoggerStorage import LoggerStorage
+
+import ZODB.interfaces
+import zope.interface
+
+from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
+import transaction
+import time
+from zLOG import LOG
+
+class UnsetMinimum:
+  def __lt__(self, value):
+    return False
+  def __gt__(self, value):
+    return True
+
+def logStorageStatistics(duration_list):
+  count = 0
+  min = UnsetMinimum()
+  max = 0
+  avg = 0
+  tot = 0
+  for i in duration_list:
+    count += 1
+    if i < min: min = i
+    if i > max: max = i
+    tot += i
+  if count != 0:
+    avg = tot / count
+  LOG("Storage request statistics:", 0, 'count %d, ' % count +
+                                        'total duration %s s, ' % tot +
+                                        'min/avg/max = %s/%s/%s s' % (min, avg, max))
+
+class LoggerStorage(object):
+
+  zope.interface.implements(ZODB.interfaces.IStorageWrapper)
+
+  def __init__(self, base):
+    self.base = base
+    self._collecting_statistics = False # for inter method call protection
+    zope.interface.directlyProvides(self, zope.interface.providedBy(base))
+
+  def __getattr__(self, name):
+    return getattr(self.base, name)
+
+  def _wrapAndCall(self, method, args, kw):
+    if not self._collecting_statistics:
+      self._collecting_statistics = True
+      # subscribe to hooks
+      tv = getTransactionalVariable()
+      if not tv.get("LoggerStorageHooked", False):
+        tv["LoggerStorageHooked"] = True
+        duration_list = []
+        tv["LoggerStorage_transaction_statistics"] = duration_list
+        transaction.get().addAfterCommitHook(lambda *ignored: logStorageStatistics(duration_list))
+      # measure method duration
+      try:
+        start_timestamp = time.time()
+        result = method(*args, **kw)
+        duration = time.time() - start_timestamp
+      finally:
+        self._collecting_statistics = False
+      # update statistics
+      tv["LoggerStorage_transaction_statistics"].append(duration)
+      return result
+    return method(*args, **kw)
+
+  def load(self, *args, **kw):
+    return self._wrapAndCall(self.base.load, args, kw)
+
+  def loadBefore(self, *args, **kw):
+    return self._wrapAndCall(self.base.loadBefore, args, kw)
+
+  def loadSerial(self, *args, **kw):
+    return self._wrapAndCall(self.base.loadSerial, args, kw)
+
+
+class LoggerStorageConfig:
+
+  _factory = LoggerStorage
+
+  def __init__(self, config):
+    self.config = config
+    self.name = config.getSectionName()
+
+  def open(self):
+    return self._factory(self.config.base.open())
diff --git a/product/ERP5Type/component.xml b/product/ERP5Type/component.xml
index 987449b38c176781eda7c7126f799467f6f32f49..19076fb6854ef3e6a3f43e472506a03de0bcb451 100644
--- a/product/ERP5Type/component.xml
+++ b/product/ERP5Type/component.xml
@@ -12,4 +12,8 @@
       </description>
     </key>
   </sectiontype>
+  <sectiontype name="loggerstorage" datatype="Products.ERP5Type.LoggerStorage.LoggerStorageConfig"
+               implements="ZODB.storage">
+    <section type="ZODB.storage" name="*" attribute="base" required="yes" />
+  </sectiontype>
 </component>