mirror of
https://github.com/simonw/datasette.git
synced 2025-12-10 16:51:24 +01:00
Include asyncio task information in /-/threads debug page
This commit is contained in:
parent
2039e78e58
commit
d6b6c9171f
5 changed files with 41 additions and 4 deletions
|
|
@ -2,6 +2,7 @@ import asyncio
|
||||||
import collections
|
import collections
|
||||||
import hashlib
|
import hashlib
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import traceback
|
import traceback
|
||||||
|
|
@ -477,12 +478,19 @@ class Datasette:
|
||||||
|
|
||||||
def threads(self):
|
def threads(self):
|
||||||
threads = list(threading.enumerate())
|
threads = list(threading.enumerate())
|
||||||
return {
|
d = {
|
||||||
"num_threads": len(threads),
|
"num_threads": len(threads),
|
||||||
"threads": [
|
"threads": [
|
||||||
{"name": t.name, "ident": t.ident, "daemon": t.daemon} for t in threads
|
{"name": t.name, "ident": t.ident, "daemon": t.daemon} for t in threads
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
# Only available in Python 3.7+
|
||||||
|
if hasattr(asyncio, "all_tasks"):
|
||||||
|
tasks = asyncio.all_tasks()
|
||||||
|
d.update(
|
||||||
|
{"num_tasks": len(tasks), "tasks": [_cleaner_task_str(t) for t in tasks]}
|
||||||
|
)
|
||||||
|
return d
|
||||||
|
|
||||||
def table_metadata(self, database, table):
|
def table_metadata(self, database, table):
|
||||||
"Fetch table-specific metadata."
|
"Fetch table-specific metadata."
|
||||||
|
|
@ -684,3 +692,14 @@ class DatasetteRouter(AsgiRouter):
|
||||||
await asgi_send_html(
|
await asgi_send_html(
|
||||||
send, await template.render_async(info), status=status, headers=headers
|
send, await template.render_async(info), status=status, headers=headers
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
_cleaner_task_str_re = re.compile(r"\S*site-packages/")
|
||||||
|
|
||||||
|
|
||||||
|
def _cleaner_task_str(task):
|
||||||
|
s = str(task)
|
||||||
|
# This has something like the following in it:
|
||||||
|
# running at /Users/simonw/Dropbox/Development/datasette/venv-3.7.5/lib/python3.7/site-packages/uvicorn/main.py:361>
|
||||||
|
# Clean up everything up to and including site-packages
|
||||||
|
return _cleaner_task_str_re.sub("", s)
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,6 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>{{ filename }}</h1>
|
<h1>{{ filename }}</h1>
|
||||||
|
|
||||||
<pre>{{ data|tojson(indent=4) }}</pre>
|
<pre>{{ data_json }}</pre>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
||||||
|
|
@ -27,5 +27,8 @@ class JsonDataView(BaseView):
|
||||||
return await self.render(
|
return await self.render(
|
||||||
["show_json.html"],
|
["show_json.html"],
|
||||||
request=request,
|
request=request,
|
||||||
context={"filename": self.filename, "data": data},
|
context={
|
||||||
|
"filename": self.filename,
|
||||||
|
"data_json": json.dumps(data, indent=4),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ Shows currently attached databases. `Databases example <https://latest.datasette
|
||||||
/-/threads
|
/-/threads
|
||||||
----------
|
----------
|
||||||
|
|
||||||
Shows details of threads. `Threads example <https://latest.datasette.io/-/threads>`_::
|
Shows details of threads and ``asyncio`` tasks. `Threads example <https://latest.datasette.io/-/threads>`_::
|
||||||
|
|
||||||
{
|
{
|
||||||
"num_threads": 2,
|
"num_threads": 2,
|
||||||
|
|
@ -128,5 +128,11 @@ Shows details of threads. `Threads example <https://latest.datasette.io/-/thread
|
||||||
"ident": 123145319682048,
|
"ident": 123145319682048,
|
||||||
"name": "Thread-1"
|
"name": "Thread-1"
|
||||||
},
|
},
|
||||||
|
],
|
||||||
|
"num_tasks": 3,
|
||||||
|
"tasks": [
|
||||||
|
"<Task pending coro=<RequestResponseCycle.run_asgi() running at uvicorn/protocols/http/httptools_impl.py:385> cb=[set.discard()]>",
|
||||||
|
"<Task pending coro=<Server.serve() running at uvicorn/main.py:361> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x10365c3d0>()]> cb=[run_until_complete.<locals>.<lambda>()]>",
|
||||||
|
"<Task pending coro=<LifespanOn.main() running at uvicorn/lifespan/on.py:48> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x10364f050>()]>>"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ from .fixtures import ( # noqa
|
||||||
)
|
)
|
||||||
import json
|
import json
|
||||||
import pytest
|
import pytest
|
||||||
|
import sys
|
||||||
import urllib
|
import urllib
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1229,6 +1230,14 @@ def test_metadata_json(app_client):
|
||||||
assert METADATA == response.json
|
assert METADATA == response.json
|
||||||
|
|
||||||
|
|
||||||
|
def test_threads_json(app_client):
|
||||||
|
response = app_client.get("/-/threads.json")
|
||||||
|
expected_keys = {"threads", "num_threads"}
|
||||||
|
if sys.version_info >= (3, 7, 0):
|
||||||
|
expected_keys.update({"tasks", "num_tasks"})
|
||||||
|
assert expected_keys == set(response.json.keys())
|
||||||
|
|
||||||
|
|
||||||
def test_plugins_json(app_client):
|
def test_plugins_json(app_client):
|
||||||
response = app_client.get("/-/plugins.json")
|
response = app_client.get("/-/plugins.json")
|
||||||
assert [
|
assert [
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue