在Pylons应用中创建的工作线程中的日志记录似乎无法工作

0 投票
2 回答
742 浏览
提问于 2025-04-15 20:03

我有一个使用pylons框架的应用程序,在某些情况下,我想启动多个工作线程来处理队列中的项目。目前我们还没有使用线程池(理想情况下会用到,但我们会在后面加上)。主要的问题是,工作线程的日志没有写入日志文件。

当我在pylons应用程序外运行代码时,日志记录正常。所以我觉得这可能和pylons的日志处理有关,但不太确定具体是什么问题。

下面是一个简化的代码示例:

import logging
log = logging.getLogger(__name__)

import sys
from Queue import Queue
from threading import Thread, activeCount

def run(input, worker, args = None, simulteneousWorkerLimit = None):
    queue = Queue()
    threads = []

    if args is not None:
        if len(args) > 0:
            args = list(args)
            args = [worker, queue] + args
            args = tuple(args)
        else:
            args = (worker, queue)

    # start threads
    for i in range(4):
        t = Thread(target = __thread, args = args)
        t.daemon = True
        t.start()
        threads.append(t)

    # add ThreadTermSignal
    inputData = list(input)
    inputData.extend([ThreadTermSignal] * 4)

    # put in the queue
    for data in inputData:
        queue.put(data)

    # block until all contents are downloaded
    queue.join()
    log.critical("** A log line that appears fine **")

    del queue
    for thread in threads:
        del thread
    del threads

class ThreadTermSignal(object):
    pass

def __thread(worker, queue, *args):
    try:
        while True:
            data = queue.get()
            if data is ThreadTermSignal:
                sys.exit()
            try:
                log.critical("** I don't appear when run under pylons **")
            finally:
                queue.task_done()
    except SystemExit:
        queue.task_done()
        pass

请注意,RUN方法中的日志记录会出现在日志文件中,但在工作方法中的日志记录(这是在新线程中运行的)却没有出现。任何帮助都非常感谢。谢谢!

** 编辑:我应该提到,我尝试将“log”变量传递给工作线程,并在线程内重新定义一个新的“log”变量,但都没有成功。

** 编辑:添加了用于pylons应用程序的配置(来自INI文件)。下面的代码片段就是来自INI文件。

[loggers]
keys = root

[handlers]
keys = wsgierrors

[formatters]
keys = generic

[logger_root]
level = WARNING
handlers = wsgierrors

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = WARNING
formatter = generic

[handler_wsgierrors]
class = pylons.log.WSGIErrorsHandler
args = ()
level = WARNING
format = generic

2 个回答

0

你可以通过参数(args)把一个 log 变量传递给线程。

1

关于日志记录,有一点需要注意:如果在记录日志时发生了错误(无论是什么原因),这个错误通常会被忽略,不会让应用程序因为日志错误而崩溃。(这取决于使用的处理程序和logging.raiseExceptions的设置)。所以你可以检查几个方面:

  • 确保你的日志信息格式非常简单,可能只用%(message)s,直到你找到问题为止。
  • 检查一下Pylons是否关闭了日志记录或者因为某种原因搞乱了处理程序。你没有提供你的日志初始化代码,所以我不确定你使用了什么处理程序等。你可以打印log.getEffectiveLevel()来看看日志的详细程度是否被调低了(虽然CRITICAL级别不太可能,但谁知道呢)。

如果你在日志语句旁边加了打印语句,它们的输出是否如你所预期的那样?

更新:我知道关于mod_wsgi和打印的限制,但那只适用于sys.stdout。你可以例如:

print >> sys.stderr, some_data

或者

print >> open('/tmp/somefile', 'a'), some_data

这样做没有任何问题。

另外,你应该知道,调用logging.config.fileConfig()(这大概是你描述的配置实现方式)会禁用任何现有的日志记录器,除非它们在配置文件中被明确命名,或者是那些被明确命名的日志记录器的子类。虽然这听起来有点奇怪,但这是因为配置是用来替换现有配置,而不是增加它;而且由于线程可能指向现有的日志记录器,所以它们会被禁用而不是删除。你可以检查一个日志记录器的disabled属性,看看fileConfig()是否禁用了这个日志记录器——这可能就是你的问题所在。

撰写回答