15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2011 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)''' Utility functions and objects for logging. 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)''' 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import logging 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class StdoutStderrHandler(logging.Handler): 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ''' Subclass of logging.Handler which outputs to either stdout or stderr 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) based on a threshold level. 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ''' 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, threshold=logging.WARNING, err=sys.stderr, out=sys.stdout): 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ''' Args: 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) threshold: below this logging level messages are sent to stdout, 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) otherwise they are sent to stderr 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err: a stream object that error messages are sent to, defaults to 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sys.stderr 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out: a stream object that non-error messages are sent to, defaults to 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sys.stdout 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ''' 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) logging.Handler.__init__(self) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._err = logging.StreamHandler(err) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._out = logging.StreamHandler(out) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._threshold = threshold 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._last_was_err = False 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def setLevel(self, lvl): 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) logging.Handler.setLevel(self, lvl) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._err.setLevel(lvl) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._out.setLevel(lvl) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def setFormatter(self, formatter): 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) logging.Handler.setFormatter(self, formatter) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._err.setFormatter(formatter) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._out.setFormatter(formatter) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def emit(self, record): 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if record.levelno < self._threshold: 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._out.emit(record) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._last_was_err = False 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._err.emit(record) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._last_was_err = False 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def flush(self): 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # preserve order on the flushing, the stalest stream gets flushed first 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self._last_was_err: 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._out.flush() 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._err.flush() 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._err.flush() 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._out.flush() 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FORMAT = "%(asctime)s %(filename)s [%(levelname)s] %(message)s" 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DATEFMT = "%H:%M:%S" 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def config_root(level=logging.INFO, threshold=logging.WARNING, format=FORMAT, 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) datefmt=DATEFMT): 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ''' Configure the root logger to use a StdoutStderrHandler and some default 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) formatting. 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) level: messages below this level are ignored 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) threshold: below this logging level messages are sent to stdout, 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) otherwise they are sent to stderr 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) format: format for log messages, see logger.Format 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) datefmt: format for date in log messages 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ''' 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # to set the handler of the root logging object, we need to do setup 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # manually rather than using basicConfig 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) root = logging.getLogger() 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) root.setLevel(level) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) formatter = logging.Formatter(format, datefmt) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handler = StdoutStderrHandler(threshold=threshold) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handler.setLevel(level) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handler.setFormatter(formatter) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) root.addHandler(handler) 83