Skip to content

Add support for PyCharm Pro's Remote Debug Server #5674

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

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,19 @@ Added
* Added graceful shutdown for workflow engine. #5463
Contributed by @khushboobhatia01

* Allow debugging st2 services in PyCharm Pro's Remote Debug Server.
To enable debugging, before starting the st2 process(es), you need to:

- install pydevd-pycharm (use the version specific to your pycharm install) in StackStorm's virtualenv.
- set the ``ST2_PYCHARM_DEBUG`` environment var to something non-empty like "true".
- (optional) set environment vars ``ST2_PYCHARM_DEBUG_HOST`` and
``ST2_PYCHARM_DEBUG_PORT`` if pycharm is listening somewhere other than
``localhost:5000``.

see: https://www.jetbrains.com/help/pycharm/remote-debugging-with-product.html#remote-debug-config

#5674 Contributed by @cognifloyd.

3.7.0 - May 05, 2022
--------------------

Expand Down
2 changes: 1 addition & 1 deletion lint-configs/python/.pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ property-classes=abc.abstractproperty
# Note: This modules are manipulated during the runtime so we can't detect all the properties during
# static analysis
# orjson has type stubs, but pylint doesn't support __init__.pyi yet: https://github.com/PyCQA/pylint/issues/2873
ignored-modules=distutils,eventlet.green.subprocess,six,six.moves,orjson
ignored-modules=distutils,eventlet.green.subprocess,six,six.moves,orjson,pydevd_pycharm

[FORMAT]
max-line-length=100
Expand Down
22 changes: 22 additions & 0 deletions st2common/st2common/util/monkey_patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

from __future__ import absolute_import

import os
import sys

__all__ = [
Expand All @@ -43,6 +44,23 @@ def monkey_patch(patch_thread=None):
patched unless debugger is used.
:type patch_thread: ``bool``
"""
if os.environ.get("ST2_PYCHARM_DEBUG", False):

# pydevd_pycharm uses this to save copies of stdlib modules before
# eventlet monkey patches them, or the debugger will not work.
# see: https://intellij-support.jetbrains.com/hc/en-us/community/posts/360000333980
os.environ["GEVENT_SUPPORT"] = "True"

import pydevd_pycharm

pydevd_pycharm.settrace(
Comment on lines +47 to +56
Copy link
Member Author

@cognifloyd cognifloyd Jul 18, 2022

Choose a reason for hiding this comment

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

@armab Do you have a recommendation on how we can make this extensible so that people can inject whatever debugger before monkey_patching occurs?

Copy link
Member Author

@cognifloyd cognifloyd Jul 18, 2022

Choose a reason for hiding this comment

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

What about something like:

def monkey_patch(patch_thread=None):
    """
    ...
    """
    use_debugger = is_use_debugger_flag_provided()
    if use_debugger:
        try:
            from st2_3rd_party_debugger import pre_monkey_patch
        except ImportError:
            pass
        else:
            pre_monkey_patch()

    ...
    import eventlet
    ...
    if patch_thread is None:
        patch_thread = not use_debugger

    eventlet.monkey_patch(...)
    ...

Then, I would only need to install a package in the st2 virtualenv that provides a pycharm-specific version of the st2_3rd_party_debugger module.

@armab what do you think of this solution for enabling me to inject the debugger without adding anything IDE-specific, and without patching the st2 code.

os.environ.get("ST2_PYCHARM_DEBUG_HOST", "localhost"),
port=os.environ.get("ST2_PYCHARM_DEBUG_PORT", 5000),
stdoutToServer=True,
stderrToServer=True,
patch_multiprocessing=True,
)

# Eventlet when patched doesn't throw the standard ssl error on timeout, which can break
# some third-party libraries including redis SSL.
# See: https://github.com/eventlet/eventlet/issues/692
Expand Down Expand Up @@ -117,4 +135,8 @@ def is_use_debugger_flag_provided():
if arg.startswith(PARENT_ARGS_FLAG) and USE_DEBUGGER_FLAG in arg:
return True

# 3. Check for ST2_PYCHARM_DEBUG env var
if os.environ.get("ST2_PYCHARM_DEBUG", False):
return True
Comment on lines +138 to +140
Copy link
Member Author

Choose a reason for hiding this comment

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

This part is not pycharm specific - it allows enabling debug mode via env var instead of changing the cli args.

Suggested change
# 3. Check for ST2_PYCHARM_DEBUG env var
if os.environ.get("ST2_PYCHARM_DEBUG", False):
return True
# 3. Check for ST2_DEBUG env var
if os.environ.get("ST2_DEBUG", False):
return True

Copy link
Member Author

Choose a reason for hiding this comment

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

OK I split this change into a separate PR: #5675


return False