Python psycopg2 - 记录事件

8
我是使用psycopg2,遇到了一个问题,需要将事件(执行的查询、通知、错误)记录到文件中。我希望能够像PgAdmin的历史窗口一样实现这个功能。
例如,我正在执行以下查询:
insert into city(id, name, countrycode, district, population) values (4080,'Savilla', 'ESP', 'andalucia', 1000000)

在PgAdmin中,我看到的效果如下:

Executing query: 
insert into city(id, name, countrycode, district, population) values (4080,'Sevilla', 'ESP', 'andalucia', 1000000)

Query executed in 26 ms.
One row affected.

我可以使用psycopg2获得类似的效果吗?

我尝试使用LoggingCursor,但对我来说并不令人满意,因为它只记录查询。

谢谢帮助。


编辑:

我的代码:

conn = psycopg2.extras.LoggingConnection(DSN)
File=open('log.log','a')
File.write('================================')
psycopg2.extras.LoggingConnection.initialize(conn,File)

File.write('\n'+time.strftime("%Y-%m-%d %H:%M:%S") + '---Executing query:\n\t')
q="""insert into city(id, name, countrycode, district, population) values (4080,'Sevilla', 'ESP', 'andalucia', 10000)"""
c=conn.cursor()
c.execute(q)
File.write('\n'+time.strftime("%Y-%m-%d %H:%M:%S") + '---Executing query:\n\t')
q="""delete from city where id = 4080"""
c=conn.cursor()
c.execute(q)
conn.commit()
File.close()

这是我的输出日志:

================================
2012-12-30 22:42:31---Executing query:
    insert into city(id, name, countrycode, district, population) values (4080,'Sevilla', 'ESP', 'andalucia', 10000)

2012-12-30 22:42:31---Executing query:
    delete from city where id = 4080

我希望在日志文件中看到关于受影响行数的信息以及错误信息。最后,我希望拥有一个包含所有事件的完整日志文件。


如果您在使用示例LoggingCursor类时遇到问题,请将您的代码和SQL语句输出一起发布,我们会尽力帮助您解决问题。 :) - Talvalin
3个回答

4
据我所见,LoggingCursor类无法满足您的三个要求:
  1. 查询执行时间
  2. 受影响的行数
  3. 包含所有事件的完整日志文件。
对于第一个要求,请查看psycopg2.extras中MinTimeLoggingConnection类的源代码。它是LoggingConnection的子类,并输出超过最小时间的查询执行时间(请注意,这需要与MinTimeLoggingCursor一起使用)。
对于第二个要求,游标类的rowcount属性指定:

最后一个execute*()语句产生的行数(对于SELECT等DQL语句)或受影响的行数(对于UPDATE或INSERT等DML语句)

因此,应该可以创建自己的LoggingConnection和LoggingCursor类型,其中包括此附加功能。
我的尝试如下。只需在代码中将LoggingConnection替换为LoggingConnection2,就可以使其全部运行。值得一提的是,您不需要为第二个查询创建新的游标。在定义第二个查询后,只需再次调用c.execute(q)即可。
import psycopg2
import os
import time
from psycopg2.extras import LoggingConnection
from psycopg2.extras import LoggingCursor

class LoggingConnection2(psycopg2.extras.LoggingConnection):
    def initialize(self, logobj):
        LoggingConnection.initialize(self, logobj)

    def filter(self, msg, curs):
        t = (time.time() - curs.timestamp) * 1000
        return msg + os.linesep + 'Query executed in: {0:.2f} ms. {1} row(s) affected.'.format(t, curs.rowcount)

    def cursor(self, *args, **kwargs):
        kwargs.setdefault('cursor_factory', LoggingCursor2)
        return super(LoggingConnection, self).cursor(*args, **kwargs)

class LoggingCursor2(psycopg2.extras.LoggingCursor):    
    def execute(self, query, vars=None):
        self.timestamp = time.time()
        return LoggingCursor.execute(self, query, vars)

    def callproc(self, procname, vars=None):
        self.timestamp = time.time()
        return LoggingCursor.execute(self, procname, vars)

我不确定如何创建所有事件的完整日志,但连接类的“notices属性”可能会引起兴趣。请参考此链接

对我有用 :) - Jeremy Salwen

2
也许你在不编写任何代码的情况下就能得到你想要的结果。
在postgresql本身中有一个名为"log_min_duration"的选项可能会帮助你解决问题。
你可以将其设置为零,每个查询都将被记录,并记录其运行时间成本。或者您可以将其设置为某个正数,比如500,postgresql只会记录运行时间至少为500毫秒的查询。
日志文件中不会返回查询结果,但会返回精确的查询内容,包括插入的绑定参数。
如果这对你有用,以后请查看auto_explain模块。
祝好运!

0

只需看一下LoggingCursor的实现方式,然后编写自己的游标子类:这非常容易。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接