We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Incorrect casing for log level config causes errors
Support any case?

Example (EL6),
in `/etc/st2/logging.actionrunner.conf`
if you have
```
[logger_root]
level=debug
```
instead of 
```
[logger_root]
level=DEBUG
```

..this happens
```
$ sudo /opt/stackstorm/st2/bin/python /opt/stackstorm/st2/bin/st2actionrunner --config-file /etc/st2/st2.conf
2017-06-23 11:26:37,074 DEBUG [-] Using config files: /etc/st2/st2.conf
2017-06-23 11:26:37,075 DEBUG [-] Using logging config: /etc/st2/logging.actionrunner.conf
ERROR: Traceback (most recent call last):
  File "/opt/stackstorm/st2/lib/python2.7/site-packages/st2common/log.py", line 186, in setup
    disable_existing_loggers=disable_existing_loggers)
  File "/usr/share/python/st2python/lib/python2.7/logging/config.py", line 85, in fileConfig
    handlers = _install_handlers(cp, formatters)
  File "/usr/share/python/st2python/lib/python2.7/logging/config.py", line 166, in _install_handlers
    h.setLevel(logging._levelNames[level])
KeyError: 'debug'
2017-06-23 11:26:37,077 ERROR [-] (PID=1189) Worker quit due to exception.
Traceback (most recent call last):
  File "/opt/stackstorm/st2/lib/python2.7/site-packages/st2actions/cmd/actionrunner.py", line 81, in main
    _setup()
  File "/opt/stackstorm/st2/lib/python2.7/site-packages/st2actions/cmd/actionrunner.py", line 36, in _setup
    register_signal_handlers=True)
  File "/opt/stackstorm/st2/lib/python2.7/site-packages/st2common/service_setup.py", line 92, in setup
    excludes=cfg.CONF.log.excludes)
  File "/opt/stackstorm/st2/lib/python2.7/site-packages/st2common/log.py", line 196, in setup
    raise Exception(six.text_type(exc))
Exception: 'debug'
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `st2common/st2common/log.py`
Content:
```
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
19 import sys
20 import logging
21 import logging.config
22 import logging.handlers
23 import traceback
24 from functools import wraps
25 
26 import six
27 
28 from st2common.logging.filters import ExclusionFilter
29 
30 # Those are here for backward compatibility reasons
31 from st2common.logging.handlers import FormatNamedFileHandler
32 from st2common.logging.handlers import ConfigurableSyslogHandler
33 from st2common.util.misc import prefix_dict_keys
34 from st2common.util.misc import get_normalized_file_path
35 
36 __all__ = [
37     'getLogger',
38     'setup',
39 
40     'FormatNamedFileHandler',
41     'ConfigurableSyslogHandler',
42 
43     'LoggingStream'
44 ]
45 
46 logging.AUDIT = logging.CRITICAL + 10
47 logging.addLevelName(logging.AUDIT, 'AUDIT')
48 
49 LOGGER_KEYS = [
50     'debug',
51     'info',
52     'warning',
53     'error',
54     'critical',
55     'exception',
56     'log',
57 
58     'audit'
59 ]
60 
61 # Note: This attribute is used by "find_caller" so it can correctly exclude this file when looking
62 # for the logger method caller frame.
63 _srcfile = get_normalized_file_path(__file__)
64 
65 
66 def find_caller():
67     """
68     Find the stack frame of the caller so that we can note the source file name, line number and
69     function name.
70 
71     Note: This is based on logging/__init__.py:findCaller and modified so it takes into account
72     this file - https://hg.python.org/cpython/file/2.7/Lib/logging/__init__.py#l1233
73     """
74     rv = '(unknown file)', 0, '(unknown function)'
75 
76     try:
77         f = logging.currentframe().f_back
78         while hasattr(f, 'f_code'):
79             co = f.f_code
80             filename = os.path.normcase(co.co_filename)
81             if filename in (_srcfile, logging._srcfile):  # This line is modified.
82                 f = f.f_back
83                 continue
84             rv = (filename, f.f_lineno, co.co_name)
85             break
86     except Exception:
87         pass
88 
89     return rv
90 
91 
92 def decorate_log_method(func):
93     @wraps(func)
94     def func_wrapper(*args, **kwargs):
95         # Prefix extra keys with underscore
96         if 'extra' in kwargs:
97             kwargs['extra'] = prefix_dict_keys(dictionary=kwargs['extra'], prefix='_')
98 
99         try:
100             return func(*args, **kwargs)
101         except TypeError as e:
102             # In some version of Python 2.7, logger.exception doesn't take any kwargs so we need
103             # this hack :/
104             # See:
105             # - https://docs.python.org/release/2.7.3/library/logging.html#logging.Logger.exception
106             # - https://docs.python.org/release/2.7.7/library/logging.html#logging.Logger.exception
107             if 'got an unexpected keyword argument \'extra\'' in str(e):
108                 kwargs.pop('extra', None)
109                 return func(*args, **kwargs)
110             raise e
111     return func_wrapper
112 
113 
114 def decorate_logger_methods(logger):
115     """
116     Decorate all the logger methods so all the keys in the extra dictionary are
117     automatically prefixed with an underscore to avoid clashes with standard log
118     record attributes.
119     """
120 
121     # Note: We override findCaller with our custom implementation which takes into account this
122     # module.
123     # This way filename, module, funcName and lineno LogRecord attributes contain correct values
124     # instead of all pointing to decorate_log_method.
125     logger.findCaller = find_caller
126     for key in LOGGER_KEYS:
127         log_method = getattr(logger, key)
128         log_method = decorate_log_method(log_method)
129         setattr(logger, key, log_method)
130 
131     return logger
132 
133 
134 def getLogger(name):
135     # make sure that prefix isn't appended multiple times to preserve logging name hierarchy
136     prefix = 'st2.'
137     if name.startswith(prefix):
138         logger = logging.getLogger(name)
139     else:
140         logger_name = '{}{}'.format(prefix, name)
141         logger = logging.getLogger(logger_name)
142 
143     logger = decorate_logger_methods(logger=logger)
144     return logger
145 
146 
147 class LoggingStream(object):
148 
149     def __init__(self, name, level=logging.ERROR):
150         self._logger = getLogger(name)
151         self._level = level
152 
153     def write(self, message):
154         self._logger._log(self._level, message, None)
155 
156     def flush(self):
157         pass
158 
159 
160 def _audit(logger, msg, *args, **kwargs):
161     if logger.isEnabledFor(logging.AUDIT):
162         logger._log(logging.AUDIT, msg, args, **kwargs)
163 
164 
165 logging.Logger.audit = _audit
166 
167 
168 def _add_exclusion_filters(handlers, excludes=None):
169     if excludes:
170         for h in handlers:
171             h.addFilter(ExclusionFilter(excludes))
172 
173 
174 def _redirect_stderr():
175     # It is ok to redirect stderr as none of the st2 handlers write to stderr.
176     sys.stderr = LoggingStream('STDERR')
177 
178 
179 def setup(config_file, redirect_stderr=True, excludes=None, disable_existing_loggers=False):
180     """
181     Configure logging from file.
182     """
183     try:
184         logging.config.fileConfig(config_file,
185                                   defaults=None,
186                                   disable_existing_loggers=disable_existing_loggers)
187         handlers = logging.getLoggerClass().manager.root.handlers
188         _add_exclusion_filters(handlers=handlers, excludes=excludes)
189         if redirect_stderr:
190             _redirect_stderr()
191     except Exception as exc:
192         # revert stderr redirection since there is no logger in place.
193         sys.stderr = sys.__stderr__
194         # No logger yet therefore write to stderr
195         sys.stderr.write('ERROR: %s' % traceback.format_exc())
196         raise Exception(six.text_type(exc))
197
```

Path: `st2common/st2common/service_setup.py`
Content:
```
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 """
17 This module contains common service setup and teardown code.
18 """
19 
20 from __future__ import absolute_import
21 
22 import os
23 
24 from oslo_config import cfg
25 
26 from st2common import log as logging
27 from st2common.constants.logging import DEFAULT_LOGGING_CONF_PATH
28 from st2common.transport.bootstrap_utils import register_exchanges_with_retry
29 from st2common.signal_handlers import register_common_signal_handlers
30 from st2common.util.debugging import enable_debugging
31 from st2common.models.utils.profiling import enable_profiling
32 from st2common import triggers
33 from st2common.rbac.migrations import run_all as run_all_rbac_migrations
34 
35 # Note: This is here for backward compatibility.
36 # Function has been moved in a standalone module to avoid expensive in-direct
37 # import costs
38 from st2common.database_setup import db_setup
39 from st2common.database_setup import db_teardown
40 
41 
42 __all__ = [
43     'setup',
44     'teardown',
45 
46     'db_setup',
47     'db_teardown'
48 ]
49 
50 LOG = logging.getLogger(__name__)
51 
52 
53 def setup(service, config, setup_db=True, register_mq_exchanges=True,
54           register_signal_handlers=True, register_internal_trigger_types=False,
55           run_migrations=True, config_args=None):
56     """
57     Common setup function.
58 
59     Currently it performs the following operations:
60 
61     1. Parses config and CLI arguments
62     2. Establishes DB connection
63     3. Set log level for all the loggers to DEBUG if --debug flag is present or
64        if system.debug config option is set to True.
65     4. Registers RabbitMQ exchanges
66     5. Registers common signal handlers
67     6. Register internal trigger types
68 
69     :param service: Name of the service.
70     :param config: Config object to use to parse args.
71     """
72     # Set up logger which logs everything which happens during and before config
73     # parsing to sys.stdout
74     logging.setup(DEFAULT_LOGGING_CONF_PATH, excludes=None)
75 
76     # Parse args to setup config.
77     if config_args:
78         config.parse_args(config_args)
79     else:
80         config.parse_args()
81 
82     config_file_paths = cfg.CONF.config_file
83     config_file_paths = [os.path.abspath(path) for path in config_file_paths]
84     LOG.debug('Using config files: %s', ','.join(config_file_paths))
85 
86     # Setup logging.
87     logging_config_path = config.get_logging_config_path()
88     logging_config_path = os.path.abspath(logging_config_path)
89 
90     LOG.debug('Using logging config: %s', logging_config_path)
91     logging.setup(logging_config_path, redirect_stderr=cfg.CONF.log.redirect_stderr,
92                   excludes=cfg.CONF.log.excludes)
93 
94     if cfg.CONF.debug or cfg.CONF.system.debug:
95         enable_debugging()
96 
97     if cfg.CONF.profile:
98         enable_profiling()
99 
100     # All other setup which requires config to be parsed and logging to
101     # be correctly setup.
102     if setup_db:
103         db_setup()
104 
105     if register_mq_exchanges:
106         register_exchanges_with_retry()
107 
108     if register_signal_handlers:
109         register_common_signal_handlers()
110 
111     if register_internal_trigger_types:
112         triggers.register_internal_trigger_types()
113 
114     # TODO: This is a "not so nice" workaround until we have a proper migration system in place
115     if run_migrations:
116         run_all_rbac_migrations()
117 
118 
119 def teardown():
120     """
121     Common teardown function.
122     """
123     db_teardown()
124
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/st2common/st2common/log.py b/st2common/st2common/log.py
--- a/st2common/st2common/log.py
+++ b/st2common/st2common/log.py
@@ -189,8 +189,16 @@
         if redirect_stderr:
             _redirect_stderr()
     except Exception as exc:
+        exc_cls = type(exc)
+        tb_msg = traceback.format_exc()
+
+        msg = str(exc)
+        msg += '\n\n' + tb_msg
+
         # revert stderr redirection since there is no logger in place.
         sys.stderr = sys.__stderr__
+
         # No logger yet therefore write to stderr
-        sys.stderr.write('ERROR: %s' % traceback.format_exc())
-        raise Exception(six.text_type(exc))
+        sys.stderr.write('ERROR: %s' % (msg))
+
+        raise exc_cls(six.text_type(msg))
diff --git a/st2common/st2common/service_setup.py b/st2common/st2common/service_setup.py
--- a/st2common/st2common/service_setup.py
+++ b/st2common/st2common/service_setup.py
@@ -20,6 +20,7 @@
 from __future__ import absolute_import
 
 import os
+import traceback
 
 from oslo_config import cfg
 
@@ -88,8 +89,18 @@
     logging_config_path = os.path.abspath(logging_config_path)
 
     LOG.debug('Using logging config: %s', logging_config_path)
-    logging.setup(logging_config_path, redirect_stderr=cfg.CONF.log.redirect_stderr,
-                  excludes=cfg.CONF.log.excludes)
+
+    try:
+        logging.setup(logging_config_path, redirect_stderr=cfg.CONF.log.redirect_stderr,
+                      excludes=cfg.CONF.log.excludes)
+    except KeyError as e:
+        tb_msg = traceback.format_exc()
+        if 'log.setLevel' in tb_msg:
+            msg = 'Invalid log level selected. Log level names need to be all uppercase.'
+            msg += '\n\n' + getattr(e, 'message', str(e))
+            raise KeyError(msg)
+        else:
+            raise e
 
     if cfg.CONF.debug or cfg.CONF.system.debug:
         enable_debugging()

{"golden_diff": "diff --git a/st2common/st2common/log.py b/st2common/st2common/log.py\n--- a/st2common/st2common/log.py\n+++ b/st2common/st2common/log.py\n@@ -189,8 +189,16 @@\n         if redirect_stderr:\n             _redirect_stderr()\n     except Exception as exc:\n+        exc_cls = type(exc)\n+        tb_msg = traceback.format_exc()\n+\n+        msg = str(exc)\n+        msg += '\\n\\n' + tb_msg\n+\n         # revert stderr redirection since there is no logger in place.\n         sys.stderr = sys.__stderr__\n+\n         # No logger yet therefore write to stderr\n-        sys.stderr.write('ERROR: %s' % traceback.format_exc())\n-        raise Exception(six.text_type(exc))\n+        sys.stderr.write('ERROR: %s' % (msg))\n+\n+        raise exc_cls(six.text_type(msg))\ndiff --git a/st2common/st2common/service_setup.py b/st2common/st2common/service_setup.py\n--- a/st2common/st2common/service_setup.py\n+++ b/st2common/st2common/service_setup.py\n@@ -20,6 +20,7 @@\n from __future__ import absolute_import\n \n import os\n+import traceback\n \n from oslo_config import cfg\n \n@@ -88,8 +89,18 @@\n     logging_config_path = os.path.abspath(logging_config_path)\n \n     LOG.debug('Using logging config: %s', logging_config_path)\n-    logging.setup(logging_config_path, redirect_stderr=cfg.CONF.log.redirect_stderr,\n-                  excludes=cfg.CONF.log.excludes)\n+\n+    try:\n+        logging.setup(logging_config_path, redirect_stderr=cfg.CONF.log.redirect_stderr,\n+                      excludes=cfg.CONF.log.excludes)\n+    except KeyError as e:\n+        tb_msg = traceback.format_exc()\n+        if 'log.setLevel' in tb_msg:\n+            msg = 'Invalid log level selected. Log level names need to be all uppercase.'\n+            msg += '\\n\\n' + getattr(e, 'message', str(e))\n+            raise KeyError(msg)\n+        else:\n+            raise e\n \n     if cfg.CONF.debug or cfg.CONF.system.debug:\n         enable_debugging()\n", "issue": "Incorrect casing for log level config causes errors\nSupport any case?\r\n\r\nExample (EL6),\r\nin `/etc/st2/logging.actionrunner.conf`\r\nif you have\r\n```\r\n[logger_root]\r\nlevel=debug\r\n```\r\ninstead of \r\n```\r\n[logger_root]\r\nlevel=DEBUG\r\n```\r\n\r\n..this happens\r\n```\r\n$ sudo /opt/stackstorm/st2/bin/python /opt/stackstorm/st2/bin/st2actionrunner --config-file /etc/st2/st2.conf\r\n2017-06-23 11:26:37,074 DEBUG [-] Using config files: /etc/st2/st2.conf\r\n2017-06-23 11:26:37,075 DEBUG [-] Using logging config: /etc/st2/logging.actionrunner.conf\r\nERROR: Traceback (most recent call last):\r\n  File \"/opt/stackstorm/st2/lib/python2.7/site-packages/st2common/log.py\", line 186, in setup\r\n    disable_existing_loggers=disable_existing_loggers)\r\n  File \"/usr/share/python/st2python/lib/python2.7/logging/config.py\", line 85, in fileConfig\r\n    handlers = _install_handlers(cp, formatters)\r\n  File \"/usr/share/python/st2python/lib/python2.7/logging/config.py\", line 166, in _install_handlers\r\n    h.setLevel(logging._levelNames[level])\r\nKeyError: 'debug'\r\n2017-06-23 11:26:37,077 ERROR [-] (PID=1189) Worker quit due to exception.\r\nTraceback (most recent call last):\r\n  File \"/opt/stackstorm/st2/lib/python2.7/site-packages/st2actions/cmd/actionrunner.py\", line 81, in main\r\n    _setup()\r\n  File \"/opt/stackstorm/st2/lib/python2.7/site-packages/st2actions/cmd/actionrunner.py\", line 36, in _setup\r\n    register_signal_handlers=True)\r\n  File \"/opt/stackstorm/st2/lib/python2.7/site-packages/st2common/service_setup.py\", line 92, in setup\r\n    excludes=cfg.CONF.log.excludes)\r\n  File \"/opt/stackstorm/st2/lib/python2.7/site-packages/st2common/log.py\", line 196, in setup\r\n    raise Exception(six.text_type(exc))\r\nException: 'debug'\r\n```\n", "before_files": [{"content": "# Licensed to the StackStorm, Inc ('StackStorm') under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom __future__ import absolute_import\n\nimport os\nimport sys\nimport logging\nimport logging.config\nimport logging.handlers\nimport traceback\nfrom functools import wraps\n\nimport six\n\nfrom st2common.logging.filters import ExclusionFilter\n\n# Those are here for backward compatibility reasons\nfrom st2common.logging.handlers import FormatNamedFileHandler\nfrom st2common.logging.handlers import ConfigurableSyslogHandler\nfrom st2common.util.misc import prefix_dict_keys\nfrom st2common.util.misc import get_normalized_file_path\n\n__all__ = [\n    'getLogger',\n    'setup',\n\n    'FormatNamedFileHandler',\n    'ConfigurableSyslogHandler',\n\n    'LoggingStream'\n]\n\nlogging.AUDIT = logging.CRITICAL + 10\nlogging.addLevelName(logging.AUDIT, 'AUDIT')\n\nLOGGER_KEYS = [\n    'debug',\n    'info',\n    'warning',\n    'error',\n    'critical',\n    'exception',\n    'log',\n\n    'audit'\n]\n\n# Note: This attribute is used by \"find_caller\" so it can correctly exclude this file when looking\n# for the logger method caller frame.\n_srcfile = get_normalized_file_path(__file__)\n\n\ndef find_caller():\n    \"\"\"\n    Find the stack frame of the caller so that we can note the source file name, line number and\n    function name.\n\n    Note: This is based on logging/__init__.py:findCaller and modified so it takes into account\n    this file - https://hg.python.org/cpython/file/2.7/Lib/logging/__init__.py#l1233\n    \"\"\"\n    rv = '(unknown file)', 0, '(unknown function)'\n\n    try:\n        f = logging.currentframe().f_back\n        while hasattr(f, 'f_code'):\n            co = f.f_code\n            filename = os.path.normcase(co.co_filename)\n            if filename in (_srcfile, logging._srcfile):  # This line is modified.\n                f = f.f_back\n                continue\n            rv = (filename, f.f_lineno, co.co_name)\n            break\n    except Exception:\n        pass\n\n    return rv\n\n\ndef decorate_log_method(func):\n    @wraps(func)\n    def func_wrapper(*args, **kwargs):\n        # Prefix extra keys with underscore\n        if 'extra' in kwargs:\n            kwargs['extra'] = prefix_dict_keys(dictionary=kwargs['extra'], prefix='_')\n\n        try:\n            return func(*args, **kwargs)\n        except TypeError as e:\n            # In some version of Python 2.7, logger.exception doesn't take any kwargs so we need\n            # this hack :/\n            # See:\n            # - https://docs.python.org/release/2.7.3/library/logging.html#logging.Logger.exception\n            # - https://docs.python.org/release/2.7.7/library/logging.html#logging.Logger.exception\n            if 'got an unexpected keyword argument \\'extra\\'' in str(e):\n                kwargs.pop('extra', None)\n                return func(*args, **kwargs)\n            raise e\n    return func_wrapper\n\n\ndef decorate_logger_methods(logger):\n    \"\"\"\n    Decorate all the logger methods so all the keys in the extra dictionary are\n    automatically prefixed with an underscore to avoid clashes with standard log\n    record attributes.\n    \"\"\"\n\n    # Note: We override findCaller with our custom implementation which takes into account this\n    # module.\n    # This way filename, module, funcName and lineno LogRecord attributes contain correct values\n    # instead of all pointing to decorate_log_method.\n    logger.findCaller = find_caller\n    for key in LOGGER_KEYS:\n        log_method = getattr(logger, key)\n        log_method = decorate_log_method(log_method)\n        setattr(logger, key, log_method)\n\n    return logger\n\n\ndef getLogger(name):\n    # make sure that prefix isn't appended multiple times to preserve logging name hierarchy\n    prefix = 'st2.'\n    if name.startswith(prefix):\n        logger = logging.getLogger(name)\n    else:\n        logger_name = '{}{}'.format(prefix, name)\n        logger = logging.getLogger(logger_name)\n\n    logger = decorate_logger_methods(logger=logger)\n    return logger\n\n\nclass LoggingStream(object):\n\n    def __init__(self, name, level=logging.ERROR):\n        self._logger = getLogger(name)\n        self._level = level\n\n    def write(self, message):\n        self._logger._log(self._level, message, None)\n\n    def flush(self):\n        pass\n\n\ndef _audit(logger, msg, *args, **kwargs):\n    if logger.isEnabledFor(logging.AUDIT):\n        logger._log(logging.AUDIT, msg, args, **kwargs)\n\n\nlogging.Logger.audit = _audit\n\n\ndef _add_exclusion_filters(handlers, excludes=None):\n    if excludes:\n        for h in handlers:\n            h.addFilter(ExclusionFilter(excludes))\n\n\ndef _redirect_stderr():\n    # It is ok to redirect stderr as none of the st2 handlers write to stderr.\n    sys.stderr = LoggingStream('STDERR')\n\n\ndef setup(config_file, redirect_stderr=True, excludes=None, disable_existing_loggers=False):\n    \"\"\"\n    Configure logging from file.\n    \"\"\"\n    try:\n        logging.config.fileConfig(config_file,\n                                  defaults=None,\n                                  disable_existing_loggers=disable_existing_loggers)\n        handlers = logging.getLoggerClass().manager.root.handlers\n        _add_exclusion_filters(handlers=handlers, excludes=excludes)\n        if redirect_stderr:\n            _redirect_stderr()\n    except Exception as exc:\n        # revert stderr redirection since there is no logger in place.\n        sys.stderr = sys.__stderr__\n        # No logger yet therefore write to stderr\n        sys.stderr.write('ERROR: %s' % traceback.format_exc())\n        raise Exception(six.text_type(exc))\n", "path": "st2common/st2common/log.py"}, {"content": "# Licensed to the StackStorm, Inc ('StackStorm') under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"\nThis module contains common service setup and teardown code.\n\"\"\"\n\nfrom __future__ import absolute_import\n\nimport os\n\nfrom oslo_config import cfg\n\nfrom st2common import log as logging\nfrom st2common.constants.logging import DEFAULT_LOGGING_CONF_PATH\nfrom st2common.transport.bootstrap_utils import register_exchanges_with_retry\nfrom st2common.signal_handlers import register_common_signal_handlers\nfrom st2common.util.debugging import enable_debugging\nfrom st2common.models.utils.profiling import enable_profiling\nfrom st2common import triggers\nfrom st2common.rbac.migrations import run_all as run_all_rbac_migrations\n\n# Note: This is here for backward compatibility.\n# Function has been moved in a standalone module to avoid expensive in-direct\n# import costs\nfrom st2common.database_setup import db_setup\nfrom st2common.database_setup import db_teardown\n\n\n__all__ = [\n    'setup',\n    'teardown',\n\n    'db_setup',\n    'db_teardown'\n]\n\nLOG = logging.getLogger(__name__)\n\n\ndef setup(service, config, setup_db=True, register_mq_exchanges=True,\n          register_signal_handlers=True, register_internal_trigger_types=False,\n          run_migrations=True, config_args=None):\n    \"\"\"\n    Common setup function.\n\n    Currently it performs the following operations:\n\n    1. Parses config and CLI arguments\n    2. Establishes DB connection\n    3. Set log level for all the loggers to DEBUG if --debug flag is present or\n       if system.debug config option is set to True.\n    4. Registers RabbitMQ exchanges\n    5. Registers common signal handlers\n    6. Register internal trigger types\n\n    :param service: Name of the service.\n    :param config: Config object to use to parse args.\n    \"\"\"\n    # Set up logger which logs everything which happens during and before config\n    # parsing to sys.stdout\n    logging.setup(DEFAULT_LOGGING_CONF_PATH, excludes=None)\n\n    # Parse args to setup config.\n    if config_args:\n        config.parse_args(config_args)\n    else:\n        config.parse_args()\n\n    config_file_paths = cfg.CONF.config_file\n    config_file_paths = [os.path.abspath(path) for path in config_file_paths]\n    LOG.debug('Using config files: %s', ','.join(config_file_paths))\n\n    # Setup logging.\n    logging_config_path = config.get_logging_config_path()\n    logging_config_path = os.path.abspath(logging_config_path)\n\n    LOG.debug('Using logging config: %s', logging_config_path)\n    logging.setup(logging_config_path, redirect_stderr=cfg.CONF.log.redirect_stderr,\n                  excludes=cfg.CONF.log.excludes)\n\n    if cfg.CONF.debug or cfg.CONF.system.debug:\n        enable_debugging()\n\n    if cfg.CONF.profile:\n        enable_profiling()\n\n    # All other setup which requires config to be parsed and logging to\n    # be correctly setup.\n    if setup_db:\n        db_setup()\n\n    if register_mq_exchanges:\n        register_exchanges_with_retry()\n\n    if register_signal_handlers:\n        register_common_signal_handlers()\n\n    if register_internal_trigger_types:\n        triggers.register_internal_trigger_types()\n\n    # TODO: This is a \"not so nice\" workaround until we have a proper migration system in place\n    if run_migrations:\n        run_all_rbac_migrations()\n\n\ndef teardown():\n    \"\"\"\n    Common teardown function.\n    \"\"\"\n    db_teardown()\n", "path": "st2common/st2common/service_setup.py"}], "after_files": [{"content": "# Licensed to the StackStorm, Inc ('StackStorm') under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom __future__ import absolute_import\n\nimport os\nimport sys\nimport logging\nimport logging.config\nimport logging.handlers\nimport traceback\nfrom functools import wraps\n\nimport six\n\nfrom st2common.logging.filters import ExclusionFilter\n\n# Those are here for backward compatibility reasons\nfrom st2common.logging.handlers import FormatNamedFileHandler\nfrom st2common.logging.handlers import ConfigurableSyslogHandler\nfrom st2common.util.misc import prefix_dict_keys\nfrom st2common.util.misc import get_normalized_file_path\n\n__all__ = [\n    'getLogger',\n    'setup',\n\n    'FormatNamedFileHandler',\n    'ConfigurableSyslogHandler',\n\n    'LoggingStream'\n]\n\nlogging.AUDIT = logging.CRITICAL + 10\nlogging.addLevelName(logging.AUDIT, 'AUDIT')\n\nLOGGER_KEYS = [\n    'debug',\n    'info',\n    'warning',\n    'error',\n    'critical',\n    'exception',\n    'log',\n\n    'audit'\n]\n\n# Note: This attribute is used by \"find_caller\" so it can correctly exclude this file when looking\n# for the logger method caller frame.\n_srcfile = get_normalized_file_path(__file__)\n\n\ndef find_caller():\n    \"\"\"\n    Find the stack frame of the caller so that we can note the source file name, line number and\n    function name.\n\n    Note: This is based on logging/__init__.py:findCaller and modified so it takes into account\n    this file - https://hg.python.org/cpython/file/2.7/Lib/logging/__init__.py#l1233\n    \"\"\"\n    rv = '(unknown file)', 0, '(unknown function)'\n\n    try:\n        f = logging.currentframe().f_back\n        while hasattr(f, 'f_code'):\n            co = f.f_code\n            filename = os.path.normcase(co.co_filename)\n            if filename in (_srcfile, logging._srcfile):  # This line is modified.\n                f = f.f_back\n                continue\n            rv = (filename, f.f_lineno, co.co_name)\n            break\n    except Exception:\n        pass\n\n    return rv\n\n\ndef decorate_log_method(func):\n    @wraps(func)\n    def func_wrapper(*args, **kwargs):\n        # Prefix extra keys with underscore\n        if 'extra' in kwargs:\n            kwargs['extra'] = prefix_dict_keys(dictionary=kwargs['extra'], prefix='_')\n\n        try:\n            return func(*args, **kwargs)\n        except TypeError as e:\n            # In some version of Python 2.7, logger.exception doesn't take any kwargs so we need\n            # this hack :/\n            # See:\n            # - https://docs.python.org/release/2.7.3/library/logging.html#logging.Logger.exception\n            # - https://docs.python.org/release/2.7.7/library/logging.html#logging.Logger.exception\n            if 'got an unexpected keyword argument \\'extra\\'' in str(e):\n                kwargs.pop('extra', None)\n                return func(*args, **kwargs)\n            raise e\n    return func_wrapper\n\n\ndef decorate_logger_methods(logger):\n    \"\"\"\n    Decorate all the logger methods so all the keys in the extra dictionary are\n    automatically prefixed with an underscore to avoid clashes with standard log\n    record attributes.\n    \"\"\"\n\n    # Note: We override findCaller with our custom implementation which takes into account this\n    # module.\n    # This way filename, module, funcName and lineno LogRecord attributes contain correct values\n    # instead of all pointing to decorate_log_method.\n    logger.findCaller = find_caller\n    for key in LOGGER_KEYS:\n        log_method = getattr(logger, key)\n        log_method = decorate_log_method(log_method)\n        setattr(logger, key, log_method)\n\n    return logger\n\n\ndef getLogger(name):\n    # make sure that prefix isn't appended multiple times to preserve logging name hierarchy\n    prefix = 'st2.'\n    if name.startswith(prefix):\n        logger = logging.getLogger(name)\n    else:\n        logger_name = '{}{}'.format(prefix, name)\n        logger = logging.getLogger(logger_name)\n\n    logger = decorate_logger_methods(logger=logger)\n    return logger\n\n\nclass LoggingStream(object):\n\n    def __init__(self, name, level=logging.ERROR):\n        self._logger = getLogger(name)\n        self._level = level\n\n    def write(self, message):\n        self._logger._log(self._level, message, None)\n\n    def flush(self):\n        pass\n\n\ndef _audit(logger, msg, *args, **kwargs):\n    if logger.isEnabledFor(logging.AUDIT):\n        logger._log(logging.AUDIT, msg, args, **kwargs)\n\n\nlogging.Logger.audit = _audit\n\n\ndef _add_exclusion_filters(handlers, excludes=None):\n    if excludes:\n        for h in handlers:\n            h.addFilter(ExclusionFilter(excludes))\n\n\ndef _redirect_stderr():\n    # It is ok to redirect stderr as none of the st2 handlers write to stderr.\n    sys.stderr = LoggingStream('STDERR')\n\n\ndef setup(config_file, redirect_stderr=True, excludes=None, disable_existing_loggers=False):\n    \"\"\"\n    Configure logging from file.\n    \"\"\"\n    try:\n        logging.config.fileConfig(config_file,\n                                  defaults=None,\n                                  disable_existing_loggers=disable_existing_loggers)\n        handlers = logging.getLoggerClass().manager.root.handlers\n        _add_exclusion_filters(handlers=handlers, excludes=excludes)\n        if redirect_stderr:\n            _redirect_stderr()\n    except Exception as exc:\n        exc_cls = type(exc)\n        tb_msg = traceback.format_exc()\n\n        msg = str(exc)\n        msg += '\\n\\n' + tb_msg\n\n        # revert stderr redirection since there is no logger in place.\n        sys.stderr = sys.__stderr__\n\n        # No logger yet therefore write to stderr\n        sys.stderr.write('ERROR: %s' % (msg))\n\n        raise exc_cls(six.text_type(msg))\n", "path": "st2common/st2common/log.py"}, {"content": "# Licensed to the StackStorm, Inc ('StackStorm') under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"\nThis module contains common service setup and teardown code.\n\"\"\"\n\nfrom __future__ import absolute_import\n\nimport os\nimport traceback\n\nfrom oslo_config import cfg\n\nfrom st2common import log as logging\nfrom st2common.constants.logging import DEFAULT_LOGGING_CONF_PATH\nfrom st2common.transport.bootstrap_utils import register_exchanges_with_retry\nfrom st2common.signal_handlers import register_common_signal_handlers\nfrom st2common.util.debugging import enable_debugging\nfrom st2common.models.utils.profiling import enable_profiling\nfrom st2common import triggers\nfrom st2common.rbac.migrations import run_all as run_all_rbac_migrations\n\n# Note: This is here for backward compatibility.\n# Function has been moved in a standalone module to avoid expensive in-direct\n# import costs\nfrom st2common.database_setup import db_setup\nfrom st2common.database_setup import db_teardown\n\n\n__all__ = [\n    'setup',\n    'teardown',\n\n    'db_setup',\n    'db_teardown'\n]\n\nLOG = logging.getLogger(__name__)\n\n\ndef setup(service, config, setup_db=True, register_mq_exchanges=True,\n          register_signal_handlers=True, register_internal_trigger_types=False,\n          run_migrations=True, config_args=None):\n    \"\"\"\n    Common setup function.\n\n    Currently it performs the following operations:\n\n    1. Parses config and CLI arguments\n    2. Establishes DB connection\n    3. Set log level for all the loggers to DEBUG if --debug flag is present or\n       if system.debug config option is set to True.\n    4. Registers RabbitMQ exchanges\n    5. Registers common signal handlers\n    6. Register internal trigger types\n\n    :param service: Name of the service.\n    :param config: Config object to use to parse args.\n    \"\"\"\n    # Set up logger which logs everything which happens during and before config\n    # parsing to sys.stdout\n    logging.setup(DEFAULT_LOGGING_CONF_PATH, excludes=None)\n\n    # Parse args to setup config.\n    if config_args:\n        config.parse_args(config_args)\n    else:\n        config.parse_args()\n\n    config_file_paths = cfg.CONF.config_file\n    config_file_paths = [os.path.abspath(path) for path in config_file_paths]\n    LOG.debug('Using config files: %s', ','.join(config_file_paths))\n\n    # Setup logging.\n    logging_config_path = config.get_logging_config_path()\n    logging_config_path = os.path.abspath(logging_config_path)\n\n    LOG.debug('Using logging config: %s', logging_config_path)\n\n    try:\n        logging.setup(logging_config_path, redirect_stderr=cfg.CONF.log.redirect_stderr,\n                      excludes=cfg.CONF.log.excludes)\n    except KeyError as e:\n        tb_msg = traceback.format_exc()\n        if 'log.setLevel' in tb_msg:\n            msg = 'Invalid log level selected. Log level names need to be all uppercase.'\n            msg += '\\n\\n' + getattr(e, 'message', str(e))\n            raise KeyError(msg)\n        else:\n            raise e\n\n    if cfg.CONF.debug or cfg.CONF.system.debug:\n        enable_debugging()\n\n    if cfg.CONF.profile:\n        enable_profiling()\n\n    # All other setup which requires config to be parsed and logging to\n    # be correctly setup.\n    if setup_db:\n        db_setup()\n\n    if register_mq_exchanges:\n        register_exchanges_with_retry()\n\n    if register_signal_handlers:\n        register_common_signal_handlers()\n\n    if register_internal_trigger_types:\n        triggers.register_internal_trigger_types()\n\n    # TODO: This is a \"not so nice\" workaround until we have a proper migration system in place\n    if run_migrations:\n        run_all_rbac_migrations()\n\n\ndef teardown():\n    \"\"\"\n    Common teardown function.\n    \"\"\"\n    db_teardown()\n", "path": "st2common/st2common/service_setup.py"}]}