Skip to content
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

Add Option to configure renderers in Django settings #158

Closed
wants to merge 5 commits into from

Conversation

kracekumar
Copy link
Contributor

Description

Why?

  • HTMLRenderer is a default renderer for Django App.
  • It'll be useful to support exporting the profile data for various formats to generate alternate visualization graphs like flame graph and use with other applications like speedscope.

Changes

  • Supports a new Django settings variable PYINSTRUMENT_RENDERER which takes in the path of the renderer to use.
  • The middleware produces the output in the configured path. The file extension can only be json, HTML, txt for now. I'm happy to make the extension configurable too.

Let me know If I need to add test cases and modify the docs.

Thanks.

"""Return the renderer instance and output file extension.
"""
if path:
renderer = import_string(path)()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we catch ImportError when the renderer is missing?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, ImportError seems reasonable for a misconfiguration I think.

Copy link
Owner

@joerick joerick left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool feature! Just a few tweaks needed.

"""Return the renderer instance and output file extension.
"""
if path:
renderer = import_string(path)()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, ImportError seems reasonable for a misconfiguration I think.

return renderer, "html"
elif isinstance(renderer, JSONRenderer):
return renderer, "json"
# should other renderers be discouraged?
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not discouraged, if we implement the class variable approach above.

Comment on lines 27 to 30
if isinstance(renderer, HTMLRenderer):
return renderer, "html"
elif isinstance(renderer, JSONRenderer):
return renderer, "json"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These extension values could be accessed through the Renderer object. E.g. a class variable on each could specify output_file_extension. That would allow custom renderers to participate.

@@ -41,8 +57,10 @@ def process_response(self, request, response):
if hasattr(request, "profiler"):
profile_session = request.profiler.stop()

renderer = HTMLRenderer()
output_html = renderer.render(profile_session)
configured_renderer = getattr(settings, "PYINSTRUMENT_RENDERER", None)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So... this is only the configured renderer for the profile_dir. Perhaps a better name for the option would be PYINSTRUMENT_PROFILE_DIR_RENDERER? Then also, we could move the rendering into the if profile_dir: section. That would save cycles rendering something that isn't used.

- Add output_file_extension attribute to the Renderer class
- Use PYINSTRUMENT_PROFILE_DIR_RENDERER setting variable
Copy link
Contributor Author

@kracekumar kracekumar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have used print statement to print error message. Let me know if I need to use logger.

@@ -29,6 +29,10 @@ class Renderer:
Dictionary containing processor options, passed to each processor.
"""

output_file_extension: str = "txt"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added the output_file_extension attribute.

@@ -41,8 +61,10 @@ def process_response(self, request, response):
if hasattr(request, "profiler"):
profile_session = request.profiler.stop()

renderer = HTMLRenderer()
output_html = renderer.render(profile_session)
configured_renderer = getattr(settings, "PYINSTRUMENT_PROFILE_DIR_RENDERER", None)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeping this here since this renderer is used in the if/else block to produce output.

pyinstrument/middleware.py Outdated Show resolved Hide resolved
@joerick joerick added the automerge Tells https://github.com/apps/mergery to Squash-merge the PR when the button is green. label Oct 31, 2021
return renderer, renderer.output_file_extension
else:
print("Renderer should subclass: %s. Using HTMLRenderer" % Renderer)
return HTMLRenderer(), HTMLRenderer.output_file_extension
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pyright was pointing out this can return None. So when the renderer is not a subclass of Renderer, we will be using HTMLRenderer. Let me know if this is fine?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be better to raise an error, instead. I'll update it.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made the update. For some reason I wasn't able to push to this branch. I've pushed it to 69b195b - if you could cherry-pick that here, I think we're good to go.

@joerick joerick removed the automerge Tells https://github.com/apps/mergery to Squash-merge the PR when the button is green. label Nov 4, 2021
mergery bot pushed a commit that referenced this pull request Nov 4, 2021
…] (#163)

* Add Option to configure renderers in Django settings

* Run precommit hook on all files

* Incorporate the review feedback

- Add output_file_extension attribute to the Renderer class
- Use PYINSTRUMENT_PROFILE_DIR_RENDERER setting variable

* Update pyinstrument/middleware.py

* Remove exit condition and use html renderer when render is missing

* Tidy up, raise error on misconfig

* pre-commit fixes

Co-authored-by: Kracekumar <me@kracekumar.com>
Co-authored-by: pre-commit <pre-commit@example.com>
@joerick
Copy link
Owner

joerick commented Nov 4, 2021

This was merged in #163

@joerick joerick closed this Nov 4, 2021
@kracekumar
Copy link
Contributor Author

Thanks a lot! Couldn't do complete earlier.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants