mirror of
https://github.com/open-telemetry/opentelemetry-python-contrib.git
synced 2025-07-30 21:56:07 +08:00
123 lines
3.6 KiB
Python
123 lines
3.6 KiB
Python
import collections
|
|
from copy import deepcopy
|
|
|
|
from ..internal.logger import get_logger
|
|
from ..span import Span
|
|
|
|
log = get_logger(__name__)
|
|
|
|
|
|
class Hooks(object):
|
|
"""
|
|
Hooks configuration object is used for registering and calling hook functions
|
|
|
|
Example::
|
|
|
|
@config.falcon.hooks.on('request')
|
|
def on_request(span, request, response):
|
|
pass
|
|
"""
|
|
__slots__ = ['_hooks']
|
|
|
|
def __init__(self):
|
|
self._hooks = collections.defaultdict(set)
|
|
|
|
def __deepcopy__(self, memodict=None):
|
|
hooks = Hooks()
|
|
hooks._hooks = deepcopy(self._hooks)
|
|
return hooks
|
|
|
|
def register(self, hook, func=None):
|
|
"""
|
|
Function used to register a hook for the provided name.
|
|
|
|
Example::
|
|
|
|
def on_request(span, request, response):
|
|
pass
|
|
|
|
config.falcon.hooks.register('request', on_request)
|
|
|
|
|
|
If no function is provided then a decorator is returned::
|
|
|
|
@config.falcon.hooks.register('request')
|
|
def on_request(span, request, response):
|
|
pass
|
|
|
|
:param hook: The name of the hook to register the function for
|
|
:type hook: str
|
|
:param func: The function to register, or ``None`` if a decorator should be returned
|
|
:type func: function, None
|
|
:returns: Either a function decorator if ``func is None``, otherwise ``None``
|
|
:rtype: function, None
|
|
"""
|
|
# If they didn't provide a function, then return a decorator
|
|
if not func:
|
|
def wrapper(func):
|
|
self.register(hook, func)
|
|
return func
|
|
return wrapper
|
|
self._hooks[hook].add(func)
|
|
|
|
# Provide shorthand `on` method for `register`
|
|
# >>> @config.falcon.hooks.on('request')
|
|
# def on_request(span, request, response):
|
|
# pass
|
|
on = register
|
|
|
|
def deregister(self, func):
|
|
"""
|
|
Function to deregister a function from all hooks it was registered under
|
|
|
|
Example::
|
|
|
|
@config.falcon.hooks.on('request')
|
|
def on_request(span, request, response):
|
|
pass
|
|
|
|
config.falcon.hooks.deregister(on_request)
|
|
|
|
|
|
:param func: Function hook to register
|
|
:type func: function
|
|
"""
|
|
for funcs in self._hooks.values():
|
|
if func in funcs:
|
|
funcs.remove(func)
|
|
|
|
def _emit(self, hook, span, *args, **kwargs):
|
|
"""
|
|
Function used to call registered hook functions.
|
|
|
|
:param hook: The hook to call functions for
|
|
:type hook: str
|
|
:param span: The span to call the hook with
|
|
:type span: :class:`ddtrace.span.Span`
|
|
:param args: Positional arguments to pass to the hook functions
|
|
:type args: list
|
|
:param kwargs: Keyword arguments to pass to the hook functions
|
|
:type kwargs: dict
|
|
"""
|
|
# Return early if no hooks are registered
|
|
if hook not in self._hooks:
|
|
return
|
|
|
|
# Return early if we don't have a Span
|
|
if not isinstance(span, Span):
|
|
return
|
|
|
|
# Call registered hooks
|
|
for func in self._hooks[hook]:
|
|
try:
|
|
func(span, *args, **kwargs)
|
|
except Exception:
|
|
# DEV: Use log.debug instead of log.error until we have a throttled logger
|
|
log.debug('Failed to run hook %s function %s', hook, func, exc_info=True)
|
|
|
|
def __repr__(self):
|
|
"""Return string representation of this class instance"""
|
|
cls = self.__class__
|
|
hooks = ','.join(self._hooks.keys())
|
|
return '{}.{}({})'.format(cls.__module__, cls.__name__, hooks)
|