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