Python logger:每个线程不同的日志记录属性

问题描述 投票:0回答:1

我的用例如下:我有一个处理请求的服务器,对于每个请求,我希望日志记录包含一个

user_id
。我希望团队中的其他开发人员能够尽可能无缝地使用它,这样他们就可以简单地导入
logging
并使用它,而无需传递 user_id 。 这是一个 MWE,但是,正如您所看到的,它并不总是有效:

import logging
import threading
import time

class ContextFilter(logging.Filter):
    def __init__(self, user_id: str):
        super().__init__()
        self.local = threading.local()
        self.local.user_id = user_id

    def filter(self, record):
        record.user_id = getattr(self.local, 'user_id', 'NoValue')
        return True  # Returning True ensures the log message is processed

# Set up logging
logger = logging.getLogger("my_logger")
logger.setLevel(logging.DEBUG)

# Add a handler
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(user_id)s - %(message)s')
handler = logging.StreamHandler()
handler.setFormatter(formatter)
logger.addHandler(handler)

# logger.info("This is a test message.")

def worker(user_id: str):
    logger.addFilter(ContextFilter(user_id=user_id))
    logger.info("message 1")
    time.sleep(0.5)
    logger.info("message 2")
    

t1 = threading.Thread(target=worker, args=("user1",))
t2 = threading.Thread(target=worker, args=("user2",))

t1.start()
t2.start()

t1.join()
t2.join()

这是输出:

2024-11-20 17:46:39,780 - INFO - user1 - message 1
2024-11-20 17:46:39,780 - INFO - user2 - message 1
2024-11-20 17:46:40,284 - INFO - NoValue - message 2
2024-11-20 17:46:40,285 - INFO - user2 - message 2

我在这里缺少什么?

python multithreading logging
1个回答
0
投票

两个线程都将过滤器安装到同一个记录器,并且两个过滤器都被调用,最后安装的过滤器将显示其值。

只需一个过滤器,并让每个线程修改该 id 的线程本地版本。 (虽然所有线程都读取和写入相同的

self.local
,但每个线程在读取或写入时会看到不同的属性,这就是线程本地的含义)

import logging

import threading
import time


class ContextFilter(logging.Filter):
    def __init__(self):
        super().__init__()
        self.local = threading.local()

    def set_id(self, user_id):
        self.local.user_id = user_id

    def filter(self, record):
        record.user_id = getattr(self.local, 'user_id', 'NoValue')
        return True  # Returning True ensures the log message is processed


# Set up logging
logger = logging.getLogger("my_logger")
logger.setLevel(logging.DEBUG)

# Add a handler
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(user_id)s - %(message)s')
handler = logging.StreamHandler()
handler.setFormatter(formatter)
logger.addHandler(handler)

global_filter = ContextFilter()
logger.addFilter(global_filter)

def worker(user_id: str):
    global_filter.set_id(user_id)
    logger.info("message 1")
    time.sleep(0.5)
    logger.info("message 2")


t1 = threading.Thread(target=worker, args=("user1",))
t2 = threading.Thread(target=worker, args=("user2",))

t1.start()
t2.start()

t1.join()
t2.join()
© www.soinside.com 2019 - 2024. All rights reserved.