def traced_load_middleware(django, pin, func, instance, args, kwargs): """Patches django.core.handlers.base.BaseHandler.load_middleware to instrument all middlewares.""" settings_middleware = [] # Gather all the middleware if getattr(django.conf.settings, "MIDDLEWARE", None): settings_middleware += django.conf.settings.MIDDLEWARE if getattr(django.conf.settings, "MIDDLEWARE_CLASSES", None): settings_middleware += django.conf.settings.MIDDLEWARE_CLASSES # Iterate over each middleware provided in settings.py # Each middleware can either be a function or a class for mw_path in settings_middleware: mw = django.utils.module_loading.import_string(mw_path) # Instrument function-based middleware if isfunction(mw) and not iswrapped(mw): split = mw_path.split(".") if len(split) < 2: continue base = ".".join(split[:-1]) attr = split[-1] # Function-based middleware is a factory which returns a handler function for requests. # So instead of tracing the factory, we want to trace its returned value. # We wrap the factory to return a traced version of the handler function. def wrapped_factory(func, instance, args, kwargs): # r is the middleware handler function returned from the factory r = func(*args, **kwargs) return wrapt.FunctionWrapper( r, traced_func(django, "django.middleware", resource=mw_path)) wrap(base, attr, wrapped_factory) # Instrument class-based middleware elif isclass(mw): for hook in [ "process_request", "process_response", "process_view", "process_template_response", "__call__", ]: if hasattr(mw, hook) and not iswrapped(mw, hook): wrap( mw, hook, traced_func(django, "django.middleware", resource=mw_path + ".{0}".format(hook))) # Do a little extra for `process_exception` if hasattr(mw, "process_exception") and not iswrapped( mw, "process_exception"): res = mw_path + ".{0}".format("process_exception") wrap( mw, "process_exception", traced_process_exception(django, "django.middleware", resource=res)) return func(*args, **kwargs)
def instrument_caches(django): cache_backends = set([cache["BACKEND"] for cache in django.conf.settings.CACHES.values()]) for cache_path in cache_backends: split = cache_path.split(".") cache_module = ".".join(split[:-1]) cache_cls = split[-1] for method in ["get", "set", "add", "delete", "incr", "decr", "get_many", "set_many", "delete_many"]: try: cls = django.utils.module_loading.import_string(cache_path) # DEV: this can be removed when we add an idempotent `wrap` if not iswrapped(cls, method): wrap(cache_module, "{0}.{1}".format(cache_cls, method), traced_cache(django)) except Exception: log.debug("Error instrumenting cache %r", cache_path, exc_info=True)