Integrate LAWDE Shield with FastAPI, Flask, Django, or workers by posting the Sentinel JSON contract over HTTPS. Phase A is a test script; Phase B registers a global handler in your main app — built-in scrubbing still targets <50ms with 0 bytes durable source.
What does the Python integration do?
You POST scrubbed exception JSON to Sentinel from inside your running process. There is no background agent reading Python memory. AI fixes remain gated at Trust Score 0.70 after ACK.
Create test_ingest.py, run it, confirm a cluster on Overview. You may delete this file afterward. It does not attach to FastAPI/Flask/Django.
test_ingest.py
# File: test_ingest.py ← SMOKE TEST ONLY
# Run once: python test_ingest.py
# This does NOT keep listening for future crashes.
import os
import requests
from dotenv import load_dotenv
load_dotenv()
url = "https://lawde.net/api/v1/logs/ingest"
headers = {
"x-lawde-api-key": os.environ["LAWDE_API_KEY"],
"Content-Type": "application/json",
}
payload = {
"error_class": "ValueError",
"error_message": "LAWDE Shield Initial Test Crash",
"file_path": "test_ingest.py",
"line_number": 1,
"stack_trace": "ValueError: LAWDE Shield Initial Test Crash\n at test_ingest.py:1",
"environment": "development",
"app_id": os.environ.get("LAWDE_APP_ID"),
}
payload = {k: v for k, v in payload.items() if v is not None}
r = requests.post(url, json=payload, headers=headers, timeout=15)
print(r.status_code, r.json())
3. Phase B — Shared reporter helper (put this in your app package)
Auth is the workspace API key via x-lawde-api-key. Workspace membership is resolved server-side from that key — you do not send a separate workspace header. Always wrap the HTTP call so reporting failures never take down your API.
app/lawde_report.py
# File: app/lawde_report.py ← LIVE helper used by your framework
import os
import traceback
import requests
from dotenv import load_dotenv
load_dotenv()
INGEST_URL = "https://lawde.net/api/v1/logs/ingest"
API_KEY = os.environ["LAWDE_API_KEY"]
APP_ID = os.environ.get("LAWDE_APP_ID") # optional
def report_exception(exc: BaseException, *, environment: str = "production") -> dict | None:
"""Push one crash to Sentinel. Never raise into the host app."""
tb = "".join(traceback.format_exception(type(exc), exc, exc.__traceback__))
frame = traceback.extract_tb(exc.__traceback__)[-1] if exc.__traceback__ else None
payload = {
"error_class": type(exc).__name__,
"error_message": str(exc) or type(exc).__name__,
"stack_trace": tb or str(exc),
"file_path": frame.filename if frame else "unknown",
"line_number": frame.lineno if frame else 1,
"environment": environment,
}
if APP_ID:
payload["app_id"] = APP_ID
try:
response = requests.post(
INGEST_URL,
headers={
"Content-Type": "application/json",
"x-lawde-api-key": API_KEY,
},
json=payload,
timeout=15,
)
response.raise_for_status()
return response.json()
except Exception:
return None # fail silently — never take down the API
4. FastAPI — live global exception handler
Register @app.exception_handler(Exception) on the same FastAPI instance you serve with uvicorn/gunicorn. Every unhandled route exception becomes a Sentinel event.
FastAPI
# File: app/main.py ← LIVE wire for FastAPI
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from app.lawde_report import report_exception
app = FastAPI()
@app.exception_handler(Exception)
async def lawde_exception_handler(request: Request, exc: Exception):
# Called for unhandled exceptions in routes — this IS live monitoring
report_exception(exc, environment="production")
return JSONResponse(status_code=500, content={"detail": "internal_error"})
@app.get("/boom")
def boom():
raise RuntimeError("LAWDE live wire check")
# Start (example):
# uvicorn app.main:app --host 0.0.0.0 --port 8000
5. Flask — live errorhandler
Flask
# File: app.py ← LIVE wire for Flask
from flask import Flask, jsonify
from app.lawde_report import report_exception
app = Flask(__name__)
@app.errorhandler(Exception)
def handle_exception(exc):
report_exception(exc, environment="production")
return jsonify(error="internal_error"), 500
@app.get("/boom")
def boom():
raise RuntimeError("LAWDE live wire check")
if __name__ == "__main__":
app.run(port=5000)
6. Django — live middleware
Prefer middleware process_exception (or a logging.Handler that calls the same helper). Add the middleware in settings.MIDDLEWARE and restart gunicorn/uwsgi/runserver.
Django
# File: myproject/lawde_middleware.py ← LIVE wire for Django
from app.lawde_report import report_exception # adjust import path
class LawdeExceptionMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
return self.get_response(request)
def process_exception(self, request, exception):
# Django calls this for unhandled view exceptions
report_exception(exception, environment="production")
return None # let Django continue its normal 500 handling
# settings.py — add near the top of MIDDLEWARE so it wraps views:
# MIDDLEWARE = [
# "myproject.lawde_middleware.LawdeExceptionMiddleware",
# ...
# ]