Claude Code Claude Opus 4.6 commited on
Commit
ce4bc03
·
1 Parent(s): 79d6a8b

Claude Code: Add request logging middleware and STARTUP_MODE support

Browse files

- Add middleware to log all requests and exceptions to logs/runtime.log
- Create logs/ directory automatically if it doesn't exist
- Pass STARTUP_MODE from entrypoint.sh (default: minimal)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Files changed (2) hide show
  1. app.py +48 -0
  2. entrypoint.sh +1 -0
app.py CHANGED
@@ -1,11 +1,59 @@
 
 
1
  from fastapi import FastAPI, Request
2
  from datetime import datetime
3
  from fastapi.responses import JSONResponse
4
  from pydantic import BaseModel
5
  from typing import Optional
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
 
7
  app = FastAPI()
8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  # In-memory worker state tracking
10
  _worker_state = {
11
  "worker_pid": None,
 
1
+ import os
2
+ import logging
3
  from fastapi import FastAPI, Request
4
  from datetime import datetime
5
  from fastapi.responses import JSONResponse
6
  from pydantic import BaseModel
7
  from typing import Optional
8
+ from fastapi.responses import PlainTextResponse
9
+ from fastapi.exceptions import RequestValidationError
10
+ from starlette.exceptions import HTTPException as StarletteHTTPException
11
+
12
+ # Ensure logs directory exists
13
+ os.makedirs("logs", exist_ok=True)
14
+
15
+ # Configure logging
16
+ logging.basicConfig(
17
+ level=logging.INFO,
18
+ format='%(asctime)s - %(levelname)s - %(message)s',
19
+ handlers=[
20
+ logging.FileHandler('logs/runtime.log'),
21
+ logging.StreamHandler()
22
+ ]
23
+ )
24
+ logger = logging.getLogger(__name__)
25
+
26
+ STARTUP_MODE = os.environ.get("STARTUP_MODE", "minimal")
27
 
28
  app = FastAPI()
29
 
30
+
31
+ @app.middleware("http")
32
+ async def log_requests(request: Request, call_next):
33
+ """Log all incoming requests and responses."""
34
+ start_time = datetime.utcnow()
35
+ logger.info(f"Request: {request.method} {request.url.path}")
36
+
37
+ try:
38
+ response = await call_next(request)
39
+ duration = (datetime.utcnow() - start_time).total_seconds()
40
+ logger.info(f"Response: {response.status_code} - {duration:.3f}s")
41
+ return response
42
+ except Exception as e:
43
+ duration = (datetime.utcnow() - start_time).total_seconds()
44
+ logger.error(f"Request failed after {duration:.3f}s: {str(e)}")
45
+ raise
46
+
47
+
48
+ @app.exception_handler(Exception)
49
+ async def global_exception_handler(request: Request, exc: Exception):
50
+ """Log all unhandled exceptions."""
51
+ logger.error(f"Unhandled exception on {request.url.path}: {type(exc).__name__}: {str(exc)}")
52
+ return JSONResponse(
53
+ status_code=500,
54
+ content={"error": "Internal server error", "detail": str(exc)}
55
+ )
56
+
57
  # In-memory worker state tracking
58
  _worker_state = {
59
  "worker_pid": None,
entrypoint.sh CHANGED
@@ -1,2 +1,3 @@
1
  #!/bin/bash
 
2
  exec uvicorn app:app --host 0.0.0.0 --port 7860
 
1
  #!/bin/bash
2
+ export STARTUP_MODE="${STARTUP_MODE:-minimal}"
3
  exec uvicorn app:app --host 0.0.0.0 --port 7860