Log tbs from non-RAE `._invoke()`-RPC-task errors

`RemoteActorError`s show this by default in their `.__repr__()`, and we
obvi capture and embed the src traceback in an `Error` msg prior to
transit, but for logging it's also handy to see the tb of any set
`Context._remote_error` on console especially when trying to decipher
remote error details at their origin actor. Also improve the log message
description using `ctx.repr_state` and show any `ctx.outcome`.
runtime_to_msgspec
Tyler Goodlet 2024-06-14 15:49:30 -04:00
parent 418c6907fd
commit e6d4ec43b9
1 changed files with 30 additions and 17 deletions

View File

@ -26,6 +26,7 @@ from contextlib import (
from functools import partial from functools import partial
import inspect import inspect
from pprint import pformat from pprint import pformat
import traceback
from typing import ( from typing import (
Any, Any,
Callable, Callable,
@ -47,6 +48,7 @@ from ._context import (
) )
from ._exceptions import ( from ._exceptions import (
ContextCancelled, ContextCancelled,
RemoteActorError,
ModuleNotExposed, ModuleNotExposed,
MsgTypeError, MsgTypeError,
TransportClosed, TransportClosed,
@ -198,7 +200,8 @@ async def _invoke_non_context(
raise ipc_err raise ipc_err
else: else:
log.exception( log.exception(
f'Failed to respond to runtime RPC request for\n\n' f'Failed to ack runtime RPC request\n\n'
f'{func} x=> {ctx.chan}\n\n'
f'{ack}\n' f'{ack}\n'
) )
@ -415,7 +418,6 @@ async def _errors_relayed_via_ipc(
async def _invoke( async def _invoke(
actor: Actor, actor: Actor,
cid: str, cid: str,
chan: Channel, chan: Channel,
@ -691,10 +693,6 @@ async def _invoke(
boxed_type=trio.Cancelled, boxed_type=trio.Cancelled,
canceller=canceller, canceller=canceller,
) )
# does this matter other then for
# consistentcy/testing? |_ no user code should be
# in this scope at this point..
# ctx._local_error = ctxc
raise ctxc raise ctxc
# XXX: do we ever trigger this block any more? # XXX: do we ever trigger this block any more?
@ -715,6 +713,11 @@ async def _invoke(
# always set this (child) side's exception as the # always set this (child) side's exception as the
# local error on the context # local error on the context
ctx._local_error: BaseException = scope_error ctx._local_error: BaseException = scope_error
# ^-TODO-^ question,
# does this matter other then for
# consistentcy/testing?
# |_ no user code should be in this scope at this point
# AND we already set this in the block below?
# if a remote error was set then likely the # if a remote error was set then likely the
# exception group was raised due to that, so # exception group was raised due to that, so
@ -741,22 +744,32 @@ async def _invoke(
logmeth: Callable = log.runtime logmeth: Callable = log.runtime
merr: Exception|None = ctx.maybe_error merr: Exception|None = ctx.maybe_error
descr_str: str = 'with final result `{repr(ctx.outcome)}`' message: str = 'IPC context terminated '
message: str = ( descr_str: str = (
f'IPC context terminated {descr_str}\n\n' f'after having {ctx.repr_state!r}\n'
) )
if merr: if merr:
descr_str: str = (
f'with ctx having {ctx.repr_state!r}\n' logmeth: Callable = log.error
f'{ctx.repr_outcome()}\n'
)
if isinstance(merr, ContextCancelled): if isinstance(merr, ContextCancelled):
logmeth: Callable = log.runtime logmeth: Callable = log.runtime
else:
logmeth: Callable = log.error
message += f'\n{merr!r}\n'
logmeth(message) if not isinstance(merr, RemoteActorError):
tb_str: str = ''.join(traceback.format_exception(merr))
descr_str += (
f'\n{merr!r}\n' # needed?
f'{tb_str}\n'
)
else:
descr_str += f'\n{merr!r}\n'
else:
descr_str += f'\nand final result {ctx.outcome!r}\n'
logmeth(
message
+
descr_str
)
async def try_ship_error_to_remote( async def try_ship_error_to_remote(