]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- The psycopg2 dialect will log NOTICE messages via the
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 25 Mar 2010 21:02:50 +0000 (17:02 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 25 Mar 2010 21:02:50 +0000 (17:02 -0400)
"sqlalchemy.dialects.postgresql" logger name.
[ticket:877]

CHANGES
doc/build/dbengine.rst
lib/sqlalchemy/dialects/postgresql/psycopg2.py
test/dialect/test_postgresql.py

diff --git a/CHANGES b/CHANGES
index 37e29a035f0e6583b957b1144c85ea0abc71b15b..db32156f947873bdfdf79e3672805d20adf510d3 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -66,6 +66,11 @@ CHANGES
    - Fixed bug introduced in 0.6beta2 where column labels would 
      render inside of column expressions already assigned a label.
      [ticket:1747]
+
+- postgresql
+   - The psycopg2 dialect will log NOTICE messages via the
+     "sqlalchemy.dialects.postgresql" logger name. 
+     [ticket:877]
      
 0.6beta2
 ========
index 644ede1ba9e7d7c6326e7758ae0a79c2482276c2..246dc9f7faca2e4264cb8045be2f3d3fbf4028c5 100644 (file)
@@ -487,6 +487,7 @@ Python's standard `logging <http://www.python.org/doc/lib/module-logging.html>`_
 This section assumes familiarity with the above linked logging module.  All logging performed by SQLAlchemy exists underneath the ``sqlalchemy`` namespace, as used by ``logging.getLogger('sqlalchemy')``.  When logging has been configured (i.e. such as via ``logging.basicConfig()``), the general namespace of SA loggers that can be turned on is as follows:
 
 * ``sqlalchemy.engine`` - controls SQL echoing.  set to ``logging.INFO`` for SQL query output, ``logging.DEBUG`` for query + result set output.
+* ``sqlalchemy.dialects`` - controls custom logging for SQL dialects.  See the documentation of individual dialects for details. 
 * ``sqlalchemy.pool`` - controls connection pool logging.  set to ``logging.INFO`` or lower to log connection pool checkouts/checkins.
 * ``sqlalchemy.orm`` - controls logging of various ORM functions.  set to ``logging.INFO`` for configurational logging as well as unit of work dumps, ``logging.DEBUG`` for extensive logging during query and flush() operations.  Subcategories of ``sqlalchemy.orm`` include:
     * ``sqlalchemy.orm.attributes`` - logs certain instrumented attribute operations, such as triggered callables
index c239a3ee061df9dd11a38232969b4a0637452c62..5cbaaffd01d7fd5598dd967ff76f36f0db44e651 100644 (file)
@@ -34,6 +34,15 @@ Transactions
 
 The psycopg2 dialect fully supports SAVEPOINT and two-phase commit operations.
 
+NOTICE logging
+---------------
+
+The psycopg2 dialect will log Postgresql NOTICE messages via the 
+``sqlalchemy.dialects.postgresql`` logger::
+
+    import logging
+    logging.getLogger('sqlalchemy.dialects.postgresql').setLevel(logging.INFO)
+
 
 Per-Statement Execution Options
 -------------------------------
@@ -46,8 +55,10 @@ The following per-statement execution options are respected:
 
 """
 
-import random, re
+import random
+import re
 import decimal
+import logging
 
 from sqlalchemy import util
 from sqlalchemy import processors
@@ -59,6 +70,10 @@ from sqlalchemy.dialects.postgresql.base import PGDialect, PGCompiler, \
                                             PGIdentifierPreparer, PGExecutionContext, \
                                             ENUM, ARRAY
 
+
+logger = logging.getLogger('sqlalchemy.dialects.postgresql')
+
+
 class _PGNumeric(sqltypes.Numeric):
     def bind_processor(self, dialect):
         return None
@@ -130,11 +145,22 @@ class PGExecutionContext_psycopg2(PGExecutionContext):
             return self._connection.connection.cursor()
 
     def get_result_proxy(self):
+        if logger.isEnabledFor(logging.INFO):
+            self._log_notices(self.cursor)
+        
         if self.__is_server_side:
             return base.BufferedRowResultProxy(self)
         else:
             return base.ResultProxy(self)
 
+    def _log_notices(self, cursor):
+        for notice in cursor.connection.notices:
+            # NOTICE messages have a 
+            # newline character at the end
+            logger.info(notice.rstrip())
+
+        cursor.connection.notices[:] = []
+
 
 class PGCompiler_psycopg2(PGCompiler):
     def visit_mod(self, binary, **kw):
@@ -190,7 +216,7 @@ class PGDialect_psycopg2(PGDialect):
             return connect
         else:
             return base_on_connect
-            
+
     def create_connect_args(self, url):
         opts = url.translate_connect_args(username='user')
         if 'port' in opts:
index 472b12e508c7d5a29e95dbaaa697de670c45d98d..bc3fbc6145f3af7827b1573f4ac071caea978fb7 100644 (file)
@@ -13,6 +13,7 @@ from sqlalchemy.test.util import round_decimal
 from sqlalchemy.sql import table, column
 from sqlalchemy.test.testing import eq_
 from test.engine._base import TablesTest
+import logging
 
 class SequenceTest(TestBase, AssertsCompiledSQL):
     def test_basic(self):
@@ -395,9 +396,6 @@ class EnumTest(TestBase, AssertsExecutionResults, AssertsCompiledSQL):
         finally:
             metadata.drop_all()
         
-        
-        
-        
 class InsertTest(TestBase, AssertsExecutionResults):
     __only_on__ = 'postgresql'
 
@@ -964,7 +962,6 @@ class DomainReflectionTest(TestBase, AssertsExecutionResults):
         finally:
             postgresql.PGDialect.ischema_names = ischema_names
 
-
 class MiscTest(TestBase, AssertsExecutionResults, AssertsCompiledSQL):
     __only_on__ = 'postgresql'
 
@@ -1001,6 +998,29 @@ class MiscTest(TestBase, AssertsExecutionResults, AssertsCompiledSQL):
         ]:
             
             eq_(testing.db.dialect._get_server_version_info(MockConn(string)), version)
+    
+    @testing.only_on('postgresql+psycopg2', 'psycopg2-specific feature')
+    def test_notice_logging(self):
+        log = logging.getLogger('sqlalchemy.dialects.postgresql')
+        buf = logging.handlers.BufferingHandler(100)
+        lev = log.level
+        log.addHandler(buf)
+        log.setLevel(logging.INFO)
+        try:
+            conn = testing.db.connect()
+            trans = conn.begin()
+            try:
+                conn.execute("create table foo (id serial primary key)")
+            finally:
+                trans.rollback()
+        finally:
+            log.removeHandler(buf)
+            log.setLevel(lev)
+
+        msgs = " ".join(b.msg for b in buf.buffer)
+        assert "will create implicit sequence" in msgs
+        assert "will create implicit index" in msgs
+         
         
     def test_pg_weirdchar_reflection(self):
         meta1 = MetaData(testing.db)