当应用程序有多个调用时,日志记录配置无法加载 value-formatter()
Logging config fails to the load the value-formatter() when the application has multiple calls
我正在使用 Bottle wsgi 框架来创建 Web 服务。我在 app.py 中配置了记录器(如 app.py 所示),它接收应用程序调用并使用方法 get_output() 将输入参数传递给 backend.py。我正在使用 backend.py 来处理应用程序的请求。在后端文件中,记录器配置使用 self.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 文件时选择存储在共享内存中的先前请求参数(它选择蓝色代替绿色...等)。
我重新创建了日志语句,如下所示
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 次并行调用,同时调用了属性绿色、蓝色、黑色、紫色
问题:
我的记录器在第 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
来自每个请求的所有函数都可用于处理该请求的所有函数,无需手动传递,并且线程之间没有竞争条件。
我正在使用 Bottle wsgi 框架来创建 Web 服务。我在 app.py 中配置了记录器(如 app.py 所示),它接收应用程序调用并使用方法 get_output() 将输入参数传递给 backend.py。我正在使用 backend.py 来处理应用程序的请求。在后端文件中,记录器配置使用 self.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 文件时选择存储在共享内存中的先前请求参数(它选择蓝色代替绿色...等)。
我重新创建了日志语句,如下所示
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 次并行调用,同时调用了属性绿色、蓝色、黑色、紫色
问题:
我的记录器在第 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
来自每个请求的所有函数都可用于处理该请求的所有函数,无需手动传递,并且线程之间没有竞争条件。