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

Proposed by Leo Arias
Status: Merged
Approved by: Michael Terry
Approved revision: 115
Merged at revision: 116
Proposed branch: lp:~elopio/snapcraft/log_handler
Merge into: lp:~snappy-dev/snapcraft/core
Diff against target: 174 lines (+140/-8)
3 files modified
snapcraft/log.py (+52/-0)
snapcraft/main.py (+2/-8)
snapcraft/tests/test_log.py (+86/-0)
To merge this branch: bzr merge lp:~elopio/snapcraft/log_handler
Reviewer Review Type Date Requested Status
Michael Terry (community) Approve
Review via email: mp+266424@code.launchpad.net

Commit message

Send error logs to stderr and message logs to stdout.

Description of the change

On the original logging prints, some messages went to stdout and some to stderr. That was not consistent, nor tested. So this branch adds two handlers to recover that behavoiur, but cleaner.

To post a comment you must log in.
lp:~elopio/snapcraft/log_handler updated
115. By Leo Arias

Added the test file.

Revision history for this message
Michael Terry (mterry) wrote :

LGTM, thanks Leo! And nice that we have a separate log module for any future additions.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'snapcraft/log.py'
--- snapcraft/log.py 1970-01-01 00:00:00 +0000
+++ snapcraft/log.py 2015-07-30 14:52:01 +0000
@@ -0,0 +1,52 @@
1#!/usr/bin/python3
2# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
3#
4# Copyright (C) 2015 Canonical Ltd
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License version 3 as
8# published by the Free Software Foundation.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18import logging
19import sys
20
21
22_COLOR_BOLD = '\033[1m'
23_COLOR_END = '\033[0m'
24
25
26class _StdoutFilter(logging.Filter):
27
28 def filter(self, record):
29 return record.levelno <= logging.WARNING
30
31
32class _StderrFilter(logging.Filter):
33
34 def filter(self, record):
35 return record.levelno >= logging.ERROR
36
37
38def configure(logger_name=None):
39 stdout_handler = logging.StreamHandler(stream=sys.stdout)
40 stdout_handler.addFilter(_StdoutFilter())
41 stderr_handler = logging.StreamHandler(stream=sys.stderr)
42 stderr_handler.addFilter(_StderrFilter())
43 handlers = [stdout_handler, stderr_handler]
44
45 formatter = logging.Formatter(
46 _COLOR_BOLD + '{msg}' + _COLOR_END, style='{')
47 logger = logging.getLogger(logger_name)
48 for handler in handlers:
49 handler.setFormatter(formatter)
50 logger.addHandler(handler)
51
52 logger.setLevel(logging.INFO)
053
=== modified file 'snapcraft/main.py'
--- snapcraft/main.py 2015-07-23 14:32:16 +0000
+++ snapcraft/main.py 2015-07-30 14:52:01 +0000
@@ -16,20 +16,14 @@
16# along with this program. If not, see <http://www.gnu.org/licenses/>.16# along with this program. If not, see <http://www.gnu.org/licenses/>.
1717
18import argparse18import argparse
19import logging
20import sys19import sys
2120
22import snapcraft.cmds21import snapcraft.cmds
2322from snapcraft import log
24
25_COLOR_BOLD = '\033[1m'
26_COLOR_END = '\033[0m'
2723
2824
29def main():25def main():
30 logging.basicConfig(26 log.configure()
31 format=_COLOR_BOLD + '%(message)s' + _COLOR_END, level=logging.INFO)
32
33 root_parser = argparse.ArgumentParser()27 root_parser = argparse.ArgumentParser()
34 subparsers = root_parser.add_subparsers(dest='cmd')28 subparsers = root_parser.add_subparsers(dest='cmd')
3529
3630
=== added file 'snapcraft/tests/test_log.py'
--- snapcraft/tests/test_log.py 1970-01-01 00:00:00 +0000
+++ snapcraft/tests/test_log.py 2015-07-30 14:52:01 +0000
@@ -0,0 +1,86 @@
1# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
2#
3# Copyright (C) 2015 Canonical Ltd
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License version 3 as
7# published by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17import io
18import logging
19from unittest import mock
20
21from snapcraft import (
22 log,
23 tests
24)
25
26
27@mock.patch('sys.stdout', new_callable=io.StringIO)
28@mock.patch('sys.stderr', new_callable=io.StringIO)
29class LogTestCase(tests.TestCase):
30
31 def test_configure_must_send_messages_to_stdout(
32 self, mock_stderr, mock_stdout):
33 logger_name = self.id()
34 log.configure(logger_name)
35 logger = logging.getLogger(logger_name)
36 # Overwrite the level to log everything.
37 logger.setLevel(logging.DEBUG)
38
39 logger.debug('Test debug')
40 logger.info('Test info')
41 logger.warning('Test warning')
42
43 expected_out = (
44 '\033[1mTest debug\033[0m\n'
45 '\033[1mTest info\033[0m\n'
46 '\033[1mTest warning\033[0m\n')
47 self.assertEqual(expected_out, mock_stdout.getvalue())
48 self.assertEqual('', mock_stderr.getvalue())
49
50 def test_configure_must_send_errors_to_stderr(
51 self, mock_stderr, mock_stdout):
52 logger_name = self.id()
53 log.configure(logger_name)
54 logger = logging.getLogger(logger_name)
55 # Overwrite the level to log everything.
56 logger.setLevel(logging.DEBUG)
57
58 logger.error('Test error')
59 logger.critical('Test critical')
60
61 expected_err = (
62 '\033[1mTest error\033[0m\n'
63 '\033[1mTest critical\033[0m\n')
64 self.assertEqual(expected_err, mock_stderr.getvalue())
65 self.assertEqual('', mock_stdout.getvalue())
66
67 def test_configure_must_log_info_and_higher(
68 self, mock_stderr, mock_stdout):
69 logger_name = self.id()
70 log.configure(logger_name)
71 logger = logging.getLogger(logger_name)
72
73 logger.debug('Test debug')
74 logger.info('Test info')
75 logger.warning('Test warning')
76 logger.error('Test error')
77 logger.critical('Test critical')
78
79 expected_out = (
80 '\033[1mTest info\033[0m\n'
81 '\033[1mTest warning\033[0m\n')
82 expected_err = (
83 '\033[1mTest error\033[0m\n'
84 '\033[1mTest critical\033[0m\n')
85 self.assertEqual(expected_out, mock_stdout.getvalue())
86 self.assertEqual(expected_err, mock_stderr.getvalue())

Subscribers

People subscribed via source and target branches

to all changes: