1

当我使用标准包从 greenlets 中打印出日志语句时logging,我得到如下所示的文本:

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

我指的是那11396-Dummy-2部分。例如,我希望它改为说“Main”或“Listener 1”之类的东西。这可能吗?从当前的文档中,我看不到任何 API 可以这样做。

4

2 回答 2

5

我不确定11396-Dummy-2您的日志中的部分来自哪里,但是如果您想将上下文信息添加到日志中(例如 greenlet 标识符),有许多记录在案的方法。这是一个示例,使用 a 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
于 2014-02-07T18:04:38.077 回答
4

请注意,如果threading模块是猴子补丁,线程几乎映射到greenlets。特别是猴子补丁替换_start_new_thread()(因此它会启动一个新的greenlet),以及_get_ident()(因此每当请求线程ID时都会返回greenlet ID)。多亏了这个映射,当你询问当前线程时,实际上你会得到一个Thread与当前运行的 greenlet 相关联的虚拟对象实例!

因此,完全可以执行以下操作:

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在任何其他导入之前修补该模块(请参阅此答案)。

于 2014-03-28T11:27:32.573 回答