64 lines
1.8 KiB
Python
64 lines
1.8 KiB
Python
# SPDX-License-Identifier: Apache-2.0
|
|
# Standard
|
|
from typing import Optional
|
|
import sys
|
|
import threading
|
|
import traceback
|
|
|
|
# Third Party
|
|
from fastapi import APIRouter, Query
|
|
from starlette.requests import Request
|
|
from starlette.responses import PlainTextResponse
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("/threads")
|
|
async def get_threads(
|
|
request: Request,
|
|
name: Optional[str] = Query(
|
|
None, description="Filter by thread name (fuzzy match)"
|
|
),
|
|
thread_id: Optional[int] = Query(None, description="Filter by thread ID"),
|
|
):
|
|
"""Return information about active threads with optional filtering"""
|
|
threads = threading.enumerate()
|
|
|
|
filtered_threads = []
|
|
for t in threads:
|
|
# Apply filters
|
|
if name and name.lower() not in t.name.lower():
|
|
continue
|
|
if thread_id and t.ident != thread_id:
|
|
continue
|
|
filtered_threads.append(t)
|
|
|
|
thread_info = []
|
|
|
|
for t in filtered_threads:
|
|
# Basic thread info with creation time
|
|
info = f"Thread: {t}\n"
|
|
|
|
# Get stack trace if available
|
|
try:
|
|
stack_frames = (
|
|
sys._current_frames().get(t.ident) if t.ident is not None else None
|
|
)
|
|
if stack_frames:
|
|
stack_trace = traceback.format_stack(stack_frames)
|
|
info += "Stack trace:\n" + "".join(stack_trace)
|
|
else:
|
|
info += "No stack trace available\n"
|
|
except AttributeError:
|
|
info += "Stack trace unavailable\n"
|
|
|
|
thread_info.append(info)
|
|
|
|
# Add summary section
|
|
summary = "\n\n=== Thread Summary ===\n"
|
|
summary += f"Total threads: {len(filtered_threads)}\n"
|
|
|
|
return PlainTextResponse(
|
|
content="\n\n".join(thread_info) + summary, media_type="text/plain"
|
|
)
|