@@ -56,6 +56,20 @@ def filter(self, record: logging.LogRecord) -> bool:
5656
5757
5858class GAERequestLogger :
59+ """
60+ A logger for emitting structured request logs in Google App Engine.
61+
62+ This logger is designed to work with FastAPI applications deployed on Google App Engine. It logs
63+ structured data after each request is handled, including the HTTP request method, URL, status,
64+ user agent, response size, latency, and remote IP address. The log severity is determined by the
65+ maximum log level recorded during the request.
66+
67+ Attributes:
68+ LOG_LEVEL_TO_SEVERITY (Dict[int, str]): Mapping of Python logging levels to Cloud Logging severity levels.
69+ logger (Logger): The Google Cloud Logger instance to log requests.
70+ resource (Resource): The Google Cloud resource associated with the logger.
71+ log_payload (bool): Whether to log the request payload for certain HTTP methods. Defaults to True.
72+ """
5973 LOG_LEVEL_TO_SEVERITY : Dict [int , str ] = {
6074 logging .NOTSET : 'DEFAULT' ,
6175 logging .DEBUG : 'DEBUG' ,
@@ -72,6 +86,7 @@ def __init__(self, logger: Logger, resource: Resource, log_payload: bool = True)
7286 Args:
7387 logger (Logger): The Google Cloud Logger instance to log requests.
7488 resource (Resource): The resource associated with the logger.
89+ log_payload (bool): Whether to log the request payload for certain HTTP methods. Defaults to True.
7590 """
7691 self .logger = logger
7792 self .resource = resource
@@ -143,15 +158,41 @@ async def emit_request_log(self, request: Request, response: Response) -> None:
143158
144159class FastAPIGAELoggingMiddleware :
145160 """
146- Custom middleware to set up request start time and emit logs after request completion.
147- Specifically designed for FastAPI applications deployed on Google App Engine.
161+ Middleware to set up request start time and emit logs after request completion.
162+
163+ This middleware is specifically designed for FastAPI applications deployed on Google App Engine.
164+ It records the start time of the request and then emits a log after the request is completed,
165+ containing details about the request and response.
166+
167+ Attributes:
168+ app (ASGIApp): The ASGI application instance.
169+ logger (GAERequestLogger): The logger used to emit structured logs.
148170 """
149171
150172 def __init__ (self , app : ASGIApp , logger : GAERequestLogger ):
173+ """
174+ Initialize the middleware.
175+
176+ Args:
177+ app (ASGIApp): The ASGI application instance.
178+ logger (GAERequestLogger): The logger instance used to log request data.
179+ """
151180 self .app = app
152181 self .logger = logger
153182
154183 async def __call__ (self , scope : Scope , receive : Receive , send : Send ):
184+ """
185+ Middleware entry point, invoked for each request.
186+
187+ This method sets up the request context with trace information, start time, and initial log level.
188+ It then intercepts the response to capture details for logging. In case of exceptions, they are
189+ logged, and the exception is re-raised.
190+
191+ Args:
192+ scope (Scope): The ASGI scope dictionary containing request information.
193+ receive (Receive): The receive channel for incoming messages.
194+ send (Send): The send channel for outgoing messages.
195+ """
155196 if scope ["type" ] == "http" :
156197
157198 # https://stackoverflow.com/questions/64115628/get-starlette-request-body-in-the-middleware-context
@@ -171,10 +212,10 @@ async def receive_cached():
171212 'max_log_level' : logging .NOTSET
172213 })
173214
174- # start with the default response in case of generic error
215+ # Default response in case of an error
175216 response = Response (status_code = 500 )
176217
177- # intercept the sent message to get the response status and body
218+ # Intercept the sent message to get the response status and body
178219 # for later use
179220 async def send_spoof_wrapper (message : Dict [str , Any ]) -> None :
180221 if message ["type" ] == "http.response.start" :
@@ -195,9 +236,11 @@ async def send_spoof_wrapper(message: Dict[str, Any]) -> None:
195236
196237class FastAPIGAELoggingHandler (CloudLoggingHandler ):
197238 """
198- Custom Cloud Logging handler for FastAPI applications deployed in Google App Engine.
199- Groups logs coming from the same request lifecycle and propagates the maximum log level
200- throughout the request lifecycle using middleware and context management.
239+ Custom Cloud Logging handler for FastAPI applications deployed on Google App Engine.
240+
241+ This handler groups logs from the same request lifecycle and propagates the maximum log level
242+ observed throughout the request. It also integrates with FastAPI by adding middleware that
243+ handles request and response logging.
201244 """
202245
203246 REQUEST_LOGGER_SUFFIX : str = '-request-logger'
@@ -216,9 +259,7 @@ def __init__(
216259 app (FastAPI): The FastAPI application instance.
217260 request_logger_name (Optional[str]): The name of the Cloud Logging logger to use for request logs.
218261 Defaults to the Google Cloud Project ID with '-request-logger' suffix.
219- log_payload (bool): Whether to log the request payload. If True, the payload for
220- POST, PUT, PATCH, and DELETE requests will be logged.
221- Defaults to True.
262+ log_payload (bool): Whether to log the request payload for certain HTTP methods. Defaults to True.
222263 *args: Additional arguments to pass to the superclass constructor.
223264 Any argument you would pass to CloudLoggingHandler.
224265 **kwargs: Additional keyword arguments to pass to the superclass constructor.
0 commit comments