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