xref: /OpenGrok/tools/src/main/python/opengrok_tools/utils/log.py (revision 2d57dc692b4dd10e696ca6922510f6cecded1bfd)
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