1dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org) 2dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# 3dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# Redistribution and use in source and binary forms, with or without 4dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# modification, are permitted provided that the following conditions 5dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# are met: 6dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# 1. Redistributions of source code must retain the above copyright 7dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# notice, this list of conditions and the following disclaimer. 8dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# 2. Redistributions in binary form must reproduce the above copyright 9dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# notice, this list of conditions and the following disclaimer in the 10dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# documentation and/or other materials provided with the distribution. 11dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# 12dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND 13dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR 16dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 17dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 18dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 19dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 20dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 21dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 23dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block"""Supports webkitpy logging.""" 24dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 25dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# FIXME: Move this file to webkitpy/python24 since logging needs to 26dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# be configured prior to running version-checking code. 27dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 28dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockimport logging 29dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockimport os 30dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockimport sys 31dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 32dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockimport webkitpy 33dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 34dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 35dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block_log = logging.getLogger(__name__) 36dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 37dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# We set these directory paths lazily in get_logger() below. 38dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block_scripts_dir = "" 39dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block"""The normalized, absolute path to the ...Scripts directory.""" 40dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 41dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block_webkitpy_dir = "" 42dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block"""The normalized, absolute path to the ...Scripts/webkitpy directory.""" 43dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 44dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 45dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockdef _normalize_path(path): 46dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block """Return the given path normalized. 47dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 48dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block Converts a path to an absolute path, removes any trailing slashes, 49dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block removes any extension, and lower-cases it. 50dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 51dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block """ 52dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block path = os.path.abspath(path) 53dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block path = os.path.normpath(path) 54dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block path = os.path.splitext(path)[0] # Remove the extension, if any. 55dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block path = path.lower() 56dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 57dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return path 58dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 59dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 60dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# Observe that the implementation of this function does not require 61dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# the use of any hard-coded strings like "webkitpy", etc. 62dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# 63dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# The main benefit this function has over using-- 64dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# 65dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# _log = logging.getLogger(__name__) 66dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# 67dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# is that get_logger() returns the same value even if __name__ is 68dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# "__main__" -- i.e. even if the module is the script being executed 69dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block# from the command-line. 70dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockdef get_logger(path): 71dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block """Return a logging.logger for the given path. 72dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 73dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block Returns: 74dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block A logger whose name is the name of the module corresponding to 75dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block the given path. If the module is in webkitpy, the name is 76dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block the fully-qualified dotted module name beginning with webkitpy.... 77dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block Otherwise, the name is the base name of the module (i.e. without 78dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block any dotted module name prefix). 79dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 80dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block Args: 81dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block path: The path of the module. Normally, this parameter should be 82dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block the __file__ variable of the module. 83dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 84dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block Sample usage: 85dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 862fc2651226baac27029e38c9d6ef883fa32084dbSteve Block from webkitpy.common.system import logutils 87dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 88dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block _log = logutils.get_logger(__file__) 89dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 90dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block """ 91dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # Since we assign to _scripts_dir and _webkitpy_dir in this function, 92dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # we need to declare them global. 93dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block global _scripts_dir 94dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block global _webkitpy_dir 95dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 96dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block path = _normalize_path(path) 97dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 98dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # Lazily evaluate _webkitpy_dir and _scripts_dir. 99dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if not _scripts_dir: 100dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # The normalized, absolute path to ...Scripts/webkitpy/__init__. 101dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block webkitpy_path = _normalize_path(webkitpy.__file__) 102dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 103dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block _webkitpy_dir = os.path.split(webkitpy_path)[0] 104dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block _scripts_dir = os.path.split(_webkitpy_dir)[0] 105dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 106dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if path.startswith(_webkitpy_dir): 107dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # Remove the initial Scripts directory portion, so the path 108dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # starts with /webkitpy, for example "/webkitpy/init/logutils". 109dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block path = path[len(_scripts_dir):] 110dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 111dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block parts = [] 112dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block while True: 113dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block (path, tail) = os.path.split(path) 114dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if not tail: 115dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block break 116dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block parts.insert(0, tail) 117dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 118dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block logger_name = ".".join(parts) # For example, webkitpy.common.system.logutils. 119dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block else: 120dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # The path is outside of webkitpy. Default to the basename 121dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # without the extension. 122dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block basename = os.path.basename(path) 123dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block logger_name = os.path.splitext(basename)[0] 124dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 125dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return logging.getLogger(logger_name) 126dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 127dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 128dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockdef _default_handlers(stream): 129dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block """Return a list of the default logging handlers to use. 130dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 131dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block Args: 132dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block stream: See the configure_logging() docstring. 133dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 134dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block """ 135dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # Create the filter. 136dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block def should_log(record): 137dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block """Return whether a logging.LogRecord should be logged.""" 138dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # FIXME: Enable the logging of autoinstall messages once 139dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # autoinstall is adjusted. Currently, autoinstall logs 140dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # INFO messages when importing already-downloaded packages, 141dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # which is too verbose. 142dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if record.name.startswith("webkitpy.thirdparty.autoinstall"): 143dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return False 144dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return True 145dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 146dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block logging_filter = logging.Filter() 147dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block logging_filter.filter = should_log 148dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 149dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # Create the handler. 150dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block handler = logging.StreamHandler(stream) 151dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block formatter = logging.Formatter("%(name)s: [%(levelname)s] %(message)s") 152dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block handler.setFormatter(formatter) 153dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block handler.addFilter(logging_filter) 154dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 155dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return [handler] 156dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 157dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 158dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockdef configure_logging(logging_level=None, logger=None, stream=None, 159dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block handlers=None): 160dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block """Configure logging for standard purposes. 161dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 162dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block Returns: 163dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block A list of references to the logging handlers added to the root 164dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block logger. This allows the caller to later remove the handlers 165dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block using logger.removeHandler. This is useful primarily during unit 166dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block testing where the caller may want to configure logging temporarily 167dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block and then undo the configuring. 168dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 169dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block Args: 170dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block logging_level: The minimum logging level to log. Defaults to 171dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block logging.INFO. 172dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block logger: A logging.logger instance to configure. This parameter 173dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block should be used only in unit tests. Defaults to the 174dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block root logger. 175dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block stream: A file-like object to which to log used in creating the default 176dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block handlers. The stream must define an "encoding" data attribute, 177dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block or else logging raises an error. Defaults to sys.stderr. 178dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block handlers: A list of logging.Handler instances to add to the logger 179dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block being configured. If this parameter is provided, then the 180dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block stream parameter is not used. 181dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 182dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block """ 183dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # If the stream does not define an "encoding" data attribute, the 184dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # logging module can throw an error like the following: 185dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # 186dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # Traceback (most recent call last): 187dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # File "/System/Library/Frameworks/Python.framework/Versions/2.6/... 188dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # lib/python2.6/logging/__init__.py", line 761, in emit 189dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # self.stream.write(fs % msg.encode(self.stream.encoding)) 190dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block # LookupError: unknown encoding: unknown 191dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if logging_level is None: 192dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block logging_level = logging.INFO 193dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if logger is None: 194dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block logger = logging.getLogger() 195dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if stream is None: 196dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block stream = sys.stderr 197dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if handlers is None: 198dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block handlers = _default_handlers(stream) 199dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 200dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block logger.setLevel(logging_level) 201dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 202dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block for handler in handlers: 203dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block logger.addHandler(handler) 204dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 205dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block _log.debug("Debug logging enabled.") 206dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 207dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return handlers 208