Merge pull request #71 from goodboy/propagate_loglevel

Propagate `tractor.run()` logging level to subactors
user_update
goodboy 2019-03-23 23:30:45 -04:00 committed by GitHub
commit ac4a025aa5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 49 additions and 5 deletions

View File

@ -1,6 +1,7 @@
""" """
Spawning basics Spawning basics
""" """
import pytest
import trio import trio
import tractor import tractor
@ -94,3 +95,42 @@ async def test_most_beautiful_word(start_method):
# actor has completed its main task ``cellar_door``. # actor has completed its main task ``cellar_door``.
print(await portal.result()) print(await portal.result())
async def check_loglevel(level):
assert tractor.current_actor().loglevel == level
log = tractor.log.get_logger()
# XXX using a level actually used inside tractor seems to trigger
# some kind of `logging` module bug FYI.
log.critical('yoyoyo')
def test_loglevel_propagated_to_subactor(
start_method,
capfd,
arb_addr,
):
if start_method == 'forkserver':
pytest.skip(
"a bug with `capfd` seems to make forkserver capture not work?")
level = 'critical'
async def main():
async with tractor.open_nursery() as tn:
await tn.run_in_actor(
'log_checker',
check_loglevel,
level=level,
)
tractor.run(
main,
name='arbiter',
loglevel=level,
start_method=start_method,
arbiter_addr=arb_addr,
)
# ensure subactor spits log message on stderr
captured = capfd.readouterr()
assert 'yoyoyo' in captured.err

View File

@ -10,7 +10,7 @@ import typing
import trio # type: ignore import trio # type: ignore
from trio import MultiError from trio import MultiError
from .log import get_console_log, get_logger, get_loglevel from . import log
from ._ipc import _connect_chan, Channel, Context from ._ipc import _connect_chan, Channel, Context
from ._actor import ( from ._actor import (
Actor, _start_actor, Arbiter, get_arbiter, find_actor, wait_for_actor Actor, _start_actor, Arbiter, get_arbiter, find_actor, wait_for_actor
@ -51,11 +51,14 @@ async def _main(
) -> typing.Any: ) -> typing.Any:
"""Async entry point for ``tractor``. """Async entry point for ``tractor``.
""" """
log = get_logger('tractor') logger = log.get_logger('tractor')
main = partial(async_fn, *args) main = partial(async_fn, *args)
arbiter_addr = (host, port) = arbiter_addr or ( arbiter_addr = (host, port) = arbiter_addr or (
_default_arbiter_host, _default_arbiter_port) _default_arbiter_host, _default_arbiter_port)
get_console_log(kwargs.get('loglevel', get_loglevel())) loglevel = kwargs.get('loglevel', log.get_loglevel())
if loglevel is not None:
log._default_loglevel = loglevel
log.get_console_log(loglevel)
# make a temporary connection to see if an arbiter exists # make a temporary connection to see if an arbiter exists
arbiter_found = False arbiter_found = False
@ -63,11 +66,11 @@ async def _main(
async with _connect_chan(host, port): async with _connect_chan(host, port):
arbiter_found = True arbiter_found = True
except OSError: except OSError:
log.warning(f"No actor could be found @ {host}:{port}") logger.warning(f"No actor could be found @ {host}:{port}")
# create a local actor and start up its main routine/task # create a local actor and start up its main routine/task
if arbiter_found: # we were able to connect to an arbiter if arbiter_found: # we were able to connect to an arbiter
log.info(f"Arbiter seems to exist @ {host}:{port}") logger.info(f"Arbiter seems to exist @ {host}:{port}")
actor = Actor( actor = Actor(
name or 'anonymous', name or 'anonymous',
arbiter_addr=arbiter_addr, arbiter_addr=arbiter_addr,

View File

@ -112,6 +112,7 @@ class ActorNursery:
rpc_module_paths=[mod_path] + rpc_module_paths, rpc_module_paths=[mod_path] + rpc_module_paths,
bind_addr=bind_addr, bind_addr=bind_addr,
statespace=statespace, statespace=statespace,
loglevel=loglevel,
) )
# this marks the actor to be cancelled after its portal result # this marks the actor to be cancelled after its portal result
# is retreived, see ``wait()`` below. # is retreived, see ``wait()`` below.