如何为 Python 日志记录设置 HTTPHandler

saz*_*saz 11 python logging httphandler python-3.x python-requests

我正在尝试使用标准 python 日志库的 HTTPHandler 类来发送日志。我需要使用基本凭据(用户名和密码)发出 https 发布请求。这就是我如何设置 HTTPHandler-

    host = 'example.com'
    url = '/path'
    handler = logging.handlers.HTTPHandler(host, url, method='POST', secure=True, credentials=('username','password'), context=None)
    logger.addHandler(handler)
Run Code Online (Sandbox Code Playgroud)

但问题是,我的远程服务器中没有任何日志。我什至没有看到处理程序有任何异常。我是否错误地设置了处理程序参数?我可以使用简单的 pythong http 请求发送类似的日志-

url = 'https://username:password@example.com/path'
headers = {'content-type': 'application/json'}
jsonLog = { 'id': '4444','level': 'info', 'message': 'python log' };

r = requests.post(url, data = json.dumps(jsonLog), headers=headers)
Run Code Online (Sandbox Code Playgroud)

由于 json 内容类型,我是否需要以某种方式设置标题?如果是,那么我如何在 httphandler 中设置它?

更新

我想我应该更新我最终做的事情。经过多次搜索,我发现我可以通过覆盖 logging.Handler 的 emit() 来创建自定义处理程序。

class CustomHandler(logging.Handler):
def emit(self, record):
    log_entry = self.format(record)
    # some code....
    url = 'url'
    # some code....
    return requests.post(url, log_entry, headers={"Content-type": "application/json"}).content
Run Code Online (Sandbox Code Playgroud)

如果有更好的建议欢迎留言。

Ist*_*van 9

扩展给出的解决方案saz,以下是如何添加自定义 HTTP 处理程序,该处理程序将使用不记名令牌将发出的日志转发到指定的 URL。

它使用请求会话,而不必为每个日志事件建立一个新会话。

此外,如果请求失败,它会尝试重新发送日志并进行给定的重试次数。

注意:确保您的日志记录处理程序尽可能简单,以防止应用程序因日志事件而停止。

我用一个简单的localhost回显服务器测试了它,它可以工作。

请随意提出任何更改建议。

import json
import logging
import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry

class CustomHttpHandler(logging.Handler):
    def __init__(self, url: str, token: str, silent: bool = True):
        '''
        Initializes the custom http handler
        Parameters:
            url (str): The URL that the logs will be sent to
            token (str): The Authorization token being used
            silent (bool): If False the http response and logs will be sent 
                           to STDOUT for debug
        '''
        self.url = url
        self.token = token
        self.silent = silent

        # sets up a session with the server
        self.MAX_POOLSIZE = 100
        self.session = session = requests.Session()
        session.headers.update({
            'Content-Type': 'application/json',
            'Authorization': 'Bearer %s' % (self.token)
        })
        self.session.mount('https://', HTTPAdapter(
            max_retries=Retry(
                total=5,
                backoff_factor=0.5,
                status_forcelist=[403, 500]
            ),
            pool_connections=self.MAX_POOLSIZE,
            pool_maxsize=self.MAX_POOLSIZE
        ))

        super().__init__()

    def emit(self, record):
        '''
        This function gets called when a log event gets emitted. It recieves a
        record, formats it and sends it to the url
        Parameters:
            record: a log record
        '''
        logEntry = self.format(record)
        response = self.session.post(self.url, data=logEntry)

        if not self.silent:
            print(logEntry)
            print(response.content)

# create logger
log = logging.getLogger('')
log.setLevel(logging.INFO)

# create formatter - this formats the log messages accordingly
formatter = logging.Formatter(json.dumps({
    'time': '%(asctime)s',
    'pathname': '%(pathname)s',
    'line': '%(lineno)d',
    'logLevel': '%(levelname)s',
    'message': '%(message)s'
}))

# create a custom http logger handler
httpHandler = CustomHttpHandler(
    url='<YOUR_URL>',
    token='<YOUR_TOKEN>',
    silent=False
)

httpHandler.setLevel(logging.INFO)

# add formatter to custom http handler
httpHandler.setFormatter(formatter)

# add handler to logger
log.addHandler(httpHandler)

log.info('Hello world!')
Run Code Online (Sandbox Code Playgroud)


Vin*_*jip 6

您将需要子类化HTTPHandler并覆盖该emit()方法以执行您需要的操作。您可以使用 的当前实现HTTPHandler.emit()作为指南。