Test Failed
Push — master ( e380d0...f5671d )
by W
02:58
created

st2common/st2common/logging/misc.py (1 issue)

1
# Licensed to the StackStorm, Inc ('StackStorm') under one or more
2
# contributor license agreements.  See the NOTICE file distributed with
3
# this work for additional information regarding copyright ownership.
4
# The ASF licenses this file to You under the Apache License, Version 2.0
5
# (the "License"); you may not use this file except in compliance with
6
# the License.  You may obtain a copy of the License at
7
#
8
#     http://www.apache.org/licenses/LICENSE-2.0
9
#
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS,
12
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
# See the License for the specific language governing permissions and
14
# limitations under the License.
15
16
from __future__ import absolute_import
17
18
import os.path
19
import logging
20
21
from st2common.logging.filters import LoggerFunctionNameExclusionFilter
22
23
__all__ = [
24
    'reopen_log_files',
25
    'set_log_level_for_all_handlers',
26
    'set_log_level_for_all_loggers'
27
]
28
29
LOG = logging.getLogger(__name__)
30
31
# Because some loggers are just waste of attention span
32
SPECIAL_LOGGERS = {
33
    'swagger_spec_validator.ref_validators': logging.INFO
34
}
35
36
# Log messages for function names which are very spammy and we want to filter out when DEBUG log
37
# level is enabled
38
IGNORED_FUNCTION_NAMES = [
39
    # Used by pyamqp, logs every heartbit tick every 2 ms by default
40
    'heartbeat_tick'
41
]
42
43
44
def reopen_log_files(handlers):
45
    """
46
    This method iterates through all of the providers handlers looking for the FileHandler types.
47
48
    A lock is acquired, the underlying stream closed, reopened, then the lock is released.
49
50
51
    This method should be called when logs are to be rotated by an external process. The simplest
52
    way to do this is via a signal handler.
53
    """
54
    for handler in handlers:
55
        if not isinstance(handler, logging.FileHandler):
56
            continue
57
58
        LOG.info('Re-opening log file "%s" with mode "%s"\n' %
0 ignored issues
show
Coding Style Best Practice introduced by
Specify string format arguments as logging function parameters
Loading history...
59
                 (handler.baseFilename, handler.mode))
60
61
        try:
62
            handler.acquire()
63
            handler.stream.close()
64
            handler.stream = open(handler.baseFilename, handler.mode)
65
        finally:
66
            try:
67
                handler.release()
68
            except RuntimeError as e:
69
                if 'cannot release' in str(e):
70
                    # Release failed which most likely indicates that acquire failed
71
                    # and lock was never acquired
72
                    LOG.warn('Failed to release lock', exc_info=True)
73
                else:
74
                    raise e
75
76
77
def set_log_level_for_all_handlers(logger, level=logging.DEBUG):
78
    """
79
    Set a log level for all the handlers on the provided logger.
80
    """
81
    logger.setLevel(level)
82
83
    handlers = logger.handlers
84
    for handler in handlers:
85
        handler.setLevel(level)
86
87
    return logger
88
89
90
def set_log_level_for_all_loggers(level=logging.DEBUG):
91
    """
92
    Set a log level for all the loggers and handlers to the provided level.
93
    """
94
    root_logger = logging.getLogger()
95
    loggers = list(logging.Logger.manager.loggerDict.values())
96
    loggers += [root_logger]
97
98
    for logger in loggers:
99
        if not isinstance(logger, logging.Logger):
100
            continue
101
102
        if hasattr(logger, 'addFilter'):
103
            logger.addFilter(LoggerFunctionNameExclusionFilter(exclusions=IGNORED_FUNCTION_NAMES))
104
105
        if logger.name in SPECIAL_LOGGERS:
106
            set_log_level_for_all_handlers(logger=logger, level=SPECIAL_LOGGERS.get(logger.name))
107
        else:
108
            set_log_level_for_all_handlers(logger=logger, level=level)
109
110
111
def get_logger_name_for_module(module, exclude_module_name=False):
112
    """
113
    Retrieve fully qualified logger name for current module (e.g. st2common.cmd.sensormanager).
114
115
    :type: ``str``
116
    """
117
    module_file = module.__file__
118
    base_dir = os.path.dirname(os.path.abspath(module_file))
119
    module_name = os.path.basename(module_file)
120
    module_name = module_name.replace('.pyc', '').replace('.py', '')
121
122
    split = base_dir.split(os.path.sep)
123
    split = [component for component in split if component]
124
125
    # Find first component which starts with st2 and use that as a starting point
126
    start_index = 0
127
    for index, component in enumerate(reversed(split)):
128
        if component.startswith('st2'):
129
            start_index = ((len(split) - 1) - index)
130
            break
131
132
    split = split[start_index:]
133
134
    if exclude_module_name:
135
        name = '.'.join(split)
136
    else:
137
        name = '.'.join(split) + '.' + module_name
138
139
    return name
140