14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
"""Transport decorator that logs transport operations to .bzr.log."""
17
"""Transport decorator that logs transport operations to brz.log."""
20
19
# see also the transportstats plugin, which gives you some summary information
21
20
# in a machine-readable dump
28
from bzrlib.trace import mutter
29
from bzrlib.transport import decorator
25
from ..trace import mutter
26
from ..transport import decorator
32
29
class TransportLogDecorator(decorator.TransportDecorator):
33
"""Decorator for Transports that logs interesting operations to .bzr.log.
30
"""Decorator for Transports that logs interesting operations to brz.log.
35
32
In general we want to log things that usually take a network round trip
38
35
Not all operations are logged yet.
40
See also TransportTraceDecorator, that records a machine-readable log in
37
See also TransportTraceDecorator, that records a machine-readable log in
41
38
memory for eg testing.
44
41
def __init__(self, *args, **kw):
45
42
super(TransportLogDecorator, self).__init__(*args, **kw)
46
44
def _make_hook(hookname):
47
45
def _hook(relpath, *args, **kw):
48
46
return self._log_and_call(hookname, relpath, *args, **kw)
48
# GZ 2017-05-21: Not all methods take relpath as first argument, for
49
# instance copy_to takes list of relpaths. Also, unclear on url vs
50
# filesystem path split. Needs tidying up.
50
51
for methodname in (
60
'put_bytes', 'put_bytes_non_atomic', 'put_file put_file_non_atomic',
61
'list_dir', 'lock_read', 'lock_write',
62
'readv', 'rename', 'rmdir',
61
'put_bytes', 'put_bytes_non_atomic', 'put_file put_file_non_atomic',
62
'list_dir', 'lock_read', 'lock_write',
63
'readv', 'rename', 'rmdir',
66
67
setattr(self, methodname, _make_hook(methodname))
72
73
def iter_files_recursive(self):
73
74
# needs special handling because it does not have a relpath parameter
75
% ('iter_files_recursive', self._decorated.base))
76
% ('iter_files_recursive', self._decorated.base))
76
77
return self._call_and_log_result('iter_files_recursive', (), {})
78
79
def _log_and_call(self, methodname, relpath, *args, **kwargs):
108
109
return_result = iter(result)
110
111
return_result = result
111
if isinstance(result, (cStringIO.OutputType, StringIO.StringIO)):
112
val = repr(result.getvalue())
112
# Is this an io object with a getvalue() method?
113
getvalue = getattr(result, 'getvalue', None)
114
if getvalue is not None:
115
val = repr(getvalue())
113
116
result_len = len(val)
114
117
shown_result = "%s(%s) (%d bytes)" % (result.__class__.__name__,
115
self._shorten(val), result_len)
118
self._shorten(val), result_len)
116
119
elif methodname == 'readv':
117
120
num_hunks = len(result)
118
total_bytes = sum((len(d) for o,d in result))
121
total_bytes = sum((len(d) for o, d in result))
119
122
shown_result = "readv response, %d hunks, %d total bytes" % (
120
123
num_hunks, total_bytes)
121
124
result_len = total_bytes
131
134
# this is the rate of higher-level data, not the raw network
132
135
# speed using base-10 units (see HACKING.txt).
133
136
mutter(" %9.03fs %8dkB/s"
134
% (elapsed, result_len/elapsed/1000))
137
% (elapsed, result_len / elapsed / 1000))
136
139
mutter(" %9.03fs" % (elapsed))
137
140
return return_result