xref: /OpenGrok/tools/src/main/python/opengrok_tools/utils/log.py (revision b33822c50ce6634de1822d15498d494b6e728c2f)
12d57dc69SVladimir Kotal#
22d57dc69SVladimir Kotal# CDDL HEADER START
32d57dc69SVladimir Kotal#
42d57dc69SVladimir Kotal# The contents of this file are subject to the terms of the
52d57dc69SVladimir Kotal# Common Development and Distribution License (the "License").
62d57dc69SVladimir Kotal# You may not use this file except in compliance with the License.
72d57dc69SVladimir Kotal#
82d57dc69SVladimir Kotal# See LICENSE.txt included in this distribution for the specific
92d57dc69SVladimir Kotal# language governing permissions and limitations under the License.
102d57dc69SVladimir Kotal#
112d57dc69SVladimir Kotal# When distributing Covered Code, include this CDDL HEADER in each
122d57dc69SVladimir Kotal# file and include the License file at LICENSE.txt.
132d57dc69SVladimir Kotal# If applicable, add the following below this CDDL HEADER, with the
142d57dc69SVladimir Kotal# fields enclosed by brackets "[]" replaced with your own identifying
152d57dc69SVladimir Kotal# information: Portions Copyright [yyyy] [name of copyright owner]
162d57dc69SVladimir Kotal#
172d57dc69SVladimir Kotal# CDDL HEADER END
182d57dc69SVladimir Kotal#
192d57dc69SVladimir Kotal
202d57dc69SVladimir Kotal#
21*b33822c5SVladimir Kotal# Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
222d57dc69SVladimir Kotal#
232d57dc69SVladimir Kotal
242d57dc69SVladimir Kotalimport logging
252d57dc69SVladimir Kotalimport sys
262d57dc69SVladimir Kotalimport os
272d57dc69SVladimir Kotalimport argparse
282d57dc69SVladimir Kotalfrom logging.handlers import RotatingFileHandler
292d57dc69SVladimir Kotalfrom .exitvals import (
302d57dc69SVladimir Kotal    FAILURE_EXITVAL,
312d57dc69SVladimir Kotal)
322d57dc69SVladimir Kotal
332d57dc69SVladimir Kotal
342d57dc69SVladimir Kotaldef fatal(msg, exit=True):
352d57dc69SVladimir Kotal    """
362d57dc69SVladimir Kotal    Print message to standard error output and exit
372d57dc69SVladimir Kotal    unless the exit parameter is False
382d57dc69SVladimir Kotal    :param msg: message
392d57dc69SVladimir Kotal    :param exit
402d57dc69SVladimir Kotal    """
412d57dc69SVladimir Kotal    print(msg, file=sys.stderr)
422d57dc69SVladimir Kotal    if exit:
432d57dc69SVladimir Kotal        sys.exit(FAILURE_EXITVAL)
442d57dc69SVladimir Kotal    else:
452d57dc69SVladimir Kotal        return FAILURE_EXITVAL
462d57dc69SVladimir Kotal
472d57dc69SVladimir Kotal
482d57dc69SVladimir Kotaldef add_log_level_argument(parser):
492d57dc69SVladimir Kotal    parser.add_argument('-l', '--loglevel', action=LogLevelAction,
502d57dc69SVladimir Kotal                        help='Set log level (e.g. \"ERROR\")',
51*b33822c5SVladimir Kotal                        default="INFO")
522d57dc69SVladimir Kotal
532d57dc69SVladimir Kotal
542d57dc69SVladimir Kotalclass LogLevelAction(argparse.Action):
552d57dc69SVladimir Kotal    """
562d57dc69SVladimir Kotal    This class is supposed to be used as action for argparse.
572d57dc69SVladimir Kotal    The action is handled by trying to find the option argument as attribute
582d57dc69SVladimir Kotal    in the logging module. On success, its numeric value is stored in the
592d57dc69SVladimir Kotal    namespace, otherwise ValueError exception is thrown.
602d57dc69SVladimir Kotal    """
612d57dc69SVladimir Kotal    def __init__(self, option_strings, dest, nargs=None, **kwargs):
622d57dc69SVladimir Kotal        if nargs is not None:
632d57dc69SVladimir Kotal            raise ValueError("nargs not allowed")
642d57dc69SVladimir Kotal        super(LogLevelAction, self).__init__(option_strings, dest, **kwargs)
652d57dc69SVladimir Kotal
662d57dc69SVladimir Kotal    def __call__(self, parser, namespace, values, option_string=None):
672d57dc69SVladimir Kotal        # print('%r %r %r' % (namespace, values, option_string))
682d57dc69SVladimir Kotal        val = get_log_level(values)
692d57dc69SVladimir Kotal        if val:
702d57dc69SVladimir Kotal            setattr(namespace, self.dest, val)
712d57dc69SVladimir Kotal        else:
722d57dc69SVladimir Kotal            raise ValueError("invalid log level '{}'".format(values))
732d57dc69SVladimir Kotal
742d57dc69SVladimir Kotal
752d57dc69SVladimir Kotaldef get_log_level(level):
762d57dc69SVladimir Kotal    """
772d57dc69SVladimir Kotal    :param level: expressed in string (upper or lower case) or integer
782d57dc69SVladimir Kotal    :return: integer representation of the log level or None
792d57dc69SVladimir Kotal    """
802d57dc69SVladimir Kotal    if type(level) is int:
812d57dc69SVladimir Kotal        return level
822d57dc69SVladimir Kotal
832d57dc69SVladimir Kotal    # This could be a string storing a number.
842d57dc69SVladimir Kotal    try:
852d57dc69SVladimir Kotal        return int(level)
862d57dc69SVladimir Kotal    except ValueError:
872d57dc69SVladimir Kotal        pass
882d57dc69SVladimir Kotal
892d57dc69SVladimir Kotal    # Look up the name in the logging module.
902d57dc69SVladimir Kotal    try:
912d57dc69SVladimir Kotal        value = getattr(logging, level.upper())
922d57dc69SVladimir Kotal        if type(value) is int:
932d57dc69SVladimir Kotal            return value
942d57dc69SVladimir Kotal        else:
952d57dc69SVladimir Kotal            return None
962d57dc69SVladimir Kotal    except AttributeError:
972d57dc69SVladimir Kotal        return None
982d57dc69SVladimir Kotal
992d57dc69SVladimir Kotal
1002d57dc69SVladimir Kotaldef get_class_basename():
1012d57dc69SVladimir Kotal    return __name__.split('.')[0]
1022d57dc69SVladimir Kotal
1032d57dc69SVladimir Kotal
1042d57dc69SVladimir Kotaldef get_console_logger(name=__name__, level=logging.INFO,
1052d57dc69SVladimir Kotal                       format='%(message)s'):
1062d57dc69SVladimir Kotal    """
1072d57dc69SVladimir Kotal    Get logger that logs logging.ERROR and higher to stderr, the rest
1082d57dc69SVladimir Kotal    to stdout. For logging.DEBUG level more verbose format is used.
1092d57dc69SVladimir Kotal
1102d57dc69SVladimir Kotal    :param name: name of the logger
1112d57dc69SVladimir Kotal    :param level: base logging level
1122d57dc69SVladimir Kotal    :param format: format string to use
1132d57dc69SVladimir Kotal    :return: logger
1142d57dc69SVladimir Kotal    """
1152d57dc69SVladimir Kotal    if level is None:
1162d57dc69SVladimir Kotal        level = logging.INFO
1172d57dc69SVladimir Kotal
1182d57dc69SVladimir Kotal    if level == logging.DEBUG:
1192d57dc69SVladimir Kotal        format = '%(asctime)s %(levelname)8s %(name)s | %(message)s'
1202d57dc69SVladimir Kotal
1212d57dc69SVladimir Kotal    formatter = logging.Formatter(format)
1222d57dc69SVladimir Kotal
1232d57dc69SVladimir Kotal    stderr_handler = logging.StreamHandler(stream=sys.stderr)
1242d57dc69SVladimir Kotal    stderr_handler.setFormatter(formatter)
1252d57dc69SVladimir Kotal
1262d57dc69SVladimir Kotal    stdout_handler = logging.StreamHandler(stream=sys.stdout)
1272d57dc69SVladimir Kotal    stdout_handler.setFormatter(formatter)
1282d57dc69SVladimir Kotal
1292d57dc69SVladimir Kotal    stderr_handler.addFilter(lambda rec: rec.levelno >= logging.ERROR)
1302d57dc69SVladimir Kotal    stdout_handler.addFilter(lambda rec: rec.levelno < logging.ERROR)
1312d57dc69SVladimir Kotal
1322d57dc69SVladimir Kotal    logger = logging.getLogger(name)
1332d57dc69SVladimir Kotal    logger.setLevel(level)
1342d57dc69SVladimir Kotal    logger.propagate = False
1352d57dc69SVladimir Kotal    logger.handlers = []
1362d57dc69SVladimir Kotal    logger.addHandler(stdout_handler)
1372d57dc69SVladimir Kotal    logger.addHandler(stderr_handler)
1382d57dc69SVladimir Kotal
1392d57dc69SVladimir Kotal    return logger
1402d57dc69SVladimir Kotal
1412d57dc69SVladimir Kotal
1422d57dc69SVladimir Kotaldef get_batch_logger(logdir, project_name, loglevel, backupcount,
1432d57dc69SVladimir Kotal                     name=__name__):
1442d57dc69SVladimir Kotal    """
1452d57dc69SVladimir Kotal    Get rotating file logger for storing logs of mirroring of given project.
1462d57dc69SVladimir Kotal    :param logdir: log directory
1472d57dc69SVladimir Kotal    :param project_name: name of the project
1482d57dc69SVladimir Kotal    :param loglevel: logging level
1492d57dc69SVladimir Kotal    :param backupcount count of log files to keep around
1502d57dc69SVladimir Kotal    :param name name of the logger
1512d57dc69SVladimir Kotal    :return logger
1522d57dc69SVladimir Kotal    """
1532d57dc69SVladimir Kotal
1542d57dc69SVladimir Kotal    logger = logging.getLogger(name)
1552d57dc69SVladimir Kotal
1562d57dc69SVladimir Kotal    logfile = os.path.join(logdir, project_name + ".log")
1572d57dc69SVladimir Kotal
1582d57dc69SVladimir Kotal    handler = RotatingFileHandler(logfile, maxBytes=0, mode='a',
1592d57dc69SVladimir Kotal                                  backupCount=backupcount)
1602d57dc69SVladimir Kotal    formatter = logging.Formatter("%(asctime)s - %(levelname)s: "
1612d57dc69SVladimir Kotal                                  "%(message)s", '%m/%d/%Y %I:%M:%S %p')
1622d57dc69SVladimir Kotal    handler.setFormatter(formatter)
1632d57dc69SVladimir Kotal    handler.doRollover()
1642d57dc69SVladimir Kotal
1652d57dc69SVladimir Kotal    logger.setLevel(loglevel)
1662d57dc69SVladimir Kotal    logger.propagate = False
1672d57dc69SVladimir Kotal    logger.handlers = []
1682d57dc69SVladimir Kotal    logger.addHandler(handler)
1692d57dc69SVladimir Kotal
1702d57dc69SVladimir Kotal    return logger
171