【问题标题】:How to set up HTTPHandler for python logging如何为 python 日志设置 HTTPHandler
【发布时间】:2019-01-02 15:31:57
【问题描述】:

我正在尝试使用标准 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)

但问题是,我的远程服务器中没有任何日志。我什至没有看到处理程序有任何异常。我是否错误地设置了处理程序参数?我可以使用简单的 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)

由于 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

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

【问题讨论】:

  • HTTPHandler 不使用 JSON - 它以application/x-www-form-urlencoded 发送数据。因此,如果您的服务器期待 JSON,我预计它会失败。您是否在 Web 服务器的访问日志中看到了这些请求?
  • 是的,服务器期待 json。不幸的是,我无权访问服务器日志。有没有办法将内容类型更改为application/json?喜欢在处理程序中设置标题?

标签: python python-3.x logging python-requests httphandler


【解决方案1】:

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

它使用请求会话而不是必须在每个日志中建立一个新会话 事件。

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

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

我用一个简单的localhost echo 服务器对其进行了测试,它可以工作。

欢迎提出任何更改建议。

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!')

【讨论】:

    【解决方案2】:

    您需要继承 HTTPHandler 并覆盖 emit() 方法来完成您需要的操作。您可以使用HTTPHandler.emit() 的当前实现作为指导。

    【讨论】:

    • 是的,这就是我最终做的事情
    猜你喜欢
    • 2021-11-20
    • 2015-08-03
    • 2020-05-11
    • 2021-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多