当应用程序有多个调用时,日志记录配置无法加载value-formatter() - python

我正在使用bottle wsgi框架创建Web服务。我在app.py(显示在app.py中)中配置了记录器,该记录器接收应用程序调用,并使用get_output()方法将输入参数传递给backend.py。我正在使用backend.py来处理应用程序的请求。在后端文件中,使用self.logger为每个处理器实例设置logger配置(显示在backend.py文件中)

app.py

from bottle import Bottle
import logging.handlers
from backend import Processor

logger = logging.getLogger()
logger.setLevel(logging.DEBUG)

# Logging handler for files
file_handler = logging.handlers.TimedRotatingFileHandler("log.log", when="midnight", interval=1,
                                                         backupCount=10000)
file_handler.setLevel(logging.INFO)

# Logging handler for console
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)

# Formatter's for logging
formatter = logging.Formatter('%(asctime)s %(name)s %(levelname)s %(message)s')
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)

# Add handlers to the logger
logger.addHandler(file_handler)
logger.addHandler(console_handler)


class App:

    def __init__(self, host, port, server):
        logger.info("Initializing the app")
        self.processor = Processor()
        self._app = Bottle()
        self._host = host
        self._port = port
        self._server = server

    def _route(self):
        self._app.route('/hello/<attribute>/<number>', method="POST", callback=self.get_output)

    def start(self):
        self._app.run(server=self._server, host=self._host, port=self._port)  ## Starts the service
        logger.info("Web service started.")

    def get_output(self, attribute, number):
        logger.info("Got the input attribute {}".format(attribute))
        result = self.processor.compute(attribute, number)
        return result


if __name__ == '__main__':
    server = App(server='waitress', host='0.0.0.0', port=8080)
    server.start()

backend.py

 import logging


class Processor:

    def __init__(self):
        self.logger = logging.getLogger(__name__)  # Setting the logging config
        self.attribute = None  ############ Setting this variable to None for the instance

    def set_attributes(self, input_attribute):
        self.attribute = input_attribute  ############### Setter to set the attribute

    def compute(self, attribute, number):
        self.set_attributes(attribute)
        self.logger.info("Completed processing the attribute {}".format(self.attribute))
        res = number + 5
        return res

问题是,只要有多次调用此app.py文件,记录器都会选择存储在共享内存中的先前请求参数(它选择Blue表示Green ...等)。

我重新创建了日志记录语句,如下所示

2019-12-23 15:15:46,992 yoshi INFO Web service started.
Bottle v0.13-dev server starting up (using WaitressServer())...
Listening on http://0.0.0.0:8090/
Hit Ctrl-C to quit.

Serving on http://0.0.0.0:8090

line1: 2019-12-23 15:15:47,327 app.py INFO Got the input attribute Green
line2: 2019-12-23 15:15:47,327 app.py INFO Got the input attribute Blue
line3: 2019-12-23 15:15:47,327 backend.py INFO Completed processing the attribute Green
line4: 2019-12-23 15:15:47,327 app.py INFO Got the input attribute Black
line5: 2019-12-23 15:15:47,327 backend.py INFO Completed processing the attribute Green <<<-----This needs to be Blue, but it is Green again (Is it because self.attribute = None)
line6: 2019-12-23 15:15:47,327 backend.py INFO Completed processing the attribute Black
line7: 2019-12-23 15:15:47,327 backend.py INFO Completed processing the attribute None <<<-----This needs to be Violet, but it is None again (Is it because self.attribute = None)
line8: 2019-12-23 15:15:47,327 app.py INFO Got the input attribute Violet

总共我对上述应用程序进行了4次调用,同时调用了属性Green,Blue,Black,Violet

题:

我的记录器在第5行和第7行中失败的原因是什么?使用setter方法将输入参数设置为整​​个对象的正确方法吗? (如果没有,如何将输入属性设置为一个全新的模块)

是因为self.attribute使用了共享内存吗?如何解决呢?

寻找答案以创建可在我的应用程序的所有模块中使用的日志记录配置。我需要在日志消息中使用请求参数的地方,并且记录器配置不会因对应用程序的多次输入调用而失败

参考方案

我认为您可能想使用线程本地存储来保留属性。对代码进行一些修改:

app.py

import logging.handlers
import threading

from bottle import Bottle

from backend import Processor
from storage import storage

logger = logging.getLogger()
logger.setLevel(logging.DEBUG)

# Logging handler for files
file_handler = logging.handlers.TimedRotatingFileHandler("log.log", when="midnight", interval=1,
                                                         backupCount=10000)
file_handler.setLevel(logging.INFO)

# Logging handler for console
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)

# Formatter's for logging
formatter = logging.Formatter('%(asctime)s %(name)s %(levelname)s %(message)s')
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)

# Add handlers to the logger
logger.addHandler(file_handler)
logger.addHandler(console_handler)


class App:

    def __init__(self, host, port, server):
        logger.info("Initializing the app")
        self.processor = Processor()
        self._app = Bottle()
        self._host = host
        self._port = port
        self._server = server
        self._app.route('/hello/<attribute>/<number>', method="POST", callback=self.get_output)

    def start(self):
        self._app.run(server=self._server, host=self._host, port=self._port)  ## Starts the service
        logger.info("Web service started.")

    def get_output(self, attribute, number):
        logger.info("Got the input attribute %s", attribute)
        local_storage = storage()
        local_storage.attribute = attribute
        self.processor.compute()
        return f"done for {attribute}"


if __name__ == '__main__':
    server = App(server='waitress', host='0.0.0.0', port=8081)
    server.start()

backend.py

import logging
import threading

from more_backend import do_work
from storage import storage


class Processor:

    def __init__(self):
        self.logger = logging.getLogger(__name__)  # Setting the logging config

    def compute(self):
        local_storage = storage()
        do_work()
        self.logger.info("Completed processing the attribute %s", local_storage.attribute)

more_backend.py

import logging
import threading
import time
import random

from storage import storage

def do_work():
    local_storage = storage()
    logger = logging.getLogger(__name__)
    logger.info("Doing work with attribute %s", local_storage.attribute)
    time.sleep(random.random())

storage.py

from functools import lru_cache
import threading

@lru_cache()
def storage():
    return threading.local()

我认为它将满足您的要求:每个请求中的attribute将可用于处理该请求的所有功能,而无需手动传递它,并且在线程之间没有竞争条件。

Python:传递记录器是个好主意吗? - python

我的Web服务器的API日志如下:started started succeeded failed 那是同时收到的两个请求。很难说哪一个成功或失败。为了彼此分离请求,我为每个请求创建了一个随机数,并将其用作记录器的名称logger = logging.getLogger(random_number) 日志变成[111] started [222] start…

Python GPU资源利用 - python

我有一个Python脚本在某些深度学习模型上运行推理。有什么办法可以找出GPU资源的利用率水平?例如,使用着色器,float16乘法器等。我似乎在网上找不到太多有关这些GPU资源的文档。谢谢! 参考方案 您可以尝试在像Renderdoc这样的GPU分析器中运行pyxthon应用程序。它将分析您的跑步情况。您将能够获得有关已使用资源,已用缓冲区,不同渲染状态上…

Python sqlite3数据库已锁定 - python

我在Windows上使用Python 3和sqlite3。我正在开发一个使用数据库存储联系人的小型应用程序。我注意到,如果应用程序被强制关闭(通过错误或通过任务管理器结束),则会收到sqlite3错误(sqlite3.OperationalError:数据库已锁定)。我想这是因为在应用程序关闭之前,我没有正确关闭数据库连接。我已经试过了: connectio…

Python exchangelib在子文件夹中读取邮件 - python

我想从Outlook邮箱的子文件夹中读取邮件。Inbox ├──myfolder 我可以使用account.inbox.all()阅读收件箱,但我想阅读myfolder中的邮件我尝试了此页面folder部分中的内容,但无法正确完成https://pypi.python.org/pypi/exchangelib/ 参考方案 您需要首先掌握Folder的myfo…

python:ConfigParser对象,然后再阅读一次 - python

场景:我有一个配置文件,其中包含要执行的自动化测试的列表。这些测试是长期循环执行的。   配置文件的设计方式使ConfigParser可以读取它。由于有两个三个参数,因此我需要通过每个测试。现在,此配置文件由script(s1)调用,并且按照配置文件中的列表执行测试。Script(s1)第一次读取配置,并且在每次测试完成后都会执行。阅读两次的要求:由于可能会…