##// END OF EJS Templates
blackbox: Remove misleading quotes in config example...
Simon Sapin -
r47342:36f3a648 default
parent child Browse files
Show More
@@ -1,232 +1,232 b''
1 1 # blackbox.py - log repository events to a file for post-mortem debugging
2 2 #
3 3 # Copyright 2010 Nicolas Dumazet
4 4 # Copyright 2013 Facebook, Inc.
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 """log repository events to a blackbox for debugging
10 10
11 11 Logs event information to .hg/blackbox.log to help debug and diagnose problems.
12 12 The events that get logged can be configured via the blackbox.track and
13 13 blackbox.ignore config keys.
14 14
15 15 Examples::
16 16
17 17 [blackbox]
18 18 track = *
19 19 ignore = pythonhook
20 20 # dirty is *EXPENSIVE* (slow);
21 21 # each log entry indicates `+` if the repository is dirty, like :hg:`id`.
22 22 dirty = True
23 23 # record the source of log messages
24 24 logsource = True
25 25
26 26 [blackbox]
27 27 track = command, commandfinish, commandexception, exthook, pythonhook
28 28
29 29 [blackbox]
30 30 track = incoming
31 31
32 32 [blackbox]
33 33 # limit the size of a log file
34 34 maxsize = 1.5 MB
35 35 # rotate up to N log files when the current one gets too big
36 36 maxfiles = 3
37 37
38 38 [blackbox]
39 39 # Include nanoseconds in log entries with %f (see Python function
40 40 # datetime.datetime.strftime)
41 date-format = '%Y-%m-%d @ %H:%M:%S.%f'
41 date-format = %Y-%m-%d @ %H:%M:%S.%f
42 42
43 43 """
44 44
45 45 from __future__ import absolute_import
46 46
47 47 import re
48 48
49 49 from mercurial.i18n import _
50 50 from mercurial.node import hex
51 51
52 52 from mercurial import (
53 53 encoding,
54 54 loggingutil,
55 55 registrar,
56 56 )
57 57 from mercurial.utils import (
58 58 dateutil,
59 59 procutil,
60 60 )
61 61
62 62 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
63 63 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
64 64 # be specifying the version(s) of Mercurial they are tested with, or
65 65 # leave the attribute unspecified.
66 66 testedwith = b'ships-with-hg-core'
67 67
68 68 cmdtable = {}
69 69 command = registrar.command(cmdtable)
70 70
71 71 configtable = {}
72 72 configitem = registrar.configitem(configtable)
73 73
74 74 configitem(
75 75 b'blackbox',
76 76 b'dirty',
77 77 default=False,
78 78 )
79 79 configitem(
80 80 b'blackbox',
81 81 b'maxsize',
82 82 default=b'1 MB',
83 83 )
84 84 configitem(
85 85 b'blackbox',
86 86 b'logsource',
87 87 default=False,
88 88 )
89 89 configitem(
90 90 b'blackbox',
91 91 b'maxfiles',
92 92 default=7,
93 93 )
94 94 configitem(
95 95 b'blackbox',
96 96 b'track',
97 97 default=lambda: [b'*'],
98 98 )
99 99 configitem(
100 100 b'blackbox',
101 101 b'ignore',
102 102 default=lambda: [b'chgserver', b'cmdserver', b'extension'],
103 103 )
104 104 configitem(
105 105 b'blackbox',
106 106 b'date-format',
107 107 default=b'%Y/%m/%d %H:%M:%S',
108 108 )
109 109
110 110 _lastlogger = loggingutil.proxylogger()
111 111
112 112
113 113 class blackboxlogger(object):
114 114 def __init__(self, ui, repo):
115 115 self._repo = repo
116 116 self._trackedevents = set(ui.configlist(b'blackbox', b'track'))
117 117 self._ignoredevents = set(ui.configlist(b'blackbox', b'ignore'))
118 118 self._maxfiles = ui.configint(b'blackbox', b'maxfiles')
119 119 self._maxsize = ui.configbytes(b'blackbox', b'maxsize')
120 120 self._inlog = False
121 121
122 122 def tracked(self, event):
123 123 return (
124 124 b'*' in self._trackedevents and event not in self._ignoredevents
125 125 ) or event in self._trackedevents
126 126
127 127 def log(self, ui, event, msg, opts):
128 128 # self._log() -> ctx.dirty() may create new subrepo instance, which
129 129 # ui is derived from baseui. So the recursion guard in ui.log()
130 130 # doesn't work as it's local to the ui instance.
131 131 if self._inlog:
132 132 return
133 133 self._inlog = True
134 134 try:
135 135 self._log(ui, event, msg, opts)
136 136 finally:
137 137 self._inlog = False
138 138
139 139 def _log(self, ui, event, msg, opts):
140 140 default = ui.configdate(b'devel', b'default-date')
141 141 date = dateutil.datestr(default, ui.config(b'blackbox', b'date-format'))
142 142 user = procutil.getuser()
143 143 pid = b'%d' % procutil.getpid()
144 144 changed = b''
145 145 ctx = self._repo[None]
146 146 parents = ctx.parents()
147 147 rev = b'+'.join([hex(p.node()) for p in parents])
148 148 if ui.configbool(b'blackbox', b'dirty') and ctx.dirty(
149 149 missing=True, merge=False, branch=False
150 150 ):
151 151 changed = b'+'
152 152 if ui.configbool(b'blackbox', b'logsource'):
153 153 src = b' [%s]' % event
154 154 else:
155 155 src = b''
156 156 try:
157 157 fmt = b'%s %s @%s%s (%s)%s> %s'
158 158 args = (date, user, rev, changed, pid, src, msg)
159 159 with loggingutil.openlogfile(
160 160 ui,
161 161 self._repo.vfs,
162 162 name=b'blackbox.log',
163 163 maxfiles=self._maxfiles,
164 164 maxsize=self._maxsize,
165 165 ) as fp:
166 166 fp.write(fmt % args)
167 167 except (IOError, OSError) as err:
168 168 # deactivate this to avoid failed logging again
169 169 self._trackedevents.clear()
170 170 ui.debug(
171 171 b'warning: cannot write to blackbox.log: %s\n'
172 172 % encoding.strtolocal(err.strerror)
173 173 )
174 174 return
175 175 _lastlogger.logger = self
176 176
177 177
178 178 def uipopulate(ui):
179 179 ui.setlogger(b'blackbox', _lastlogger)
180 180
181 181
182 182 def reposetup(ui, repo):
183 183 # During 'hg pull' a httppeer repo is created to represent the remote repo.
184 184 # It doesn't have a .hg directory to put a blackbox in, so we don't do
185 185 # the blackbox setup for it.
186 186 if not repo.local():
187 187 return
188 188
189 189 # Since blackbox.log is stored in the repo directory, the logger should be
190 190 # instantiated per repository.
191 191 logger = blackboxlogger(ui, repo)
192 192 ui.setlogger(b'blackbox', logger)
193 193
194 194 # Set _lastlogger even if ui.log is not called. This gives blackbox a
195 195 # fallback place to log
196 196 if _lastlogger.logger is None:
197 197 _lastlogger.logger = logger
198 198
199 199 repo._wlockfreeprefix.add(b'blackbox.log')
200 200
201 201
202 202 @command(
203 203 b'blackbox',
204 204 [
205 205 (b'l', b'limit', 10, _(b'the number of events to show')),
206 206 ],
207 207 _(b'hg blackbox [OPTION]...'),
208 208 helpcategory=command.CATEGORY_MAINTENANCE,
209 209 helpbasic=True,
210 210 )
211 211 def blackbox(ui, repo, *revs, **opts):
212 212 """view the recent repository events"""
213 213
214 214 if not repo.vfs.exists(b'blackbox.log'):
215 215 return
216 216
217 217 limit = opts.get('limit')
218 218 fp = repo.vfs(b'blackbox.log', b'r')
219 219 lines = fp.read().split(b'\n')
220 220
221 221 count = 0
222 222 output = []
223 223 for line in reversed(lines):
224 224 if count >= limit:
225 225 break
226 226
227 227 # count the commands by matching lines like: 2013/01/23 19:13:36 root>
228 228 if re.match(br'^\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} .*> .*', line):
229 229 count += 1
230 230 output.append(line)
231 231
232 232 ui.status(b'\n'.join(reversed(output)))
General Comments 0
You need to be logged in to leave comments. Login now