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
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 |