diff --git a/cylc/flow/network/client.py b/cylc/flow/network/client.py index 27798c58741..b2cec410f56 100644 --- a/cylc/flow/network/client.py +++ b/cylc/flow/network/client.py @@ -20,6 +20,7 @@ abstractmethod, ) import asyncio +import getpass import os from shutil import which import socket @@ -366,6 +367,16 @@ def get_header(self) -> dict: if cmd.startswith(cylc_bin_dir): cmd = cmd.replace(cylc_bin_dir, '') + try: + behalf_of = f" (possibly on behalf of {os.getlogin()})" + except OSError: + behalf_of = None + if not behalf_of: + try: + behalf_of = f" (possibly on behalf of {getpass.getuser()})" + except OSError: + behalf_of = '' + return { 'meta': { 'prog': cmd, @@ -374,6 +385,7 @@ def get_header(self) -> dict: os.getenv( "CLIENT_COMMS_METH", default=CommsMeth.ZMQ.value - ) + ), + 'behalf_of': behalf_of } } diff --git a/cylc/flow/network/resolvers.py b/cylc/flow/network/resolvers.py index 48ef39795ec..60a9beeb524 100644 --- a/cylc/flow/network/resolvers.py +++ b/cylc/flow/network/resolvers.py @@ -723,13 +723,14 @@ async def _mutation_mapper( Others go to the scheduler command queue. """ + behalf_of = meta.get('behalf_of', '') user = meta.get('auth_user', self.schd.owner) if user == self.schd.owner: - log_user = "" # don't log user name if owner + log_user = f" from {self.schd.owner}" else: log_user = f" from {user}" - log1 = f'Command "{command}" received{log_user}.' + log1 = f'Command "{command}" received{log_user}{behalf_of}.' log2 = ( f"{command}(" + ", ".join( diff --git a/tests/integration/network/test_resolvers.py b/tests/integration/network/test_resolvers.py index 251d01e0ac4..68f5dd2c7c8 100644 --- a/tests/integration/network/test_resolvers.py +++ b/tests/integration/network/test_resolvers.py @@ -244,12 +244,19 @@ async def test_command_logging(mock_flow, caplog, log_filter): } meta["auth_user"] = mock_flow.owner await mock_flow.resolvers._mutation_mapper("put_messages", kwargs, meta) - assert not log_filter(contains='Command "put_messages" received:') + assert not log_filter( + contains=f'Command "put_messages" received from {mock_flow.owner}') meta["auth_user"] = "Dr Spock" await mock_flow.resolvers._mutation_mapper("put_messages", kwargs, meta) assert log_filter(contains='Command "put_messages" received from Dr Spock') + meta["auth_user"] = "Dr Spock" + meta["behalf_of"] = " (possibly on behalf of Mr Nimoy)" + await mock_flow.resolvers._mutation_mapper("put_messages", kwargs, meta) + assert log_filter( + contains='received from Dr Spock (possibly on behalf of Mr Nimoy)') + async def test_command_validation_failure( mock_flow,