Избегайте ошибки журнала аудита OpenERP

Я хотел бы управлять активностью пользователя OpenERP, установив модуль аудита.
После создания некоторых правил (определить, какой пользователь, какой объект и какая активность (создание, обновление...) будут отслеживаться). Я обновляю продукт, чтобы убедиться, что он работает.
При попытке обновить продукт я получил системную ошибку. Просматривая журнал, я получаю
[2010-08-31 12:53:35,042] Курсор не закрыт явно
[2010-08-31 12:53:35,043] Курсор был создан в /home/ pilgrim/working/sources/addons/audittrail/audittrail.py:204

Вот строка, вызывающая ошибку
cr = pooler.get_db(db).cursor()
Глядя на sql_db. py, я получаю комментарий

def __del__(self):
    if not self.__closed:
        # Oops. 'self' has not been closed explicitly.
        # The cursor will be deleted by the garbage collector,
        # but the database connection is not put back into the connection
        # pool, preventing some operation on the database like dropping it.
        # This can also lead to a server overload.
        msg = "Cursor not closed explicitly\n"  \
              "Cursor was created at %s:%s" % self.__caller
        log(msg, netsvc.LOG_WARNING)
        self.close()

Поскольку я новичок в Python, я не знаю, как решить эту проблему?
Есть какие-нибудь подсказки, как решить эту проблему?
Спасибо.


person Iapilgrim    schedule 31.08.2010    source источник
comment
Предупреждение будет выдано только в том случае, если вы сами явно открыли курсор и забыли закрыть его после выполнения своей логики, вам нужно вызвать cr.close() до того, как cr выйдет из своей области....   -  person shahjapan    schedule 01.09.2010


Ответы (3)


Было бы важно увидеть исходный код, чтобы понять, что происходит. Но из того, что вы опубликовали, похоже, что предыдущий курсор не был закрыт явно.

cr = sqldb.db_connect(dbname).cursor()
.........
cr.close()
cr = None

Я бы посоветовал вам взломать audittrail.py, чтобы узнать, где вы создаете курсор и где вы его закрываете. Типичная проблема возникает при неправильной обработке исключений, что приводит к тому, что код перескакивает через обычное закрытие.

Попробуйте поместить предложения try, кроме и finally вокруг сомнительной операции с курсором. Это должно помочь вам обойти проблему.

person pyfunc    schedule 31.08.2010

Думаю, я найду ответ. См. пример

def a():  
  try:
    print 'before return '
    return 1
  finally:
    print 'in finally'

позвонить ()

before return 
in finally
1

Это нормально. OK. Попробуйте другой пример (извлеките код из audittrail.py)

def do_something_with_db(db):
   // open cusror again
   cr = db.cursor()
   // do somethign
   // close cursor internally
   cr.close()
def execute(db)
   // 1, open connection and open cursor
   cr = db.cursor
   try:
        //2, do something with db, seeing that this method will open cursor again
       return do_something_with_db(db)
   finally:
       cr.close()

Видим, что реализация do_something_with_db пытается открыть курсор (можно назвать соединением), но текущий явно не закрыт. Так что решение простое: передать текущий cr вокруг

Before
**do_something_with_db(db)**
after
**do_something_with_db(cr)**

Теперь ошибка исчезла.

@Don Kirkby: Да, мы должны поэкспериментировать с try...finally

person Iapilgrim    schedule 06.10.2010

Можете ли вы запустить OpenERP в отладчике, таком как подключаемый модуль PyDev для Eclipse? Я считаю, что это самый эффективный способ отследить проблемы. Я не использовал модуль контрольного журнала, но быстро просмотрел исходный код, и кажется, что курсор открывается в начале log_fct(). (Я ожидал, что он сообщит строку 207, какую версию вы используете?) Вот что я думаю, это соответствующий код:

def log_fct(self, db, uid, passwd, object, method, fct_src, *args):
    logged_uids = []
    pool = pooler.get_pool(db)
    cr = pooler.get_db(db).cursor() # line 207 in version 5.0.12

    # ...

    if method in ('create'):

        # ...

        cr.close()
        return res_id

    # ...

    cr.close()

Похоже, что в методе есть несколько операторов return, но каждый из них сначала вызывает cr.close(), так что я не вижу никаких очевидных проблем. Попробуйте запустить его в отладчике с точкой останова в этом методе. Если это невозможно, вы можете попробовать записать в журнал что-то вроде этого:

    logger = netsvc.Logger()
    logger.notifyChannel('audittrail', netsvc.LOG_INFO, 'something happened')

Обновление: вы отметили, что это происходит при большой нагрузке. Возможно, выбрасывается исключение, а курсор не закрывается. Вы можете использовать try ... finally инструкцию, чтобы убедиться, что курсор всегда закрыт. Вот как пример выше будет выглядеть после его преобразования:

def log_fct(self, db, uid, passwd, object, method, fct_src, *args):
    logged_uids = []
    pool = pooler.get_pool(db)
    cr = pooler.get_db(db).cursor() # line 207 in version 5.0.12
    try:

        # ...

        if method in ('create'):

            # ...

            return res_id

        # ...

    finally:
        cr.close()
person Don Kirkby    schedule 01.09.2010
comment
Я быстро просмотрел исходный код и не увидел явных проблем. У нас есть проблема в производственной среде, где многие пользователи делают много вещей, и эта проблема приводит к отключению базы данных. Я должен смоделировать стресс-тесты, чтобы увидеть, как это работает. Примечание. Я использую Pydev, но ничего не нашел. Спасибо за ваш ответ. - person Iapilgrim; 02.09.2010
comment
Добро пожаловать, @lapilgrim. Я добавил еще одно предложение поэкспериментировать с попыткой... наконец. - person Don Kirkby; 03.09.2010