Skip to content

Commit 7ac9cc2

Browse files
authored
Logger fixes. Fix #37 (#38)
* Logger fixes. Fix #37 * [x] Use class name as logger prefix * [x] Use normal repr instead of manual `'{}'` code * [x] On reconnect/close use client logger instead of formatting to str * [x] Single used log templates moved to the use place
1 parent 63166d1 commit 7ac9cc2

File tree

8 files changed

+76
-88
lines changed

8 files changed

+76
-88
lines changed

exec_helpers/_api.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
from exec_helpers import exceptions
3434
from exec_helpers import exec_result # noqa # pylint: disable=unused-import
3535
from exec_helpers import proc_enums
36-
from exec_helpers import _log_templates
3736

3837
_type_exit_codes = typing.Union[int, proc_enums.ExitCodes]
3938
_type_expected = typing.Optional[typing.Iterable[_type_exit_codes]]
@@ -249,7 +248,7 @@ def execute(
249248
verbose=verbose,
250249
**kwargs
251250
)
252-
message = _log_templates.CMD_RESULT.format(result=result)
251+
message = "Command {result.cmd!r} exit code: {result.exit_code!s}".format(result=result)
253252
self.logger.log(
254253
level=logging.INFO if verbose else logging.DEBUG,
255254
msg=message
@@ -292,7 +291,8 @@ def check_call(
292291
ret = self.execute(command, verbose, timeout, **kwargs)
293292
if ret['exit_code'] not in expected:
294293
message = (
295-
_log_templates.CMD_UNEXPECTED_EXIT_CODE.format(
294+
"{append}Command {result.cmd!r} returned exit code "
295+
"{result.exit_code!s} while expected {expected!s}".format(
296296
append=error_info + '\n' if error_info else '',
297297
result=ret,
298298
expected=expected
@@ -339,7 +339,8 @@ def check_stderr(
339339
error_info=error_info, raise_on_err=raise_on_err, **kwargs)
340340
if ret['stderr']:
341341
message = (
342-
_log_templates.CMD_UNEXPECTED_STDERR.format(
342+
"{append}Command {result.cmd!r} STDERR while not expected\n"
343+
"\texit code: {result.exit_code!s}".format(
343344
append=error_info + '\n' if error_info else '',
344345
result=ret,
345346
))

exec_helpers/_log_templates.py

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,10 @@
2020
from __future__ import division
2121
from __future__ import unicode_literals
2222

23-
CMD_EXEC = "Executing command:\n{cmd!s}\n"
24-
CMD_RESULT = "Command exit code '{result.exit_code!s}':\n{result.cmd}\n"
25-
CMD_UNEXPECTED_EXIT_CODE = (
26-
"{append}Command '{result.cmd}' returned exit code '{result.exit_code!s}' "
27-
"while expected '{expected!s}'"
28-
)
29-
CMD_UNEXPECTED_STDERR = (
30-
"{append}Command '{result.cmd}' STDERR while not expected\n"
31-
"\texit code: '{result.exit_code!s}'"
32-
)
23+
CMD_EXEC = "Executing command:\n{cmd!r}\n"
24+
3325
CMD_WAIT_ERROR = (
34-
"Wait for '{result.cmd}' during {timeout!s}s: no return code!\n"
26+
"Wait for {result.cmd!r} during {timeout!s}s: no return code!\n"
3527
'\tSTDOUT:\n'
3628
'{result.stdout_brief}\n'
3729
'\tSTDERR"\n'

exec_helpers/_ssh_client_base.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@
5050

5151
__all__ = ('SSHClientBase', )
5252

53-
logger = logging.getLogger(__name__)
5453
logging.getLogger('paramiko').setLevel(logging.WARNING)
5554
logging.getLogger('iso8601').setLevel(logging.WARNING)
5655

@@ -59,9 +58,6 @@
5958
]
6059
_type_RSAKeys = typing.Iterable[paramiko.RSAKey]
6160
_type_exit_codes = typing.Union[int, proc_enums.ExitCodes]
62-
_type_multiple_results = typing.Dict[
63-
typing.Tuple[str, int], exec_result.ExecResult
64-
]
6561
_type_execute_async = typing.Tuple[
6662
paramiko.Channel,
6763
paramiko.ChannelFile,
@@ -149,7 +145,7 @@ def __call__(
149145
try:
150146
ssh.execute('cd ~', timeout=5)
151147
except BaseException: # Note: Do not change to lower level!
152-
logger.debug('Reconnect {}'.format(ssh))
148+
ssh.logger.debug('Reconnect')
153149
ssh.reconnect()
154150
return ssh
155151
if (
@@ -158,7 +154,7 @@ def __call__(
158154
): # pragma: no cover
159155
# If we have only cache reference and temporary getrefcount
160156
# reference: close connection before deletion
161-
logger.debug('Closing {} as unused'.format(cls.__cache[key]))
157+
cls.__cache[key].logger.debug('Closing as unused')
162158
cls.__cache[key].close()
163159
del cls.__cache[key]
164160
# noinspection PyArgumentList
@@ -186,7 +182,7 @@ def clear_cache(mcs): # type: () -> None
186182
CPYTHON and
187183
sys.getrefcount(ssh) == n_count
188184
): # pragma: no cover
189-
logger.debug('Closing {} as unused'.format(ssh))
185+
ssh.logger.debug('Closing as unused')
190186
ssh.close()
191187
mcs.__cache = {}
192188

@@ -306,7 +302,9 @@ def __init__(
306302
.. note:: auth has priority over username/password/private_keys
307303
"""
308304
super(SSHClientBase, self).__init__(
309-
logger=logger.getChild(
305+
logger=logging.getLogger(
306+
self.__class__.__name__
307+
).getChild(
310308
'{host}:{port}'.format(host=host, port=port)
311309
),
312310
)
@@ -376,7 +374,7 @@ def __repr__(self):
376374
auth=self.auth
377375
)
378376

379-
def __str__(self):
377+
def __str__(self): # pragma: no cover
380378
"""Representation for debug purposes."""
381379
return '{cls}(host={host}, port={port}) for user {user}'.format(
382380
cls=self.__class__.__name__, host=self.hostname, port=self.port,
@@ -832,7 +830,7 @@ def execute_together(
832830
expected=None, # type: typing.Optional[typing.Iterable[int]]
833831
raise_on_err=True, # type: bool
834832
**kwargs
835-
): # type: (...) -> _type_multiple_results
833+
): # type: (...) -> typing.Dict[typing.Tuple[str, int], exec_result.ExecResult]
836834
"""Execute command on multiple remotes in async mode.
837835
838836
:param remotes: Connections to execute on

exec_helpers/ssh_auth.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,9 +187,7 @@ def connect(
187187
logger.exception('No password has been set!')
188188
raise
189189
else:
190-
logger.critical(
191-
'Unexpected PasswordRequiredException, '
192-
'when password is set!')
190+
logger.critical('Unexpected PasswordRequiredException, when password is set!')
193191
raise
194192
except (paramiko.AuthenticationException,
195193
paramiko.BadHostKeyException):

test/test_ssh_client.py

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def __iter__(self):
5353
username = 'user'
5454
password = 'pass'
5555
command = 'ls ~\nline 2\nline 3\nline с кирилицей'
56-
command_log = u"Executing command:\n{!s}\n".format(command.rstrip())
56+
command_log = u"Executing command:\n{!r}\n".format(command.rstrip())
5757
stdout_list = [b' \n', b'2\n', b'3\n', b' \n']
5858
stdout_str = b''.join(stdout_list).strip().decode('utf-8')
5959
stderr_list = [b' \n', b'0\n', b'1\n', b' \n']
@@ -64,7 +64,7 @@ def __iter__(self):
6464
print_stdin = 'read line; echo "$line"'
6565

6666

67-
@mock.patch('exec_helpers._ssh_client_base.logger', autospec=True)
67+
@mock.patch('logging.getLogger', autospec=True)
6868
@mock.patch('paramiko.AutoAddPolicy', autospec=True, return_value='AutoAddPolicy')
6969
@mock.patch('paramiko.SSHClient', autospec=True)
7070
class TestExecute(unittest.TestCase):
@@ -89,8 +89,7 @@ def get_ssh():
8989

9090
@staticmethod
9191
def gen_cmd_result_log_message(result):
92-
return (u"Command exit code '{code!s}':\n{cmd!s}\n"
93-
.format(cmd=result.cmd.rstrip(), code=result.exit_code))
92+
return u"Command {result.cmd!r} exit code: {result.exit_code!s}".format(result=result)
9493

9594
def test_001_execute_async(self, client, policy, logger):
9695
chan = mock.Mock()
@@ -116,7 +115,8 @@ def test_001_execute_async(self, client, policy, logger):
116115
mock.call.makefile_stderr('rb'),
117116
mock.call.exec_command('{}\n'.format(command))
118117
))
119-
log = logger.getChild('{host}:{port}'.format(host=host, port=port))
118+
# raise ValueError(logger.mock_calls)
119+
log = logger(ssh.__class__.__name__).getChild('{host}:{port}'.format(host=host, port=port))
120120
self.assertIn(
121121
mock.call.log(level=logging.DEBUG, msg=command_log),
122122
log.mock_calls
@@ -151,7 +151,7 @@ def test_002_execute_async_pty(self, client, policy, logger):
151151
mock.call.makefile_stderr('rb'),
152152
mock.call.exec_command('{}\n'.format(command))
153153
))
154-
log = logger.getChild('{host}:{port}'.format(host=host, port=port))
154+
log = logger(ssh.__class__.__name__).getChild('{host}:{port}'.format(host=host, port=port))
155155
self.assertIn(
156156
mock.call.log(level=logging.DEBUG, msg=command_log),
157157
log.mock_calls
@@ -235,7 +235,7 @@ def test_004_execute_async_sudo(self, client, policy, logger):
235235
"sudo -S bash -c '"
236236
"eval \"$(base64 -d <(echo \"{0}\"))\"'".format(encoded_cmd))
237237
))
238-
log = logger.getChild('{host}:{port}'.format(host=host, port=port))
238+
log = logger(ssh.__class__.__name__).getChild('{host}:{port}'.format(host=host, port=port))
239239
self.assertIn(
240240
mock.call.log(level=logging.DEBUG, msg=command_log),
241241
log.mock_calls
@@ -271,7 +271,7 @@ def test_005_execute_async_with_sudo_enforce(self, client, policy, logger):
271271
"sudo -S bash -c '"
272272
"eval \"$(base64 -d <(echo \"{0}\"))\"'".format(encoded_cmd))
273273
))
274-
log = logger.getChild('{host}:{port}'.format(host=host, port=port))
274+
log = logger(ssh.__class__.__name__).getChild('{host}:{port}'.format(host=host, port=port))
275275
self.assertIn(
276276
mock.call.log(level=logging.DEBUG, msg=command_log),
277277
log.mock_calls
@@ -303,7 +303,7 @@ def test_006_execute_async_with_no_sudo_enforce(self, client, policy, logger):
303303
mock.call.makefile_stderr('rb'),
304304
mock.call.exec_command('{}\n'.format(command))
305305
))
306-
log = logger.getChild('{host}:{port}'.format(host=host, port=port))
306+
log = logger(ssh.__class__.__name__).getChild('{host}:{port}'.format(host=host, port=port))
307307
self.assertIn(
308308
mock.call.log(level=logging.DEBUG, msg=command_log),
309309
log.mock_calls
@@ -335,7 +335,7 @@ def test_007_execute_async_with_sudo_none_enforce(self, client, policy, logger):
335335
mock.call.makefile_stderr('rb'),
336336
mock.call.exec_command('{}\n'.format(command))
337337
))
338-
log = logger.getChild('{host}:{port}'.format(host=host, port=port))
338+
log = logger(ssh.__class__.__name__).getChild('{host}:{port}'.format(host=host, port=port))
339339
self.assertIn(
340340
mock.call.log(level=logging.DEBUG, msg=command_log),
341341
log.mock_calls
@@ -380,7 +380,7 @@ def test_008_execute_async_sudo_password(
380380
"sudo -S bash -c '"
381381
"eval \"$(base64 -d <(echo \"{0}\"))\"'".format(encoded_cmd))
382382
))
383-
log = logger.getChild('{host}:{port}'.format(host=host, port=port))
383+
log = logger(ssh.__class__.__name__).getChild('{host}:{port}'.format(host=host, port=port))
384384
self.assertIn(
385385
mock.call.log(level=logging.DEBUG, msg=command_log),
386386
log.mock_calls
@@ -410,7 +410,7 @@ def test_009_execute_async_verbose(self, client, policy, logger):
410410
mock.call.makefile_stderr('rb'),
411411
mock.call.exec_command('{}\n'.format(command))
412412
))
413-
log = logger.getChild('{host}:{port}'.format(host=host, port=port))
413+
log = logger(ssh.__class__.__name__).getChild('{host}:{port}'.format(host=host, port=port))
414414
self.assertIn(
415415
mock.call.log(level=logging.INFO, msg=command_log),
416416
log.mock_calls
@@ -420,7 +420,7 @@ def test_010_execute_async_mask_command(self, client, policy, logger):
420420
cmd = "USE='secret=secret_pass' do task"
421421
log_mask_re = r"secret\s*=\s*([A-Z-a-z0-9_\-]+)"
422422
masked_cmd = "USE='secret=<*masked*>' do task"
423-
cmd_log = u"Executing command:\n{!s}\n".format(masked_cmd)
423+
cmd_log = u"Executing command:\n{!r}\n".format(masked_cmd)
424424

425425
chan = mock.Mock()
426426
open_session = mock.Mock(return_value=chan)
@@ -445,7 +445,7 @@ def test_010_execute_async_mask_command(self, client, policy, logger):
445445
mock.call.makefile_stderr('rb'),
446446
mock.call.exec_command('{}\n'.format(cmd))
447447
))
448-
log = logger.getChild('{host}:{port}'.format(host=host, port=port))
448+
log = logger(ssh.__class__.__name__).getChild('{host}:{port}'.format(host=host, port=port))
449449
self.assertIn(
450450
mock.call.log(level=logging.DEBUG, msg=cmd_log),
451451
log.mock_calls
@@ -620,7 +620,7 @@ def test_014_check_stdin_closed(self, client, policy, logger):
620620
open_session.assert_called_once()
621621
stdin.assert_not_called()
622622

623-
log = logger.getChild('{host}:{port}'.format(host=host, port=port))
623+
log = logger(ssh.__class__.__name__).getChild('{host}:{port}'.format(host=host, port=port))
624624
log.warning.assert_called_once_with('STDIN Send failed: closed channel')
625625

626626
self.assertIn(chan, result)
@@ -777,7 +777,7 @@ def test_019_execute(
777777
execute_async.assert_called_once_with(command, verbose=False)
778778
chan.assert_has_calls((mock.call.status_event.is_set(), ))
779779
message = self.gen_cmd_result_log_message(result)
780-
log = logger.getChild('{host}:{port}'.format(host=host, port=port)).log
780+
log = logger(ssh.__class__.__name__).getChild('{host}:{port}'.format(host=host, port=port)).log
781781
log.assert_has_calls(
782782
[
783783
mock.call(
@@ -824,7 +824,7 @@ def test_020_execute_verbose(
824824
chan.assert_has_calls((mock.call.status_event.is_set(), ))
825825

826826
message = self.gen_cmd_result_log_message(result)
827-
log = logger.getChild('{host}:{port}'.format(host=host, port=port)).log
827+
log = logger(ssh.__class__.__name__).getChild('{host}:{port}'.format(host=host, port=port)).log
828828
log.assert_has_calls(
829829
[
830830
mock.call(
@@ -872,7 +872,7 @@ def test_021_execute_no_stdout(
872872
execute_async.assert_called_once_with(
873873
command, verbose=False, open_stdout=False)
874874
message = self.gen_cmd_result_log_message(result)
875-
log = logger.getChild('{host}:{port}'.format(host=host, port=port)).log
875+
log = logger(ssh.__class__.__name__).getChild('{host}:{port}'.format(host=host, port=port)).log
876876
log.assert_has_calls(
877877
[
878878
mock.call(
@@ -916,7 +916,7 @@ def test_022_execute_no_stderr(
916916
execute_async.assert_called_once_with(
917917
command, verbose=False, open_stderr=False)
918918
message = self.gen_cmd_result_log_message(result)
919-
log = logger.getChild('{host}:{port}'.format(host=host, port=port)).log
919+
log = logger(ssh.__class__.__name__).getChild('{host}:{port}'.format(host=host, port=port)).log
920920
log.assert_has_calls(
921921
[
922922
mock.call(
@@ -968,7 +968,7 @@ def test_023_execute_no_stdout_stderr(
968968
open_stderr=False
969969
)
970970
message = self.gen_cmd_result_log_message(result)
971-
log = logger.getChild('{host}:{port}'.format(host=host, port=port)).log
971+
log = logger(ssh.__class__.__name__).getChild('{host}:{port}'.format(host=host, port=port)).log
972972
log.assert_has_calls(
973973
[
974974
mock.call(level=logging.DEBUG, msg=message),
@@ -1003,7 +1003,7 @@ def test_024_execute_timeout(
10031003
execute_async.assert_called_once_with(command, verbose=False)
10041004
chan.assert_has_calls((mock.call.status_event.is_set(), ))
10051005
message = self.gen_cmd_result_log_message(result)
1006-
log = logger.getChild('{host}:{port}'.format(host=host, port=port)).log
1006+
log = logger(ssh.__class__.__name__).getChild('{host}:{port}'.format(host=host, port=port)).log
10071007
self.assertIn(
10081008
mock.call(level=logging.DEBUG, msg=message),
10091009
log.mock_calls
@@ -1069,7 +1069,7 @@ def test_026_execute_mask_command(
10691069
cmd, log_mask_re=log_mask_re, verbose=False)
10701070
chan.assert_has_calls((mock.call.status_event.is_set(),))
10711071
message = self.gen_cmd_result_log_message(result)
1072-
log = logger.getChild('{host}:{port}'.format(host=host, port=port)).log
1072+
log = logger(ssh.__class__.__name__).getChild('{host}:{port}'.format(host=host, port=port)).log
10731073
log.assert_has_calls(
10741074
[
10751075
mock.call(
@@ -1297,7 +1297,7 @@ def test_031_check_stderr(self, check_call, client, policy, logger):
12971297
error_info=None, raise_on_err=raise_on_err)
12981298

12991299

1300-
@mock.patch('exec_helpers._ssh_client_base.logger', autospec=True)
1300+
@mock.patch('logging.getLogger', autospec=True)
13011301
@mock.patch('paramiko.AutoAddPolicy', autospec=True, return_value='AutoAddPolicy')
13021302
@mock.patch('paramiko.SSHClient', autospec=True)
13031303
@mock.patch('paramiko.Transport', autospec=True)
@@ -1528,7 +1528,7 @@ def test_03_execute_through_host_get_pty(
15281528
))
15291529

15301530

1531-
@mock.patch('exec_helpers._ssh_client_base.logger', autospec=True)
1531+
@mock.patch('logging.getLogger', autospec=True)
15321532
@mock.patch('paramiko.AutoAddPolicy', autospec=True, return_value='AutoAddPolicy')
15331533
@mock.patch('paramiko.SSHClient', autospec=True)
15341534
class TestSftp(unittest.TestCase):

0 commit comments

Comments
 (0)