~bzr-pqm/bzr/bzr.dev

5387.2.7 by John Arbash Meinel
Merge bzr.dev 5444 to resolve some small text conflicts.
1
# Copyright (C) 2007, 2009, 2010 Canonical Ltd
2367.1.7 by Robert Collins
Added ``bzrlib.strace.strace`` which will strace a single callable and
2
#   Authors: Robert Collins <robert.collins@canonical.com>
3
#
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2367.1.7 by Robert Collins
Added ``bzrlib.strace.strace`` which will strace a single callable and
17
18
"""Support for running strace against the current process."""
19
2386.1.2 by John Arbash Meinel
Make sure errno is imported if we are going to use it later.
20
import errno
2367.1.7 by Robert Collins
Added ``bzrlib.strace.strace`` which will strace a single callable and
21
import os
22
import signal
23
import subprocess
24
import tempfile
25
5398.2.1 by Martin Pool
Cope with strace not allowing you to attach to your own processes
26
from bzrlib import errors
27
28
2367.1.7 by Robert Collins
Added ``bzrlib.strace.strace`` which will strace a single callable and
29
# this is currently test-focused, so importing bzrlib.tests is ok. We might
30
# want to move feature to its own module though.
31
from bzrlib.tests import Feature
32
2367.1.9 by Robert Collins
Review feedback.
33
2367.1.7 by Robert Collins
Added ``bzrlib.strace.strace`` which will strace a single callable and
34
def strace(function, *args, **kwargs):
35
    """Invoke strace on function.
36
2367.1.9 by Robert Collins
Review feedback.
37
    :return: a tuple: function-result, a StraceResult.
2367.1.7 by Robert Collins
Added ``bzrlib.strace.strace`` which will strace a single callable and
38
    """
2566.3.4 by Vincent Ladeuil
Take Martin and Robert comments into account.
39
    return strace_detailed(function, args, kwargs)
40
41
42
def strace_detailed(function, args, kwargs, follow_children=True):
2566.3.1 by Vincent Ladeuil
Fix #102019 by not asking strace to follow children forks during tests.
43
    # FIXME: strace is buggy
44
    # (https://bugs.launchpad.net/ubuntu/+source/strace/+bug/103133) and the
45
    # test suite hangs if the '-f' is given to strace *and* more than one
2566.3.4 by Vincent Ladeuil
Take Martin and Robert comments into account.
46
    # thread is running. Using follow_children=False allows the test suite to
47
    # disable fork following to work around the bug.
48
2367.1.7 by Robert Collins
Added ``bzrlib.strace.strace`` which will strace a single callable and
49
    # capture strace output to a file
2394.1.1 by Andrew Bennetts
Wait for strace to attach before running the function we want to trace.
50
    log_file = tempfile.NamedTemporaryFile()
2367.1.7 by Robert Collins
Added ``bzrlib.strace.strace`` which will strace a single callable and
51
    log_file_fd = log_file.fileno()
5398.2.1 by Martin Pool
Cope with strace not allowing you to attach to your own processes
52
    err_file = tempfile.NamedTemporaryFile()
2367.1.7 by Robert Collins
Added ``bzrlib.strace.strace`` which will strace a single callable and
53
    pid = os.getpid()
54
    # start strace
2566.3.1 by Vincent Ladeuil
Fix #102019 by not asking strace to follow children forks during tests.
55
    strace_cmd = ['strace', '-r', '-tt', '-p', str(pid), '-o', log_file.name]
2566.3.2 by Vincent Ladeuil
Fix typo, add comment, following Martin's review.
56
    if follow_children:
2566.3.1 by Vincent Ladeuil
Fix #102019 by not asking strace to follow children forks during tests.
57
        strace_args.append('-f')
5398.2.1 by Martin Pool
Cope with strace not allowing you to attach to your own processes
58
    # need to catch both stdout and stderr to work around
59
    # bug 627208
2566.3.1 by Vincent Ladeuil
Fix #102019 by not asking strace to follow children forks during tests.
60
    proc = subprocess.Popen(strace_cmd,
61
                            stdout=subprocess.PIPE,
5398.2.1 by Martin Pool
Cope with strace not allowing you to attach to your own processes
62
                            stderr=err_file.fileno())
2394.1.1 by Andrew Bennetts
Wait for strace to attach before running the function we want to trace.
63
    # Wait for strace to attach
64
    attached_notice = proc.stdout.readline()
65
    # Run the function to strace
2367.1.9 by Robert Collins
Review feedback.
66
    result = function(*args, **kwargs)
2367.1.7 by Robert Collins
Added ``bzrlib.strace.strace`` which will strace a single callable and
67
    # stop strace
68
    os.kill(proc.pid, signal.SIGQUIT)
69
    proc.communicate()
70
    # grab the log
71
    log_file.seek(0)
72
    log = log_file.read()
73
    log_file.close()
5398.2.1 by Martin Pool
Cope with strace not allowing you to attach to your own processes
74
    # and stderr
75
    err_file.seek(0)
76
    err_messages = err_file.read()
77
    err_file.close()
78
    # and read any errors
79
    if err_messages.startswith("attach: ptrace(PTRACE_ATTACH,"):
80
        raise StraceError(err_messages=err_messages)
81
    return result, StraceResult(log, err_messages)
82
83
84
class StraceError(errors.BzrError):
85
    
86
    _fmt = "strace failed: %(err_messages)s"
2367.1.7 by Robert Collins
Added ``bzrlib.strace.strace`` which will strace a single callable and
87
88
89
class StraceResult(object):
90
    """The result of stracing a function."""
91
5398.2.1 by Martin Pool
Cope with strace not allowing you to attach to your own processes
92
    def __init__(self, raw_log, err_messages):
2367.1.7 by Robert Collins
Added ``bzrlib.strace.strace`` which will strace a single callable and
93
        """Create a StraceResult.
94
95
        :param raw_log: The output that strace created.
96
        """
97
        self.raw_log = raw_log
5398.2.1 by Martin Pool
Cope with strace not allowing you to attach to your own processes
98
        self.err_messages = err_messages
2367.1.7 by Robert Collins
Added ``bzrlib.strace.strace`` which will strace a single callable and
99
100
101
class _StraceFeature(Feature):
102
103
    def _probe(self):
104
        try:
105
            proc = subprocess.Popen(['strace'],
106
                stderr=subprocess.PIPE,
107
                stdout=subprocess.PIPE)
108
            proc.communicate()
109
            return True
110
        except OSError, e:
111
            if e.errno == errno.ENOENT:
112
                # strace is not installed
113
                return False
114
            else:
115
                raise
116
117
    def feature_name(self):
118
        return 'strace'
119
120
StraceFeature = _StraceFeature()