Skip to content
Open
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
7 changes: 7 additions & 0 deletions changes/7a68cdaf97188251836d1f71709d33ce.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
desc: Added information about ``SynTask`` data when printing asyncio tasks in response
to receving a ``SIGUSR2`` signal.
desc:literal: false
prs: []
type: note
...
20 changes: 16 additions & 4 deletions synapse/glob.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,48 @@
import os
import pprint
import signal
import asyncio
import logging
import threading
import faulthandler

import synapse.common as s_common
import synapse.lib.time as s_time

logger = logging.getLogger(__name__)

_glob_loop = None
_glob_thrd = None


def _asynciostacks(*args, **kwargs): # pragma: no cover
'''
A signal handler used to print asyncio task stacks and thread stacks.
'''
ts = s_time.repr(s_common.now())
print(80 * '*')
print('Asyncio tasks stacks:')
print(f'Asyncio task stacks @ {ts}:')
tasks = asyncio.all_tasks(_glob_loop)
for task in tasks:
task.print_stack()
if hasattr(task, '_syn_task'):
st = task._syn_task
root = None
if st.root is not None:
root = st.root.iden
print(f'syntask metadata: iden={st.iden} name={st.name} root={root} user={st.user.iden} username={st.user.name}')
print(pprint.pformat(st.info))
print(80 * '*')
print('Faulthandler stack frames per thread:')
print(f'Faulthandler stack frames per thread @ {ts}:')
faulthandler.dump_traceback()
print(80 * '*')

def _threadstacks(*args, **kwargs): # pragma: no cover
'''
A signal handler used to print thread stacks.
'''
ts = s_time.repr(s_common.now())
print(80 * '*')
print('Faulthandler stack frames per thread:')
print(f'Faulthandler stack frames per thread @ {ts}:')
faulthandler.dump_traceback()
print(80 * '*')

Expand Down
47 changes: 47 additions & 0 deletions synapse/tests/test_glob.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import asyncio
import unittest.mock as mock

import synapse.glob as s_glob

import synapse.tests.utils as s_t_utils
Expand All @@ -11,3 +14,47 @@ async def afoo():

retn = s_glob.sync(afoo())
self.eq(retn, 42)

async def test_glob_stacks(self):

lines = []
def mock_print(*args, **kwargs):
self.isinstance(args[0], str)
lines.append(args[0])

with mock.patch('builtins.print', mock_print):
self.none(s_glob._threadstacks())

text = '\n'.join(lines)
self.isin('Faulthandler stack frames per thread', text)

lines.clear()

async with self.getTestCore() as core:

q = 'while (true) { $lib.time.sleep(60) }'
event = asyncio.Event()

async def coro(info):
async for mesg in core.storm(q):
if mesg[0] == 'init':
info |= mesg[1]
event.set()

init_mesg = {}
fut = core.schedCoro(coro(init_mesg))

self.true(await asyncio.wait_for(event.wait(), timeout=12))

with mock.patch('builtins.print', mock_print):
self.none(s_glob._asynciostacks())

fut.cancel()

text = '\n'.join(lines)
self.isin('Asyncio task stacks', text)
self.isin('syntask metadata', text)
self.isin(q, text)
self.isin('root=None', text)
self.isin(f'root={init_mesg.get("task", "newp")}', text)
self.isin('Faulthandler stack frames per thread', text)