Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions Assignment 12/api/logging_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import structlog
import logging

Check failure on line 2 in Assignment 12/api/logging_config.py

View workflow job for this annotation

GitHub Actions / Lint (ruff)

Ruff (F401)

Assignment 12/api/logging_config.py:2:8: F401 `logging` imported but unused
import sys

def configure_logging():
"""Configure structlog for JSON output to stdout."""

structlog.configure(
processors=[
structlog.stdlib.add_log_level,
structlog.stdlib.add_logger_name,
structlog.processors.TimeStamper(fmt="iso"),
structlog.processors.StackInfoRenderer(),
structlog.processors.format_exc_info,
structlog.processors.JSONRenderer(),
],
wrapper_class=structlog.stdlib.BoundLogger,
context_class=dict,
logger_factory=structlog.PrintLoggerFactory(file=sys.stdout),
)

def get_logger(name: str = __name__):
return structlog.get_logger(name)

Check failure on line 23 in Assignment 12/api/logging_config.py

View workflow job for this annotation

GitHub Actions / Lint (ruff)

Ruff (W292)

Assignment 12/api/logging_config.py:23:38: W292 No newline at end of file
15 changes: 15 additions & 0 deletions Assignment 12/handlers/routes/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
BusinessRuleViolationError,
InvalidStateTransitionError,
)
from api.logging_config import get_logger

logger = get_logger("sentinelpay.transactions")

router = APIRouter(prefix="/api/transactions", tags=["Transactions"])

Expand All @@ -51,6 +54,7 @@ def _handle_service_errors(exc: Exception) -> HTTPException:
return HTTPException(status_code=422, detail=str(exc))
if isinstance(exc, InvalidStateTransitionError):
return HTTPException(status_code=409, detail=str(exc))
logger.error("unhandled_error", error=str(exc), exc_info=True)
return HTTPException(status_code=500, detail=f"Internal error: {exc}")


Expand Down Expand Up @@ -91,6 +95,12 @@ def submit_transaction(
longitude=body.longitude,
is_international=body.is_international,
)
logger.info(
"transaction_submitted",
transaction_id=str(txn.transaction_id),
amount=body.amount,
currency=body.currency,
)
# ── Increment metrics ──
transactions_total.labels(channel=body.channel).inc()

Expand Down Expand Up @@ -182,6 +192,11 @@ def apply_decision(
model_scores=[s.model_dump() for s in body.model_scores],
account_tier=body.account_tier,
)
logger.info(
"fraud_decision_applied",
transaction_id=transaction_id,
fraud_score=body.fraud_score,
)
return TransactionResponse.from_domain(txn)
except Exception as e:
raise _handle_service_errors(e)
Expand Down
Loading