Merge lp:~elopio/snapcraft/log_handler-2 into lp:~snappy-dev/snapcraft/core

Proposed by Leo Arias
Status: Needs review
Proposed branch: lp:~elopio/snapcraft/log_handler-2
Merge into: lp:~snappy-dev/snapcraft/core
Prerequisite: lp:~elopio/snapcraft/log_handler
Diff against target: 105 lines (+42/-9)
4 files modified
snapcraft/cmds.py (+1/-3)
snapcraft/log.py (+26/-5)
snapcraft/tests/test_cmds.py (+2/-1)
snapcraft/tests/test_log.py (+13/-0)
To merge this branch: bzr merge lp:~elopio/snapcraft/log_handler-2
Reviewer Review Type Date Requested Status
Snappy Developers Pending
Review via email: mp+266481@code.launchpad.net

Commit message

Added filters to better handle the bold in the log.

Description of the change

Here again I went the extra mile to keep the existing behaviour. But this stuff opens the way to fancier and consistent logging, so we can change it whenever we like.

To post a comment you must log in.
Revision history for this message
Michael Terry (mterry) wrote :

This handles the specific case of the "Wrote the following as snapcraft.yaml:" message. But it feels a bit too magic to me. Doesn't it feel weird to automatically bold things based on whether a colon-newline appears in the string?

This also doesn't address the other print() statements (like when we run a subcommand.

Wouldn't it make more sense to have an argument to the info() call (maybe provided by a subclassed Logger class from snapcraft.log)?

Revision history for this message
Leo Arias (elopio) wrote :

> Wouldn't it make more sense to have an argument to the info() call (maybe
> provided by a subclassed Logger class from snapcraft.log)?

That was my first approach, extending the Format class. But then it breaks the original behaviour, where all the args and kwars passed will be used to create the string. Like:
logger.info('test {} {var}', 'v1', var='v2')

If you prefer handling the arguments ourselfs, I can easily revert.

Revision history for this message
Leo Arias (elopio) wrote :

> This also doesn't address the other print() statements (like when we run a
> subcommand.

That's the following branch. Looking for some free time to do it.
What I have in mind for that is to have a separate logger, named like __name__ + '.plugin'
Using a namespace, I can easily set a different format for it, without the bold.

Revision history for this message
Sergio Schvezov (sergiusens) wrote :

what is the gain here?

Revision history for this message
Leo Arias (elopio) wrote :

By putting it into a filter then all the logs we send will follow the same style. The alternatives require the caller to know too much about the formatting specifics, which will result in inconsistencies.

Revision history for this message
Sergio Schvezov (sergiusens) wrote :

I'll take another look at this if you merge with trunk again.

Unmerged revisions

116. By Leo Arias

Added filters to better handle the bold in the log.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'snapcraft/cmds.py'
2--- snapcraft/cmds.py 2015-07-29 15:21:18 +0000
3+++ snapcraft/cmds.py 2015-07-30 21:43:43 +0000
4@@ -47,9 +47,7 @@
5 yaml = yaml.strip()
6 with open('snapcraft.yaml', mode='w+') as f:
7 f.write(yaml)
8- logger.info('Wrote the following as snapcraft.yaml.')
9- print()
10- print(yaml)
11+ logger.info('Wrote the following as snapcraft.yaml:\n%s', yaml)
12 sys.exit(0)
13
14
15
16=== modified file 'snapcraft/log.py'
17--- snapcraft/log.py 2015-07-30 21:43:43 +0000
18+++ snapcraft/log.py 2015-07-30 21:43:43 +0000
19@@ -23,6 +23,20 @@
20 _COLOR_END = '\033[0m'
21
22
23+class _BoldFilter(logging.Filter):
24+
25+ def filter(self, record):
26+ record.msg = _wrap_bold(record.msg)
27+ return super().filter(record)
28+
29+
30+class _HeaderBoldFilter(logging.Filter):
31+
32+ def filter(self, record):
33+ record.msg = _wrap_header_bold(record.msg)
34+ return super().filter(record)
35+
36+
37 class _StdoutFilter(logging.Filter):
38
39 def filter(self, record):
40@@ -35,18 +49,25 @@
41 return record.levelno >= logging.ERROR
42
43
44+def _wrap_bold(string):
45+ return _COLOR_BOLD + string + _COLOR_END
46+
47+
48+def _wrap_header_bold(string):
49+ header, sep, rest = string.partition(':\n')
50+ return _wrap_bold(header + sep) + rest
51+
52+
53 def configure(logger_name=None):
54 stdout_handler = logging.StreamHandler(stream=sys.stdout)
55 stdout_handler.addFilter(_StdoutFilter())
56+ stdout_handler.addFilter(_HeaderBoldFilter())
57 stderr_handler = logging.StreamHandler(stream=sys.stderr)
58 stderr_handler.addFilter(_StderrFilter())
59- handlers = [stdout_handler, stderr_handler]
60+ stderr_handler.addFilter(_BoldFilter())
61
62- formatter = logging.Formatter(
63- _COLOR_BOLD + '{msg}' + _COLOR_END, style='{')
64 logger = logging.getLogger(logger_name)
65- for handler in handlers:
66- handler.setFormatter(formatter)
67+ for handler in [stdout_handler, stderr_handler]:
68 logger.addHandler(handler)
69
70 logger.setLevel(logging.INFO)
71
72=== modified file 'snapcraft/tests/test_cmds.py'
73--- snapcraft/tests/test_cmds.py 2015-07-29 15:21:18 +0000
74+++ snapcraft/tests/test_cmds.py 2015-07-30 21:43:43 +0000
75@@ -95,7 +95,8 @@
76
77 self.assertEqual(raised.exception.code, 0, 'Wrong exit code returned.')
78 self.assertEqual(
79- 'Wrote the following as snapcraft.yaml.\n',
80+ 'Wrote the following as snapcraft.yaml:\n'
81+ 'parts:\n',
82 fake_logger.output)
83
84
85
86=== modified file 'snapcraft/tests/test_log.py'
87--- snapcraft/tests/test_log.py 2015-07-30 21:43:43 +0000
88+++ snapcraft/tests/test_log.py 2015-07-30 21:43:43 +0000
89@@ -84,3 +84,16 @@
90 '\033[1mTest critical\033[0m\n')
91 self.assertEqual(expected_out, mock_stdout.getvalue())
92 self.assertEqual(expected_err, mock_stderr.getvalue())
93+
94+ def test_log_with_args_must_only_make_message_bold(self, _, mock_stdout):
95+ logger_name = self.id()
96+ log.configure(logger_name)
97+ logger = logging.getLogger(logger_name)
98+
99+ logger.info('Test info:\n%s\n%s', 'args1', 'args2')
100+
101+ expected_out = (
102+ '\033[1mTest info:\n\033[0m'
103+ 'args1\n'
104+ 'args2\n')
105+ self.assertEqual(expected_out, mock_stdout.getvalue())

Subscribers

People subscribed via source and target branches

to all changes: