簡體   English   中英

登錄異步函數時如何使用 request_id?

[英]How to use request_id while logging in asynchronous functions?

在異步函數中,每個 logger 語句都有自己的 request_id。

import logging
log = logging.getLogger('test_logger')

def sync_fun():
    log.info("test 1")
    log.info("test 2")
    log.info("test 3")

@after_response.enable
def async_fun():
    log.info("test 1")
    log.info("test 2")
    log.info("test 3")    

output of sync_fun:
[06/Nov/2019 10:42:00.234] [None] [130C6C47F1E24164AAC0440C719630] [INFO] Test 1
[06/Nov/2019 10:42:00.234] [None] [130C6C47F1E24164AAC0440C719630] [INFO] Test 2
[06/Nov/2019 10:42:00.234] [None] [130C6C47F1E24164AAC0440C719630] [INFO] Test 3

130C6C47F1E24164AAC0440C719630 是一個 request_id,它對所有記錄器語句都很常見。

output of async_fun:
[06/Nov/2019 10:42:00.234] [None] [AB352B8F2DF9459ABDD2FBF51EB05F] [INFO] Test 1
[06/Nov/2019 10:42:00.234] [None] [V9E9B6DF5F9C442195EA7C1379FBFA] [INFO] Test 2
[06/Nov/2019 10:42:00.234] [None] [DCA311A92724443C9AD7E951288917] [INFO] Test 3

async_fun 是一個異步 function 並且所有記錄器語句的請求 ID 都不同。

我如何為異步 function 中的每個記錄器語句獲取相同的 request_id。

我創建了日志過濾器。 我在這里生成request_id。 記錄時使用相同的請求 ID。

from threading import local
_thread_locals = local()

class LoggingMiddleware(object):
    def process_request(self, request):
        if request.user.username:
            _thread_locals.user = request.user.username
            _thread_locals.user_email = request.user.email
            _thread_locals.user_id = request.user.id
        #assign request id to all requests (to track cron requests also)
        _thread_locals.request_id = str(uuid.uuid4().get_hex().upper()[0:30])


    def process_response(self, request, response):
        if hasattr(_thread_locals, 'user'):
            del _thread_locals.user
        if hasattr(_thread_locals, 'request_id'):
            del _thread_locals.request_id
        if hasattr(_thread_locals, 'user_email'):
            del _thread_locals.user_email
        if hasattr(_thread_locals, 'user_id'):
            del _thread_locals.user_id
        return response

    def process_exception(self, request, exception):
        logger.exception('unhandled error - ')

def get_current_user_details():
    user_details = {
        'username': getattr(_thread_locals, 'user', None),
        'email' : getattr(_thread_locals, 'user_email', None),
        'id' : getattr(_thread_locals, 'user_id', None)
    }
    return user_details

def get_current_user():
    return getattr(_thread_locals, 'user', None)

def get_current_request_id():
    return getattr(_thread_locals, 'request_id', None)

class RequestIDFilter(logging.Filter):
    def filter(self, record):
        current_user = get_current_user()
        current_request_id = get_current_request_id()
        record.user = current_user if current_user else None
        record.request_id = current_request_id if current_request_id else str(uuid.uuid4().get_hex().upper()[0:30])
        return True

您可以使用singleton 模式,它將提供 class 的單個實例。

代碼:

import logging

#Implement Singleton Pattern For Logger
class loggerSingleton(object):
   def __new__(myClass):
       if not hasattr(myClass, 'instance'):
           myClass.instance = super(loggerSingleton, myClass).__new__(myClass)
           myClass.instance.log = logging.getLogger('test_logger')
       return myClass.instance

#Let's try to create two instances      
singletonLog1 = loggerSingleton()
singletonLog2 = loggerSingleton()

#Let's check if we have single instances
print(singletonLog1.log is singletonLog2.log)

#print the logger ID's from two initializations
print(singletonLog1.log)
print(singletonLog2.log)

Output:

> True
> <logging.Logger object at 0x7f8995fcb6d8>
> <logging.Logger object at 0x7f8995fcb6d8>

大多數情況下,包括像你這樣的奇點,我更喜歡使用 Singleton 模式。

假設您正在使用:

您可以修補after_response以傳遞並設置local.request_id

import after_response
from after_response import AFTER_RESPONSE_IMMEDIATE
from after_response.signals import function_queue, logger
from log_request_id import local


def patch():
    after_response.enable = _enable
    after_response.signals.run = _run


def _enable(func):
    def _after_response(*args, **kwargs):
        if AFTER_RESPONSE_IMMEDIATE:
            func(*args, **kwargs)
        else:
            args = (local.request_id,) + args  # Pass request_id
            function_queue.append((func, args, kwargs))
    func.after_response = _after_response
    return func


def _run(func, request_id, *args, **kwargs):
    try:
        local.request_id = request_id  # Set request_id
        func(*args, **kwargs)
    except Exception as e:
        logger.exception(str(e))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM