1*2d57dc69SVladimir Kotal# 2*2d57dc69SVladimir Kotal# CDDL HEADER START 3*2d57dc69SVladimir Kotal# 4*2d57dc69SVladimir Kotal# The contents of this file are subject to the terms of the 5*2d57dc69SVladimir Kotal# Common Development and Distribution License (the "License"). 6*2d57dc69SVladimir Kotal# You may not use this file except in compliance with the License. 7*2d57dc69SVladimir Kotal# 8*2d57dc69SVladimir Kotal# See LICENSE.txt included in this distribution for the specific 9*2d57dc69SVladimir Kotal# language governing permissions and limitations under the License. 10*2d57dc69SVladimir Kotal# 11*2d57dc69SVladimir Kotal# When distributing Covered Code, include this CDDL HEADER in each 12*2d57dc69SVladimir Kotal# file and include the License file at LICENSE.txt. 13*2d57dc69SVladimir Kotal# If applicable, add the following below this CDDL HEADER, with the 14*2d57dc69SVladimir Kotal# fields enclosed by brackets "[]" replaced with your own identifying 15*2d57dc69SVladimir Kotal# information: Portions Copyright [yyyy] [name of copyright owner] 16*2d57dc69SVladimir Kotal# 17*2d57dc69SVladimir Kotal# CDDL HEADER END 18*2d57dc69SVladimir Kotal# 19*2d57dc69SVladimir Kotal 20*2d57dc69SVladimir Kotal# 21*2d57dc69SVladimir Kotal# Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. 22*2d57dc69SVladimir Kotal# 23*2d57dc69SVladimir Kotal 24*2d57dc69SVladimir Kotalimport logging 25*2d57dc69SVladimir Kotalimport sys 26*2d57dc69SVladimir Kotalimport os 27*2d57dc69SVladimir Kotalimport argparse 28*2d57dc69SVladimir Kotalfrom logging.handlers import RotatingFileHandler 29*2d57dc69SVladimir Kotalfrom .exitvals import ( 30*2d57dc69SVladimir Kotal FAILURE_EXITVAL, 31*2d57dc69SVladimir Kotal) 32*2d57dc69SVladimir Kotal 33*2d57dc69SVladimir Kotal 34*2d57dc69SVladimir Kotaldef fatal(msg, exit=True): 35*2d57dc69SVladimir Kotal """ 36*2d57dc69SVladimir Kotal Print message to standard error output and exit 37*2d57dc69SVladimir Kotal unless the exit parameter is False 38*2d57dc69SVladimir Kotal :param msg: message 39*2d57dc69SVladimir Kotal :param exit 40*2d57dc69SVladimir Kotal """ 41*2d57dc69SVladimir Kotal print(msg, file=sys.stderr) 42*2d57dc69SVladimir Kotal if exit: 43*2d57dc69SVladimir Kotal sys.exit(FAILURE_EXITVAL) 44*2d57dc69SVladimir Kotal else: 45*2d57dc69SVladimir Kotal return FAILURE_EXITVAL 46*2d57dc69SVladimir Kotal 47*2d57dc69SVladimir Kotal 48*2d57dc69SVladimir Kotaldef add_log_level_argument(parser): 49*2d57dc69SVladimir Kotal parser.add_argument('-l', '--loglevel', action=LogLevelAction, 50*2d57dc69SVladimir Kotal help='Set log level (e.g. \"ERROR\")', 51*2d57dc69SVladimir Kotal default=logging.INFO) 52*2d57dc69SVladimir Kotal 53*2d57dc69SVladimir Kotal 54*2d57dc69SVladimir Kotalclass LogLevelAction(argparse.Action): 55*2d57dc69SVladimir Kotal """ 56*2d57dc69SVladimir Kotal This class is supposed to be used as action for argparse. 57*2d57dc69SVladimir Kotal The action is handled by trying to find the option argument as attribute 58*2d57dc69SVladimir Kotal in the logging module. On success, its numeric value is stored in the 59*2d57dc69SVladimir Kotal namespace, otherwise ValueError exception is thrown. 60*2d57dc69SVladimir Kotal """ 61*2d57dc69SVladimir Kotal def __init__(self, option_strings, dest, nargs=None, **kwargs): 62*2d57dc69SVladimir Kotal if nargs is not None: 63*2d57dc69SVladimir Kotal raise ValueError("nargs not allowed") 64*2d57dc69SVladimir Kotal super(LogLevelAction, self).__init__(option_strings, dest, **kwargs) 65*2d57dc69SVladimir Kotal 66*2d57dc69SVladimir Kotal def __call__(self, parser, namespace, values, option_string=None): 67*2d57dc69SVladimir Kotal # print('%r %r %r' % (namespace, values, option_string)) 68*2d57dc69SVladimir Kotal val = get_log_level(values) 69*2d57dc69SVladimir Kotal if val: 70*2d57dc69SVladimir Kotal setattr(namespace, self.dest, val) 71*2d57dc69SVladimir Kotal else: 72*2d57dc69SVladimir Kotal raise ValueError("invalid log level '{}'".format(values)) 73*2d57dc69SVladimir Kotal 74*2d57dc69SVladimir Kotal 75*2d57dc69SVladimir Kotaldef get_log_level(level): 76*2d57dc69SVladimir Kotal """ 77*2d57dc69SVladimir Kotal :param level: expressed in string (upper or lower case) or integer 78*2d57dc69SVladimir Kotal :return: integer representation of the log level or None 79*2d57dc69SVladimir Kotal """ 80*2d57dc69SVladimir Kotal if type(level) is int: 81*2d57dc69SVladimir Kotal return level 82*2d57dc69SVladimir Kotal 83*2d57dc69SVladimir Kotal # This could be a string storing a number. 84*2d57dc69SVladimir Kotal try: 85*2d57dc69SVladimir Kotal return int(level) 86*2d57dc69SVladimir Kotal except ValueError: 87*2d57dc69SVladimir Kotal pass 88*2d57dc69SVladimir Kotal 89*2d57dc69SVladimir Kotal # Look up the name in the logging module. 90*2d57dc69SVladimir Kotal try: 91*2d57dc69SVladimir Kotal value = getattr(logging, level.upper()) 92*2d57dc69SVladimir Kotal if type(value) is int: 93*2d57dc69SVladimir Kotal return value 94*2d57dc69SVladimir Kotal else: 95*2d57dc69SVladimir Kotal return None 96*2d57dc69SVladimir Kotal except AttributeError: 97*2d57dc69SVladimir Kotal return None 98*2d57dc69SVladimir Kotal 99*2d57dc69SVladimir Kotal 100*2d57dc69SVladimir Kotaldef get_class_basename(): 101*2d57dc69SVladimir Kotal return __name__.split('.')[0] 102*2d57dc69SVladimir Kotal 103*2d57dc69SVladimir Kotal 104*2d57dc69SVladimir Kotaldef get_console_logger(name=__name__, level=logging.INFO, 105*2d57dc69SVladimir Kotal format='%(message)s'): 106*2d57dc69SVladimir Kotal """ 107*2d57dc69SVladimir Kotal Get logger that logs logging.ERROR and higher to stderr, the rest 108*2d57dc69SVladimir Kotal to stdout. For logging.DEBUG level more verbose format is used. 109*2d57dc69SVladimir Kotal 110*2d57dc69SVladimir Kotal :param name: name of the logger 111*2d57dc69SVladimir Kotal :param level: base logging level 112*2d57dc69SVladimir Kotal :param format: format string to use 113*2d57dc69SVladimir Kotal :return: logger 114*2d57dc69SVladimir Kotal """ 115*2d57dc69SVladimir Kotal if level is None: 116*2d57dc69SVladimir Kotal level = logging.INFO 117*2d57dc69SVladimir Kotal 118*2d57dc69SVladimir Kotal if level == logging.DEBUG: 119*2d57dc69SVladimir Kotal format = '%(asctime)s %(levelname)8s %(name)s | %(message)s' 120*2d57dc69SVladimir Kotal 121*2d57dc69SVladimir Kotal formatter = logging.Formatter(format) 122*2d57dc69SVladimir Kotal 123*2d57dc69SVladimir Kotal stderr_handler = logging.StreamHandler(stream=sys.stderr) 124*2d57dc69SVladimir Kotal stderr_handler.setFormatter(formatter) 125*2d57dc69SVladimir Kotal 126*2d57dc69SVladimir Kotal stdout_handler = logging.StreamHandler(stream=sys.stdout) 127*2d57dc69SVladimir Kotal stdout_handler.setFormatter(formatter) 128*2d57dc69SVladimir Kotal 129*2d57dc69SVladimir Kotal stderr_handler.addFilter(lambda rec: rec.levelno >= logging.ERROR) 130*2d57dc69SVladimir Kotal stdout_handler.addFilter(lambda rec: rec.levelno < logging.ERROR) 131*2d57dc69SVladimir Kotal 132*2d57dc69SVladimir Kotal logger = logging.getLogger(name) 133*2d57dc69SVladimir Kotal logger.setLevel(level) 134*2d57dc69SVladimir Kotal logger.propagate = False 135*2d57dc69SVladimir Kotal logger.handlers = [] 136*2d57dc69SVladimir Kotal logger.addHandler(stdout_handler) 137*2d57dc69SVladimir Kotal logger.addHandler(stderr_handler) 138*2d57dc69SVladimir Kotal 139*2d57dc69SVladimir Kotal return logger 140*2d57dc69SVladimir Kotal 141*2d57dc69SVladimir Kotal 142*2d57dc69SVladimir Kotaldef get_batch_logger(logdir, project_name, loglevel, backupcount, 143*2d57dc69SVladimir Kotal name=__name__): 144*2d57dc69SVladimir Kotal """ 145*2d57dc69SVladimir Kotal Get rotating file logger for storing logs of mirroring of given project. 146*2d57dc69SVladimir Kotal :param logdir: log directory 147*2d57dc69SVladimir Kotal :param project_name: name of the project 148*2d57dc69SVladimir Kotal :param loglevel: logging level 149*2d57dc69SVladimir Kotal :param backupcount count of log files to keep around 150*2d57dc69SVladimir Kotal :param name name of the logger 151*2d57dc69SVladimir Kotal :return logger 152*2d57dc69SVladimir Kotal """ 153*2d57dc69SVladimir Kotal 154*2d57dc69SVladimir Kotal logger = logging.getLogger(name) 155*2d57dc69SVladimir Kotal 156*2d57dc69SVladimir Kotal logfile = os.path.join(logdir, project_name + ".log") 157*2d57dc69SVladimir Kotal 158*2d57dc69SVladimir Kotal handler = RotatingFileHandler(logfile, maxBytes=0, mode='a', 159*2d57dc69SVladimir Kotal backupCount=backupcount) 160*2d57dc69SVladimir Kotal formatter = logging.Formatter("%(asctime)s - %(levelname)s: " 161*2d57dc69SVladimir Kotal "%(message)s", '%m/%d/%Y %I:%M:%S %p') 162*2d57dc69SVladimir Kotal handler.setFormatter(formatter) 163*2d57dc69SVladimir Kotal handler.doRollover() 164*2d57dc69SVladimir Kotal 165*2d57dc69SVladimir Kotal logger.setLevel(loglevel) 166*2d57dc69SVladimir Kotal logger.propagate = False 167*2d57dc69SVladimir Kotal logger.handlers = [] 168*2d57dc69SVladimir Kotal logger.addHandler(handler) 169*2d57dc69SVladimir Kotal 170*2d57dc69SVladimir Kotal return logger 171