1 # Copyright 2020 The Pigweed Authors
3 # Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 # use this file except in compliance with the License. You may obtain a copy of
7 # https://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 # License for the specific language governing permissions and limitations under
14 """Configure the system logger for the default pw command log format."""
17 from pathlib import Path
18 from typing import NamedTuple, Union
24 # Log level used for captured output of a subprocess run through pw.
28 class LogLevel(NamedTuple):
35 # Shorten all the log levels to 3 characters for column-aligned logs.
36 # Color the logs using ANSI codes.
38 LogLevel(logging.CRITICAL, 'bold_red', 'CRT', '☠️ '),
39 LogLevel(logging.ERROR, 'red', 'ERR', '❌'),
40 LogLevel(logging.WARNING, 'yellow', 'WRN', '⚠️ '),
41 LogLevel(logging.INFO, 'magenta', 'INF', 'ℹ️ '),
42 LogLevel(LOGLEVEL_STDOUT, 'cyan', 'OUT', '💬'),
43 LogLevel(logging.DEBUG, 'blue', 'DBG', '👾'),
46 _LOG = logging.getLogger(__name__)
47 _STDERR_HANDLER = logging.StreamHandler()
51 """Show how logs look at various levels."""
53 # Force the log level to make sure all logs are shown.
54 _LOG.setLevel(logging.DEBUG)
56 # Log one message for every log level.
57 _LOG.critical('Something terrible has happened!')
58 _LOG.error('There was an error on our last operation')
59 _LOG.warning('Looks like something is amiss; consider investigating')
60 _LOG.info('The operation went as expected')
61 _LOG.log(LOGLEVEL_STDOUT, 'Standard output of subprocess')
62 _LOG.debug('Adding 1 to i')
65 def install(level: int = logging.INFO,
66 use_color: bool = None,
67 hide_timestamp: bool = False,
68 log_file: Union[str, Path] = None) -> None:
69 """Configure the system logger for the default pw command log format."""
71 colors = pw_cli.color.colors(use_color)
73 env = pw_cli.env.pigweed_environment()
74 if env.PW_SUBPROCESS or hide_timestamp:
75 # If the logger is being run in the context of a pw subprocess, the
76 # time and date are omitted (since pw_cli.process will provide them).
79 # This applies a gray background to the time to make the log lines
80 # distinct from other input, in a way that's easier to see than plain
82 timestamp_fmt = colors.black_on_white('%(asctime)s') + ' '
84 # Set log level on root logger to debug, otherwise any higher levels
85 # elsewhere are ignored.
86 root = logging.getLogger()
87 root.setLevel(logging.DEBUG)
89 handler = logging.FileHandler(log_file) if log_file else _STDERR_HANDLER
90 handler.setLevel(level)
92 logging.Formatter(timestamp_fmt + '%(levelname)s %(message)s',
94 root.addHandler(handler)
98 colorize = lambda ll: str
101 colorize = lambda ll: getattr(colors, ll.color)
103 for log_level in _LOG_LEVELS:
104 name = getattr(log_level, name_attr)
105 logging.addLevelName(log_level.level, colorize(log_level)(name))
108 def set_level(log_level: int):
109 """Sets the log level for logs to stderr."""
110 _STDERR_HANDLER.setLevel(log_level)
113 if __name__ == '__main__':