Skip to content

Commit 4db1b43

Browse files
committed
add pyhton logger code
1 parent 2018a82 commit 4db1b43

5 files changed

Lines changed: 66 additions & 1 deletion

File tree

backend/app/logging_config.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import logging
2+
import sys
3+
4+
5+
def setup_logging() -> None:
6+
handler = logging.StreamHandler(sys.stdout)
7+
handler.setFormatter(logging.Formatter(
8+
"%(asctime)s %(levelname)s [%(name)s] %(message)s",
9+
datefmt="%Y-%m-%d %H:%M:%S",
10+
))
11+
12+
root = logging.getLogger()
13+
root.setLevel(logging.INFO)
14+
root.handlers = [handler]
15+
16+
# Quiet down noisy third-party loggers
17+
logging.getLogger("httpx").setLevel(logging.WARNING)

backend/app/main.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22
from fastapi import FastAPI
33
from fastapi.middleware.cors import CORSMiddleware
44
from app.config import settings
5+
from app.logging_config import setup_logging
56
from app.utils.qdrant_service import get_qdrant_service
67
from app.routers.chat import router as chat_router
78
from app.routers.documents import router as documents_router
89

10+
setup_logging()
11+
912

1013
@asynccontextmanager
1114
async def lifespan(app: FastAPI):

backend/app/routers/chat.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import logging
12
from fastapi import APIRouter, HTTPException
23
from app.schemas import ChatRequest, ChatResponse, DocumentRead
34
from app.utils.rag import retrieve_relevant_documents, ask_gemini, ask_gemini_with_grounding, is_audit_related
45

6+
logger = logging.getLogger(__name__)
57
router = APIRouter()
68

79
CONFIDENCE_THRESHOLD = 0.65
@@ -17,19 +19,28 @@ async def chat(request: ChatRequest):
1719
if not request.question.strip():
1820
raise HTTPException(status_code=400, detail="Question cannot be empty.")
1921

22+
logger.info("Question received: %r", request.question)
23+
2024
if not await is_audit_related(request.question):
25+
logger.info("Rejected as non-audit-related")
2126
return ChatResponse(answer=NON_AUDIT_RESPONSE, sources=[])
2227

2328
try:
2429
relevant = await retrieve_relevant_documents(request.question, top_k=8)
2530
except Exception as exc:
31+
logger.error("Vector search failed: %s", exc)
2632
raise HTTPException(status_code=502, detail=f"Vector search failed: {exc}")
2733

34+
top_score = max((doc.score for doc in relevant), default=0.0)
35+
logger.info("Retrieved %d docs, top score=%.3f", len(relevant), top_score)
36+
2837
if _is_confident(relevant):
38+
logger.info("Confidence threshold met — answering from Qdrant context")
2939
try:
3040
snippets = [f"Title: {doc.title}\nContent: {doc.content}" for doc in relevant]
3141
answer = await ask_gemini(request.question, snippets)
3242
except RuntimeError as exc:
43+
logger.error("Gemini chat failed: %s", exc)
3344
raise HTTPException(status_code=502, detail=f"LLM request failed: {exc}")
3445

3546
return ChatResponse(
@@ -40,9 +51,11 @@ async def chat(request: ChatRequest):
4051
],
4152
)
4253

54+
logger.info("Confidence threshold not met — falling back to Gemini web grounding")
4355
try:
4456
answer = await ask_gemini_with_grounding(request.question)
4557
except RuntimeError as exc:
58+
logger.error("Gemini grounding failed: %s", exc)
4659
raise HTTPException(status_code=502, detail=f"LLM request failed: {exc}")
4760

4861
return ChatResponse(answer=answer, sources=[])

backend/app/utils/rag.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import asyncio
22
import json
3+
import logging
34
from typing import List
45
import httpx
56
from app.config import settings
67
from app.utils.qdrant_service import get_qdrant_service
78

9+
logger = logging.getLogger(__name__)
10+
811

912
def _build_headers(endpoint: str) -> dict:
1013
headers = {"Content-Type": "application/json"}
@@ -127,7 +130,8 @@ async def _do_request(c: httpx.AsyncClient) -> bool:
127130
return await _do_request(client)
128131
async with httpx.AsyncClient(timeout=30.0) as owned_client:
129132
return await _do_request(owned_client)
130-
except Exception:
133+
except Exception as exc:
134+
logger.warning("is_audit_related classification failed, failing open (allowing question): %s", exc)
131135
return True # fail open — don't block users if classification itself fails
132136

133137

ec2-logs.sh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/bin/bash
2+
# Quick access to EC2 application logs.
3+
#
4+
# Usage:
5+
# ./ec2-logs.sh # last 50 lines, all services
6+
# ./ec2-logs.sh backend # last 50 lines, backend only
7+
# ./ec2-logs.sh backend -f # follow backend logs live
8+
# ./ec2-logs.sh -f # follow all services live
9+
10+
KEY_PATH="$(dirname "$0")/RAG_KEY_PAIR.pem"
11+
12+
13+
SERVICE=""
14+
FOLLOW_FLAG=""
15+
16+
for arg in "$@"; do
17+
if [ "$arg" = "-f" ] || [ "$arg" = "--follow" ]; then
18+
FOLLOW_FLAG="-f"
19+
else
20+
SERVICE="$arg"
21+
fi
22+
done
23+
24+
if [ -n "$FOLLOW_FLAG" ]; then
25+
ssh -i "$KEY_PATH" "$EC2_HOST" "cd ~/RAG && docker compose logs -f $SERVICE"
26+
else
27+
ssh -i "$KEY_PATH" "$EC2_HOST" "cd ~/RAG && docker compose logs --tail=50 $SERVICE"
28+
fi

0 commit comments

Comments
 (0)