Skip to content

How best to implement a Logging Adapter? #140

Closed

Description

@StephenBrown2

I see that adapters were added, debated, and then removed for simplicities sake, but I'd like to set up a logging adapter like is possible by subclassing requests.adapters.HTTPAdapter like so:

class LoggingHTTPAdapter(requests.adapters.HTTPAdapter):
    """Adapter to log request and response."""

    def send(self, request, *args, **kwargs):
        sensitive_params = conf.SENSITIVE_PARAMS

        # transaction ID to identify the logs.
        trans_id = util.generate_uuid()

        headers = util.filter_sensitive_information(
            request.headers, sensitive_params
        )

        log.info(f"<{trans_id}> Request: {request.method} {request.url}")
        log.info(f"<{trans_id}> Request headers: {headers}")
        log.info(f"<{trans_id}> Request body: {request.body}")

        resp = super().send(request, *args, **kwargs)

        headers = util.filter_sensitive_information(
            resp.headers, sensitive_params
        )

        log.info(f"<{trans_id}> Response: {resp.status_code} {resp.reason}")
        log.info(f"<{trans_id}> Response headers: {headers}")
        log.info(f"<{trans_id}> Response body: {resp.content}")

        # Store the transaction ID in the response object, so that it can be
        # added to the logs from test cases.
        resp.__dict__["transaction_id"] = trans_id

        return resp


def mount_adapter(session):
    # currently we only have TimeoutHTTPAdapter and LoggingHTTPAdapter,
    # when we add more in the future, we can use this function to mount
    # our adapters.
    adapters = [LoggingHTTPAdapter()]
    for adapter in adapters:
        session.mount("http://", adapter)
        session.mount("https://", adapter)

With httpx, would I need to wrap/subclass a Dispatcher or Client class instead?

Activity

  1. lovelydinosaur commented on Jul 24, 2019

    @lovelydinosaur
    Member

    The Dispatcher interface is a very close equivalent to the Adapter interface.

    You could achieve the same usage you’ve given an example of by subclassing the default Dispatch implementation (ConnectionPool), and passing it to the client with dispatch=.

    That’d be equivalent to how this example subclasses HTTPAdapter, and uses mount to add it to the client.

  2. StephenBrown2 commented on Jul 24, 2019

    @StephenBrown2
    ContributorAuthor

    Excellent. I'll give that a shot tomorrow. Thanks!

  3. sethmlarson commented on Jul 28, 2019

    @sethmlarson
    Contributor

    This issue is no longer needed it seems? Reopen if I'm wrong here :)

  4. StephenBrown2 commented on Jul 28, 2019

    @StephenBrown2
    ContributorAuthor

    Yup, the custom Dispatcher worked for me, was going to update on Monday once I had a bit more testing done. Good to close 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions