~bzr-pqm/bzr/bzr.dev

2367.1.7 by Robert Collins
Added ``bzrlib.strace.strace`` which will strace a single callable and
1
# Copyright (C) 2007 Canonical Ltd
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
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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
26
# this is currently test-focused, so importing bzrlib.tests is ok. We might
27
# want to move feature to its own module though.
28
from bzrlib.tests import Feature
29
2367.1.9 by Robert Collins
Review feedback.
30
2367.1.7 by Robert Collins
Added ``bzrlib.strace.strace`` which will strace a single callable and
31
def strace(function, *args, **kwargs):
32
    """Invoke strace on function.
33
2367.1.9 by Robert Collins
Review feedback.
34
    :return: a tuple: function-result, a StraceResult.
2367.1.7 by Robert Collins
Added ``bzrlib.strace.strace`` which will strace a single callable and
35
    """
36
    # 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.
37
    log_file = tempfile.NamedTemporaryFile()
2367.1.7 by Robert Collins
Added ``bzrlib.strace.strace`` which will strace a single callable and
38
    log_file_fd = log_file.fileno()
39
    pid = os.getpid()
40
    # start strace
41
    proc = subprocess.Popen(['strace',
2394.1.1 by Andrew Bennetts
Wait for strace to attach before running the function we want to trace.
42
        '-f', '-r', '-tt', '-p', str(pid), '-o', log_file.name
2367.1.7 by Robert Collins
Added ``bzrlib.strace.strace`` which will strace a single callable and
43
        ],
2394.1.1 by Andrew Bennetts
Wait for strace to attach before running the function we want to trace.
44
        stdout=subprocess.PIPE,
45
        stderr=subprocess.STDOUT)
46
    # Wait for strace to attach
47
    attached_notice = proc.stdout.readline()
48
    # Run the function to strace
2367.1.9 by Robert Collins
Review feedback.
49
    result = function(*args, **kwargs)
2367.1.7 by Robert Collins
Added ``bzrlib.strace.strace`` which will strace a single callable and
50
    # stop strace
51
    os.kill(proc.pid, signal.SIGQUIT)
52
    proc.communicate()
53
    # grab the log
54
    log_file.seek(0)
55
    log = log_file.read()
56
    log_file.close()
2367.1.9 by Robert Collins
Review feedback.
57
    return result, StraceResult(log)
2367.1.7 by Robert Collins
Added ``bzrlib.strace.strace`` which will strace a single callable and
58
59
60
class StraceResult(object):
61
    """The result of stracing a function."""
62
63
    def __init__(self, raw_log):
64
        """Create a StraceResult.
65
66
        :param raw_log: The output that strace created.
67
        """
68
        self.raw_log = raw_log
69
70
71
class _StraceFeature(Feature):
72
73
    def _probe(self):
74
        try:
75
            proc = subprocess.Popen(['strace'],
76
                stderr=subprocess.PIPE,
77
                stdout=subprocess.PIPE)
78
            proc.communicate()
79
            return True
80
        except OSError, e:
81
            if e.errno == errno.ENOENT:
82
                # strace is not installed
83
                return False
84
            else:
85
                raise
86
87
    def feature_name(self):
88
        return 'strace'
89
90
StraceFeature = _StraceFeature()