2014-02-07 2 views
0

Когда я распечатывать отчеты журнала из greenlets, используя стандартный logging пакет, я получаю текст, который выглядит следующим образом:Могу ли я установить настраиваемое имя, отображаемое для gevent greenlet при регистрации?

2014-02-06 22:38:43,428 [INFO] (11396-Dummy-2) event_listener: About to block 

Я имею в виду 11396-Dummy-2 части. Например, я хотел бы сказать что-то вроде «Main» или «Listener 1». Это возможно? Из текущих документов я не вижу никаких API для этого.

ответ

3

Я не уверен, где находится участок 11396-Dummy-2 в ваших журналах, но если вы хотите добавить контекстуальную информацию в журнал (например, идентификатор зебры), вам необходимо выполнить a number of documented ways. Вот пример, используя LoggerAdapter:

import logging 
import gevent 

class Adapter(logging.LoggerAdapter): 
    def process(self, msg, kwargs): 
     msg = '(%s) %s' % (gevent.getcurrent()._run.__name__, msg) 
     return msg, kwargs 

logger = Adapter(logging.getLogger(), {}) 

def foo(): 
    logger.debug('Running in foo') 
    gevent.sleep(0) 
    logger.debug('Explicit context switch to foo again') 

def bar(): 
    logger.debug('Explicit context to bar') 
    gevent.sleep(0) 
    logger.debug('Implicit context switch back to bar') 

logging.basicConfig(level=logging.DEBUG, 
        format='%(levelname)s %(threadName)s %(message)s') 
gevent.joinall([ 
    gevent.spawn(foo), 
    gevent.spawn(bar), 
]) 

При запуске, это должно напечатать

DEBUG MainThread (foo) Running in foo 
DEBUG MainThread (bar) Explicit context to bar 
DEBUG MainThread (foo) Explicit context switch to foo again 
DEBUG MainThread (bar) Implicit context switch back to bar 
+0

Это должен быть принятый ответ. Поскольку он использует адаптер протоколирования и стандартную функциональность gevent. – Realistic

2

Обратите внимание, что если threading модуля обезьяна заплат, потоки в значительной степени преобразуется в greenlets. В частности, исправление обезьяны заменяет _start_new_thread() (так что вместо этого запускается новая зелень), а также _get_ident() (так что идентификатор Greenlet возвращается всякий раз, когда запрашивается идентификатор потока). Благодаря этому сопоставлению, всякий раз, когда вы спрашиваете о текущем потоке, на самом деле вы получаете экземпляр объекта dunky Thread, связанный с текущей запущенной зеленью!

Таким образом, вполне возможно сделать следующее:

import gevent.monkey 
gevent.monkey.patch_thread() 

from threading import current_thread 

# and then, at the start of the greenlet 
current_thread().name = "MyNewName" 

Теперь, когда logging код извлекает текущее имя нити, он получает за-greenlet имя. Я должен признать, что это немного взломанный, но в моем текущем проекте он очень хорошо работает.

И вот доказательство концепции:

import gevent.monkey 
gevent.monkey.patch_thread() 

import logging 
from threading import current_thread 

logger = logging.getLogger() 

def foo(): 
    current_thread().name = "MyFoo" 
    logger.debug('Running in foo') 
    gevent.sleep(0) 
    logger.debug('Explicit context switch to foo again') 

def bar(): 
    current_thread().name = "MyBar" 
    logger.debug('Explicit context to bar') 
    gevent.sleep(0) 
    logger.debug('Implicit context switch back to bar') 

logging.basicConfig(level=logging.DEBUG, 
        format='%(levelname)s %(threadName)s %(message)s') 
gevent.joinall([ 
    gevent.spawn(foo), 
    gevent.spawn(bar), 
]) 

При выполнении, он печатает:

DEBUG MyFoo Running in foo 
DEBUG MyBar Explicit context to bar 
DEBUG MyFoo Explicit context switch to foo again 
DEBUG MyBar Implicit context switch back to bar 

Просто убедитесь, что threading модуль пропатчен перед любым другим импортом (см this answer).