import logging from functools import partial from typing import List, Optional from flask import Flask, Response, request from owslib.dictutil import exclude from owslib.logger.utils import get_status_code_log_level from owslib.urlpath import is_path_match logger = logging.getLogger(__name__) safe_headers = partial(exclude, keys=["authorization"]) class RequestLogger: LOG_MESSAGE = "{status} - {verb} {resource}" def __init__( self, exclude_paths: Optional[List[str]] = None, extra_headers: bool = False, ) -> None: self.exclude_paths = exclude_paths self.extra_headers = extra_headers def init_app(self, app: Flask) -> None: app.after_request(self.log_response) def log_response(self, response: Response) -> Response: if is_path_match(request.path, match=self.exclude_paths): return response level = get_status_code_log_level(response.status_code) extra = {} if self.extra_headers: extra.update( { "request.headers": safe_headers(dict(request.headers)), "response.headers": safe_headers(dict(response.headers)), } ) logger.log( level, self.LOG_MESSAGE.format( status=response.status_code, verb=request.method, resource=request.path, ), extra=extra, ) return response