1# Copyright (c) 2011 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5''' Utility functions and objects for logging.
6'''
7
8import logging
9import sys
10
11class StdoutStderrHandler(logging.Handler):
12  ''' Subclass of logging.Handler which outputs to either stdout or stderr
13  based on a threshold level.
14  '''
15
16  def __init__(self, threshold=logging.WARNING, err=sys.stderr, out=sys.stdout):
17    ''' Args:
18          threshold: below this logging level messages are sent to stdout,
19            otherwise they are sent to stderr
20          err: a stream object that error messages are sent to, defaults to
21            sys.stderr
22          out: a stream object that non-error messages are sent to, defaults to
23            sys.stdout
24    '''
25    logging.Handler.__init__(self)
26    self._err = logging.StreamHandler(err)
27    self._out = logging.StreamHandler(out)
28    self._threshold = threshold
29    self._last_was_err = False
30
31  def setLevel(self, lvl):
32    logging.Handler.setLevel(self, lvl)
33    self._err.setLevel(lvl)
34    self._out.setLevel(lvl)
35
36  def setFormatter(self, formatter):
37    logging.Handler.setFormatter(self, formatter)
38    self._err.setFormatter(formatter)
39    self._out.setFormatter(formatter)
40
41  def emit(self, record):
42    if record.levelno < self._threshold:
43      self._out.emit(record)
44      self._last_was_err = False
45    else:
46      self._err.emit(record)
47      self._last_was_err = False
48
49  def flush(self):
50    # preserve order on the flushing, the stalest stream gets flushed first
51    if self._last_was_err:
52      self._out.flush()
53      self._err.flush()
54    else:
55      self._err.flush()
56      self._out.flush()
57
58
59FORMAT = "%(asctime)s %(filename)s [%(levelname)s] %(message)s"
60DATEFMT = "%H:%M:%S"
61
62def config_root(level=logging.INFO, threshold=logging.WARNING, format=FORMAT,
63         datefmt=DATEFMT):
64  ''' Configure the root logger to use a StdoutStderrHandler and some default
65  formatting.
66    Args:
67      level: messages below this level are ignored
68      threshold: below this logging level messages are sent to stdout,
69        otherwise they are sent to stderr
70      format: format for log messages, see logger.Format
71      datefmt: format for date in log messages
72
73  '''
74  # to set the handler of the root logging object, we need to do setup
75  # manually rather than using basicConfig
76  root = logging.getLogger()
77  root.setLevel(level)
78  formatter = logging.Formatter(format, datefmt)
79  handler = StdoutStderrHandler(threshold=threshold)
80  handler.setLevel(level)
81  handler.setFormatter(formatter)
82  root.addHandler(handler)
83