blob: 755b2475c6deefac64f37555c01075a813ac2256 [file] [log] [blame]
# -*- coding: utf-8 -*-
# Copyright 2017 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Common functions used by almost of all bisect kit scripts."""
from __future__ import print_function
import argparse
import logging
import logging.config
import os
import sys
from bisect_kit import configure
logger = logging.getLogger(__name__)
DEFAULT_SESSION_BASE = 'bisect.sessions'
DEFAULT_SESSION_NAME = 'default'
DEFAULT_LOG_FILENAME = 'bisect-kit.log'
BISECT_KIT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
common_argument_parser = None
session_optional_parser = None
session_required_parser = None
def determine_session_dir(session):
if not session:
session = DEFAULT_SESSION_NAME
session_dir = os.path.join(DEFAULT_SESSION_BASE, session)
return session_dir
def config_logging(opts):
"""Config logging handlers.
bisect-kit will write full DEBUG level messages to log file and INFO level
messages to console.
If command line argument --session is specified, the log file is stored
inside session directory; otherwise, stored in current working directory.
Args:
opts: An argparse.Namespace to hold command line arguments.
"""
if hasattr(config_logging, 'configured'):
return
config_logging.configured = True
if opts.log_file is None:
if getattr(opts, 'session', None):
session_dir = determine_session_dir(opts.session)
opts.log_file = os.path.join(session_dir, DEFAULT_LOG_FILENAME)
if not os.path.exists(session_dir):
os.makedirs(session_dir)
else:
opts.log_file = DEFAULT_LOG_FILENAME
os.environ['LOG_FILE'] = opts.log_file
if os.path.dirname(opts.log_file):
os.makedirs(os.path.dirname(opts.log_file), exist_ok=True)
print('log file = %s' % opts.log_file, file=sys.stderr)
if getattr(opts, 'debug'):
os.environ['BISECT_KIT_CONSOLE_LOG_LEVEL'] = 'DEBUG'
# By default, top level process, i.e. bisectors, output INFO level
# messages to console.
# Child processes, i.e. switcher and evaluator, output less verbosely ---
# only warnings and errors to console.
console_level = os.environ.get('BISECT_KIT_CONSOLE_LOG_LEVEL', 'INFO')
os.environ['BISECT_KIT_CONSOLE_LOG_LEVEL'] = 'WARNING'
file_handler = {
'class': 'logging.FileHandler',
'level': 'DEBUG',
'formatter': 'verbose',
'filename': opts.log_file,
}
# Rotates default log file to prevent it grows unlimitedly.
if opts.log_file == DEFAULT_LOG_FILENAME:
file_handler.update({
'class': 'logging.handlers.TimedRotatingFileHandler',
'when': 'd',
'backupCount': 2,
})
logging.config.dictConfig({
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '%(asctime)s %(module)s pid=%(process)d %(levelname)s '
'%(message)s'
},
'simple': {
'format': '%(asctime)s %(levelname)s %(message)s',
'datefmt': '%H:%M:%S'
},
},
'handlers': {
'console': {
'level': console_level,
'class': 'logging.StreamHandler',
'formatter': 'simple',
},
'file-log': file_handler,
},
'root': {
'handlers': ['file-log', 'console'],
'level': 'DEBUG',
},
})
def _setup_argument_parsers():
# pylint: disable=global-statement
global common_argument_parser
global session_optional_parser
global session_required_parser
if common_argument_parser:
return # already done
common_argument_parser = argparse.ArgumentParser(add_help=False)
session_optional_parser = argparse.ArgumentParser(add_help=False)
session_required_parser = argparse.ArgumentParser(add_help=False)
common_argument_parser.add_argument(
'--log_file',
metavar='LOG_FILE',
default=configure.get('LOG_FILE'),
help='Override log filename')
common_argument_parser.add_argument(
'--debug', action='store_true', help='Output DEBUG log to console')
common_argument_parser.add_argument(
'--rc',
metavar=configure.CONFIG_ENV_NAME,
help='Specify config file to use. Otherwise searches default '
'locations. Use "none" to suppress config file searching.')
session_optional_parser.add_argument(
'--session',
default=DEFAULT_SESSION_NAME,
help='Session name (default: %(default)r)')
session_required_parser.add_argument(
'--session', required=True, help='Session name')
def init():
configure.load_config()
configure.root.load_plugins()
_setup_argument_parsers()