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."""
19
from __future__ import absolute_import
20
21
# see also the transportstats plugin, which gives you some summary information
21
22
# in a machine-readable dump
28
from bzrlib.trace import mutter
29
from bzrlib.transport import decorator
27
from ..trace import mutter
28
from ..transport import decorator
32
31
class TransportLogDecorator(decorator.TransportDecorator):
33
"""Decorator for Transports that logs interesting operations to .bzr.log.
32
"""Decorator for Transports that logs interesting operations to brz.log.
35
34
In general we want to log things that usually take a network round trip
38
37
Not all operations are logged yet.
40
See also TransportTraceDecorator, that records a machine-readable log in
39
See also TransportTraceDecorator, that records a machine-readable log in
41
40
memory for eg testing.
44
43
def __init__(self, *args, **kw):
45
44
super(TransportLogDecorator, self).__init__(*args, **kw)
46
46
def _make_hook(hookname):
47
47
def _hook(relpath, *args, **kw):
48
48
return self._log_and_call(hookname, relpath, *args, **kw)
50
# GZ 2017-05-21: Not all methods take relpath as first argument, for
51
# instance copy_to takes list of relpaths. Also, unclear on url vs
52
# filesystem path split. Needs tidying up.
50
53
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',
63
'put_bytes', 'put_bytes_non_atomic', 'put_file put_file_non_atomic',
64
'list_dir', 'lock_read', 'lock_write',
65
'readv', 'rename', 'rmdir',
66
69
setattr(self, methodname, _make_hook(methodname))
72
75
def iter_files_recursive(self):
73
76
# needs special handling because it does not have a relpath parameter
75
% ('iter_files_recursive', self._decorated.base))
78
% ('iter_files_recursive', self._decorated.base))
76
79
return self._call_and_log_result('iter_files_recursive', (), {})
78
81
def _log_and_call(self, methodname, relpath, *args, **kwargs):
108
111
return_result = iter(result)
110
113
return_result = result
111
if isinstance(result, (cStringIO.OutputType, StringIO.StringIO)):
112
val = repr(result.getvalue())
114
# Is this an io object with a getvalue() method?
115
getvalue = getattr(result, 'getvalue', None)
116
if getvalue is not None:
117
val = repr(getvalue())
113
118
result_len = len(val)
114
119
shown_result = "%s(%s) (%d bytes)" % (result.__class__.__name__,
115
self._shorten(val), result_len)
120
self._shorten(val), result_len)
116
121
elif methodname == 'readv':
117
122
num_hunks = len(result)
118
total_bytes = sum((len(d) for o,d in result))
123
total_bytes = sum((len(d) for o, d in result))
119
124
shown_result = "readv response, %d hunks, %d total bytes" % (
120
125
num_hunks, total_bytes)
121
126
result_len = total_bytes
131
136
# this is the rate of higher-level data, not the raw network
132
137
# speed using base-10 units (see HACKING.txt).
133
138
mutter(" %9.03fs %8dkB/s"
134
% (elapsed, result_len/elapsed/1000))
139
% (elapsed, result_len / elapsed / 1000))
136
141
mutter(" %9.03fs" % (elapsed))
137
142
return return_result