-
Notifications
You must be signed in to change notification settings - Fork 452
chore(django): migrate template render wrappers to WrappingContext #14069
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
f458c41
chore(django): migrate template render wrappers to WrappingContext
brettlangdon 5308501
Merge remote-tracking branch 'origin/main' into LANGPLAT-642/django-b…
brettlangdon bd7a25c
log when we cannot close the context
brettlangdon e8d4c77
Update ddtrace/contrib/internal/django/templates.py
brettlangdon af60267
Merge remote-tracking branch 'origin/main' into LANGPLAT-642/django-b…
brettlangdon 54b183e
use context ended to end the template render span
brettlangdon 4362360
internal(core): add exc_info to context.ended.* events
brettlangdon 90ff0d8
just 'type'
brettlangdon 1b230a7
fix formatting
brettlangdon b392bfe
Merge remote-tracking branch 'origin/LANGPLAT-642/refactor.context.en…
brettlangdon bbd0758
Update ddtrace/_trace/trace_handlers.py
brettlangdon 4c3694c
Merge branch 'main' into LANGPLAT-642/django-bytecode-templates
brettlangdon 15aad90
Merge branch 'main' into LANGPLAT-642/django-bytecode-templates
brettlangdon e831c19
Merge branch 'main' into LANGPLAT-642/django-bytecode-templates
christophe-papazian ad7bcd6
Merge branch 'main' into LANGPLAT-642/django-bytecode-templates
brettlangdon c612796
Merge branch 'main' into LANGPLAT-642/django-bytecode-templates
brettlangdon 621e1b4
Merge branch 'main' into LANGPLAT-642/django-bytecode-templates
brettlangdon b94751a
Merge branch 'main' into LANGPLAT-642/django-bytecode-templates
brettlangdon 2af2a71
introduce config_django perf
brettlangdon cc604ac
Merge branch 'main' into LANGPLAT-642/django-bytecode-templates
brettlangdon File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
from types import FunctionType | ||
from types import ModuleType | ||
from types import TracebackType | ||
import typing | ||
from typing import Optional | ||
from typing import Type | ||
from typing import TypeVar | ||
|
||
import ddtrace | ||
from ddtrace import config | ||
from ddtrace._trace.pin import Pin | ||
from ddtrace.ext import http | ||
from ddtrace.internal import core | ||
from ddtrace.internal.compat import maybe_stringify | ||
from ddtrace.internal.constants import COMPONENT | ||
from ddtrace.internal.logger import get_logger | ||
from ddtrace.internal.utils.importlib import func_name | ||
from ddtrace.internal.wrapping.context import WrappingContext | ||
from ddtrace.settings.integration import IntegrationConfig | ||
|
||
|
||
T = TypeVar("T") | ||
|
||
log = get_logger(__name__) | ||
|
||
|
||
# PERF: cache the getattr lookup for the Django config | ||
config_django: IntegrationConfig = typing.cast(IntegrationConfig, config.django) | ||
|
||
|
||
class DjangoTemplateWrappingContext(WrappingContext): | ||
""" | ||
A context for wrapping django.template.base:Template.render method. | ||
""" | ||
|
||
def __init__(self, f: FunctionType, django: ModuleType) -> None: | ||
super().__init__(f) | ||
self._django = django | ||
|
||
@classmethod | ||
def instrument_module(cls, django_template_base: ModuleType) -> None: | ||
""" | ||
Instrument the django template base module to wrap the render method. | ||
""" | ||
if not config_django.instrument_templates: | ||
return | ||
|
||
# Wrap the render method of the Template class | ||
Template = getattr(django_template_base, "Template", None) | ||
if not Template or not hasattr(Template, "render"): | ||
return | ||
|
||
import django | ||
|
||
cls(typing.cast(FunctionType, Template.render), django).wrap() | ||
|
||
@classmethod | ||
def uninstrument_module(cls, django_template_base: ModuleType) -> None: | ||
# Unwrap the render method of the Template class | ||
Template = getattr(django_template_base, "Template", None) | ||
if not Template or not hasattr(Template, "render"): | ||
return | ||
|
||
if cls.is_wrapped(Template.render): | ||
ctx = cls.extract(Template.render) | ||
ctx.unwrap() | ||
|
||
def __enter__(self) -> "DjangoTemplateWrappingContext": | ||
super().__enter__() | ||
|
||
if not config_django.instrument_templates: | ||
return self | ||
|
||
# Get the template instance (self parameter of the render method) | ||
# Note: instance is a django.template.base.Template | ||
instance = self.get_local("self") | ||
|
||
# Extract template name | ||
template_name = maybe_stringify(getattr(instance, "name", None)) | ||
if template_name: | ||
resource = template_name | ||
else: | ||
resource = "{0}.{1}".format(func_name(instance), self.__wrapped__.__name__) | ||
|
||
# Build tags | ||
tags = {COMPONENT: config_django.integration_name} | ||
if template_name: | ||
tags["django.template.name"] = template_name | ||
|
||
engine = getattr(instance, "engine", None) | ||
if engine: | ||
tags["django.template.engine.class"] = func_name(engine) | ||
|
||
# Create the span context | ||
pin = Pin.get_from(self._django) | ||
brettlangdon marked this conversation as resolved.
Show resolved
Hide resolved
|
||
tracer = ddtrace.tracer | ||
if pin: | ||
tracer = pin.tracer or tracer | ||
ctx = core.context_with_data( | ||
"django.template.render", | ||
span_name="django.template.render", | ||
resource=resource, | ||
span_type=http.TEMPLATE, | ||
tags=tags, | ||
tracer=tracer, | ||
) | ||
|
||
# Enter the context and store it | ||
ctx.__enter__() | ||
self.set("ctx", ctx) | ||
|
||
return self | ||
|
||
def _close_ctx( | ||
brettlangdon marked this conversation as resolved.
Show resolved
Hide resolved
|
||
self, exc_type: Optional[Type[BaseException]], exc_val: Optional[BaseException], exc_tb: Optional[TracebackType] | ||
) -> None: | ||
try: | ||
# Close the context and any open span | ||
ctx = self.get("ctx") | ||
ctx.__exit__(exc_type, exc_val, exc_tb) | ||
except Exception: | ||
log.exception("Failed to close Django template render wrapping context") | ||
|
||
def __return__(self, value: T) -> T: | ||
if config_django.instrument_templates: | ||
self._close_ctx(None, None, None) | ||
return super().__return__(value) | ||
|
||
def __exit__( | ||
self, exc_type: Optional[Type[BaseException]], exc_val: Optional[BaseException], exc_tb: Optional[TracebackType] | ||
) -> None: | ||
if config_django.instrument_templates: | ||
self._close_ctx(exc_type, exc_val, exc_tb) | ||
return super().__exit__(exc_type, exc_val, exc_tb) |
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
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.