Created
July 18, 2018 02:06
-
-
Save garethgreenaway/74e809ef6b4beeb74f878e2485bca8e7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/salt/log/setup.py b/salt/log/setup.py | |
index 4c6d5dd8fd..6d74ee0274 100644 | |
--- a/salt/log/setup.py | |
+++ b/salt/log/setup.py | |
@@ -48,6 +48,7 @@ from salt.log.handlers import (TemporaryLoggingHandler, | |
QueueHandler) | |
from salt.log.mixins import LoggingMixInMeta, NewStyleClassMixIn | |
+from salt.utils.ctx import RequestContext | |
LOG_LEVELS = { | |
'all': logging.NOTSET, | |
@@ -305,6 +306,18 @@ class SaltLoggingClass(six.with_metaclass(LoggingMixInMeta, LOGGING_LOGGER_CLASS | |
def _log(self, level, msg, args, exc_info=None, extra=None, # pylint: disable=arguments-differ | |
exc_info_on_loglevel=None): | |
# If both exc_info and exc_info_on_loglevel are both passed, let's fail | |
+ if extra is None: | |
+ extra = {} | |
+ | |
+ current_jid = RequestContext.current.get('data', {}).get('jid', None) | |
+ log_fmt_jid = RequestContext.current.get('opts', {}).get('log_fmt_jid', None) | |
+ | |
+ if current_jid is not None: | |
+ extra['jid'] = current_jid | |
+ | |
+ if log_fmt_jid is not None: | |
+ extra['log_fmt_jid'] = log_fmt_jid | |
+ | |
if exc_info and exc_info_on_loglevel: | |
raise RuntimeError( | |
'Only one of \'exc_info\' and \'exc_info_on_loglevel\' is ' | |
@@ -335,6 +348,12 @@ class SaltLoggingClass(six.with_metaclass(LoggingMixInMeta, LOGGING_LOGGER_CLASS | |
func=None, extra=None, sinfo=None): | |
# Let's remove exc_info_on_loglevel from extra | |
exc_info_on_loglevel = extra.pop('exc_info_on_loglevel') | |
+ | |
+ jid = extra.pop('jid', '') | |
+ log_fmt_jid = extra.pop('log_fmt_jid', '[JID: %(jid)s]') | |
+ if jid: | |
+ jid = log_fmt_jid % {'jid': jid} | |
+ | |
if not extra: | |
# If nothing else is in extra, make it None | |
extra = None | |
@@ -393,6 +412,7 @@ class SaltLoggingClass(six.with_metaclass(LoggingMixInMeta, LOGGING_LOGGER_CLASS | |
logrecord.exc_info_on_loglevel_formatted = None | |
logrecord.exc_info_on_loglevel = exc_info_on_loglevel | |
+ logrecord.jid = jid | |
return logrecord | |
# pylint: enable=C0103 | |
diff --git a/salt/master.py b/salt/master.py | |
index 650dda3ead..dff9a27adf 100644 | |
--- a/salt/master.py | |
+++ b/salt/master.py | |
@@ -8,6 +8,7 @@ involves preparing the three listeners and the workers needed by the master. | |
from __future__ import absolute_import, with_statement, print_function, unicode_literals | |
import copy | |
import ctypes | |
+import functools | |
import os | |
import re | |
import sys | |
@@ -90,6 +91,9 @@ try: | |
except ImportError: | |
HAS_HALITE = False | |
+from tornado.stack_context import StackContext | |
+from salt.utils.ctx import RequestContext | |
+ | |
log = logging.getLogger(__name__) | |
@@ -1106,7 +1110,15 @@ class MWorker(salt.utils.process.SignalHandlingMultiprocessingProcess): | |
if self.opts['master_stats']: | |
start = time.time() | |
self.stats[cmd]['runs'] += 1 | |
- ret = self.aes_funcs.run_func(data['cmd'], data) | |
+ | |
+ def run_func(data): | |
+ return self.aes_funcs.run_func(data['cmd'], data) | |
+ | |
+ with StackContext(functools.partial(RequestContext, | |
+ {'data': data, | |
+ 'opts': self.opts})): | |
+ ret = run_func(data) | |
+ | |
if self.opts['master_stats']: | |
self._post_stats(start, cmd) | |
return ret | |
diff --git a/salt/minion.py b/salt/minion.py | |
index edecfcef5c..3c08e923dc 100644 | |
--- a/salt/minion.py | |
+++ b/salt/minion.py | |
@@ -4,6 +4,7 @@ Routines to set up a minion | |
''' | |
# Import python libs | |
from __future__ import absolute_import, print_function, with_statement, unicode_literals | |
+import functools | |
import os | |
import re | |
import sys | |
@@ -33,6 +34,8 @@ else: | |
from salt.ext.six.moves import range | |
from salt.utils.zeromq import zmq, ZMQDefaultLoop, install_zmq, ZMQ_VERSION_INFO | |
+from salt.utils.ctx import RequestContext | |
+ | |
# pylint: enable=no-name-in-module,redefined-builtin | |
import tornado | |
@@ -1534,11 +1537,16 @@ class Minion(MinionBase): | |
get_proc_dir(opts['cachedir'], uid=uid) | |
) | |
- with tornado.stack_context.StackContext(minion_instance.ctx): | |
+ def run_func(minion_instance, opts, data): | |
if isinstance(data['fun'], tuple) or isinstance(data['fun'], list): | |
- Minion._thread_multi_return(minion_instance, opts, data) | |
+ return Minion._thread_multi_return(minion_instance, opts, data) | |
else: | |
- Minion._thread_return(minion_instance, opts, data) | |
+ return Minion._thread_return(minion_instance, opts, data) | |
+ | |
+ with tornado.stack_context.StackContext(functools.partial(RequestContext, | |
+ {'data': data, 'opts': opts})): | |
+ with tornado.stack_context.StackContext(minion_instance.ctx): | |
+ run_func(minion_instance, opts, data) | |
@classmethod | |
def _thread_return(cls, minion_instance, opts, data): | |
diff --git a/salt/utils/ctx.py b/salt/utils/ctx.py | |
new file mode 100644 | |
index 0000000000..e80f8415ac | |
--- /dev/null | |
+++ b/salt/utils/ctx.py | |
@@ -0,0 +1,47 @@ | |
+import threading | |
+ | |
+class ClassProperty(property): | |
+ ''' | |
+ Use a classmethod as a property | |
+ http://stackoverflow.com/a/1383402/1258307 | |
+ ''' | |
+ def __get__(self, cls, owner): | |
+ return self.fget.__get__(None, owner)() # pylint: disable=no-member | |
+ | |
+ | |
+class RequestContext(object): | |
+ ''' | |
+ A context manager that saves some per-thread state globally. | |
+ Intended for use with Tornado's StackContext. | |
+ https://gist.github.com/simon-weber/7755289 | |
+ Simply import this class into any module and access the current request handler by this | |
+ class's class method property 'current'. If it returns None, there's no active request. | |
+ .. code:: python | |
+ from salt.utils.ctx import RequestContext | |
+ current_request_handler = RequestContext.current | |
+ ''' | |
+ | |
+ _state = threading.local() | |
+ _state.current_request = {} | |
+ | |
+ def __init__(self, current_request): | |
+ self._current_request = current_request | |
+ | |
+ @ClassProperty | |
+ @classmethod | |
+ def current(cls): | |
+ if not hasattr(cls._state, 'current_request'): | |
+ return {} | |
+ return cls._state.current_request | |
+ | |
+ def __enter__(self): | |
+ self._prev_request = self.__class__.current | |
+ self.__class__._state.current_request = self._current_request | |
+ | |
+ def __exit__(self, *exc): | |
+ self.__class__._state.current_request = self._prev_request | |
+ del self._prev_request | |
+ return False | |
+ | |
+ def __call__(self): | |
+ return self | |
diff --git a/salt/utils/decorators/jinja.py b/salt/utils/decorators/jinja.py | |
index f61efb2ac1..22d68369cf 100644 | |
--- a/salt/utils/decorators/jinja.py | |
+++ b/salt/utils/decorators/jinja.py | |
@@ -5,7 +5,8 @@ Jinja-specific decorators | |
from __future__ import absolute_import, print_function, unicode_literals | |
# Import Python libs | |
-import logging | |
+# Ensure we're using the custom logging from Salt | |
+import salt.log.setup as logging | |
log = logging.getLogger(__name__) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment