ecs-logging-python icon indicating copy to clipboard operation
ecs-logging-python copied to clipboard

Cache and expose extractors

Open nuno-andre opened this issue 8 months ago • 0 comments

This PR caches and exposes the extractors dict for two purposes:

  • Loads the dict only during initialization, instead of on every logger invocation.
  • Provides a clearer and more scalable way to subclass StdlibFormatter.

This is an adapted use case from the library we use for several services in our company that adds information about errors in HTTP requests :

from typing import TYPE_CHECKING
from functools import lru_cache

from ecs_logging import StdlibFormatter
import httpx

if TYPE_CHECKING:
    from logging import LogRecord


httpx._utils.SENSITIVE_HEADERS.update({
    'apikey', 'api-key', 'x-api-key', 'x-auth-token',
})


class EcsFormatter(StdlibFormatter):

    @property
    @lru_cache
    def extractors(self):
        extractors = super().extractors
        extractors['http'] = self._extract_httpx_response
        return extractors

    def _extract_httpx_response(self, record: 'LogRecord') -> dict | None:
        if not record.exc_info or not isinstance(record.exc_info[1], httpx.HTTPStatusError):
            return None

        resp = record.exc_info[1].response

        redact = lambda x: dict(httpx._utils.obfuscate_sensitive_headers(x.multi_items()))

        if (url := resp.request.url).password:
            url = str(url).replace(f':{url.password}@', ':[secure]@')

        return {
            'version':          resp.http_version,
            'request':  {
                'method':       resp.request.method,
                'url':          str(url),
                'headers':      redact(resp.request.headers),
                'body.content': resp.request.content,
            },
            'response': {
                'status_code':  resp.status_code,
                'headers':      redact(resp.headers),
                'body.content': resp.content,
            }
        }

Additionally, this PR also:

nuno-andre avatar Feb 15 '25 13:02 nuno-andre