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