File: debug_utils.py

package info (click to toggle)
openstack-trove 2014.1.3-8
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 10,752 kB
  • ctags: 6,663
  • sloc: python: 37,317; xml: 1,485; sh: 281; makefile: 49
file content (146 lines) | stat: -rw-r--r-- 4,851 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# Copyright 2011 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
#

"""Help utilities for debugging"""

import sys

from oslo.config import cfg

from trove.openstack.common import log


LOG = log.getLogger(__name__)
CONF = cfg.CONF

__debug_state = None

pydev_debug_opts = [
    cfg.StrOpt("pydev_debug",
               choices=("disabled", "enabled", "auto"),
               default="disabled",
               help="Enable or disable pydev remote debugging. "
                    "If value is 'auto' tries to connect to remote "
                    "debugger server, but in case of error "
                    "continues running with debugging disabled."),

    cfg.StrOpt("pydev_debug_host",
               help="Pydev debug server host (localhost by default)."),

    cfg.IntOpt("pydev_debug_port",
               help="Pydev debug server port (5678 by default)."),

    cfg.StrOpt("pydev_path",
               help="Set path to pydevd library, used if pydevd is "
                    "not found in python sys.path.")
]

CONF.register_opts(pydev_debug_opts)


def setup():
    """
    Analyze configuration for pydev remote debugging and establish
    connection to remote debugger service if needed

    @return: True if remote debugging was enabled successfully,
        otherwise - False
    """

    global __debug_state

    if CONF.pydev_debug == "enabled":
        __debug_state = __setup_remote_pydev_debug(
            pydev_debug_host=CONF.pydev_debug_host,
            pydev_debug_port=CONF.pydev_debug_port,
            pydev_path=CONF.pydev_path)
    elif CONF.pydev_debug == "auto":
        __debug_state = __setup_remote_pydev_debug_safe(
            pydev_debug_host=CONF.pydev_debug_host,
            pydev_debug_port=CONF.pydev_debug_port,
            pydev_path=CONF.pydev_path)
    else:
        __debug_state = False


def enabled():
    """
    @return: True if connection to remote debugger established, otherwise False
    """
    assert __debug_state is not None, ("debug_utils are not initialized. "
                                       "Please call setup() method first")
    return __debug_state


def __setup_remote_pydev_debug_safe(pydev_debug_host=None,
                                    pydev_debug_port=5678, pydev_path=None):
    """
    Safe version of __setup_remote_pydev_debug method. In error case returns
    False as result instead of Exception raising

    @see: __setup_remote_pydev_debug
    """

    try:
        return __setup_remote_pydev_debug(
            pydev_debug_host=pydev_debug_host,
            pydev_debug_port=pydev_debug_port,
            pydev_path=pydev_path)
    except Exception as e:
        LOG.info("Cann't connect to remote debug server. Continue working in "
                 "standard mode. Error: %s", e)
        return False


def __setup_remote_pydev_debug(pydev_debug_host=None, pydev_debug_port=None,
                               pydev_path=None):
    """
    Method connects to remote debug server, and attach current thread trace
    to debugger. Also thread.start_new_thread thread.start_new are patched to
    enable debugging of new threads

    @param pydev_debug_host: remote debug server host hame, 'localhost'
        if not specified or None
    @param pydev_debug_port: remote debug server port, 5678
        if not specified or None
    @param pydev_path: optional path to pydevd library, used it pydevd is not
        found in python sys.path
    @return: True if debugging initialized,
        otherwise exception should be raised
    """

    if pydev_debug_port is None:
        pydev_debug_port = 5678
    try:
        import pydevd
        LOG.debug("pydevd module was imported from system path")
    except ImportError:
        LOG.debug("Cann't load pydevd module from system path. Try load it "
                  "from pydev_path: %s", pydev_path)
        assert pydev_path, "pydev_path is not set"
        if pydev_path not in sys.path:
            sys.path.append(pydev_path)
        import pydevd
        LOG.debug("pydevd module was imported from pydev_path: %s", pydev_path)
    pydevd.settrace(
        host=pydev_debug_host,
        port=pydev_debug_port,
        stdoutToServer=True,
        stderrToServer=True,
        trace_only_current_thread=False,
        suspend=False,
    )
    return True