##// END OF EJS Templates
blackbox: account for another source of errors
Bryan O'Sullivan -
r18810:ac033647 default
parent child Browse files
Show More
@@ -1,115 +1,115
1 # blackbox.py - log repository events to a file for post-mortem debugging
1 # blackbox.py - log repository events to a file for post-mortem debugging
2 #
2 #
3 # Copyright 2010 Nicolas Dumazet
3 # Copyright 2010 Nicolas Dumazet
4 # Copyright 2013 Facebook, Inc.
4 # Copyright 2013 Facebook, Inc.
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 """log repository events to a blackbox for debugging
9 """log repository events to a blackbox for debugging
10
10
11 Logs event information to .hg/blackbox.log to help debug and diagnose problems.
11 Logs event information to .hg/blackbox.log to help debug and diagnose problems.
12 The events that get logged can be configured via the blackbox.track config key.
12 The events that get logged can be configured via the blackbox.track config key.
13 Examples:
13 Examples:
14
14
15 [blackbox]
15 [blackbox]
16 track = *
16 track = *
17
17
18 [blackbox]
18 [blackbox]
19 track = command, commandfinish, commandexception, exthook, pythonhook
19 track = command, commandfinish, commandexception, exthook, pythonhook
20
20
21 [blackbox]
21 [blackbox]
22 track = incoming
22 track = incoming
23
23
24 """
24 """
25
25
26 from mercurial import util, cmdutil
26 from mercurial import util, cmdutil
27 from mercurial.i18n import _
27 from mercurial.i18n import _
28 import os, re
28 import os, re
29
29
30 cmdtable = {}
30 cmdtable = {}
31 command = cmdutil.command(cmdtable)
31 command = cmdutil.command(cmdtable)
32 testedwith = 'internal'
32 testedwith = 'internal'
33 lastblackbox = None
33 lastblackbox = None
34
34
35 def wrapui(ui):
35 def wrapui(ui):
36 class blackboxui(ui.__class__):
36 class blackboxui(ui.__class__):
37 @util.propertycache
37 @util.propertycache
38 def track(self):
38 def track(self):
39 return ui.configlist('blackbox', 'track', ['*'])
39 return ui.configlist('blackbox', 'track', ['*'])
40
40
41 def log(self, event, *msg, **opts):
41 def log(self, event, *msg, **opts):
42 global lastblackbox
42 global lastblackbox
43 super(blackboxui, self).log(event, *msg, **opts)
43 super(blackboxui, self).log(event, *msg, **opts)
44
44
45 if not '*' in self.track and not event in self.track:
45 if not '*' in self.track and not event in self.track:
46 return
46 return
47
47
48 if util.safehasattr(self, '_blackbox'):
48 if util.safehasattr(self, '_blackbox'):
49 blackbox = self._blackbox
49 blackbox = self._blackbox
50 else:
50 else:
51 # certain ui instances exist outside the context of
51 # certain ui instances exist outside the context of
52 # a repo, so just default to the last blackbox that
52 # a repo, so just default to the last blackbox that
53 # was seen.
53 # was seen.
54 blackbox = lastblackbox
54 blackbox = lastblackbox
55
55
56 if blackbox:
56 if blackbox:
57 date = util.datestr(None, '%Y/%m/%d %H:%M:%S')
57 date = util.datestr(None, '%Y/%m/%d %H:%M:%S')
58 user = util.getuser()
58 user = util.getuser()
59 formattedmsg = msg[0] % msg[1:]
59 formattedmsg = msg[0] % msg[1:]
60 try:
60 try:
61 blackbox.write('%s %s> %s' % (date, user, formattedmsg))
61 blackbox.write('%s %s> %s' % (date, user, formattedmsg))
62 except IOError, err:
62 except IOError, err:
63 self.debug('warning: cannot write to blackbox.log: %s\n' %
63 self.debug('warning: cannot write to blackbox.log: %s\n' %
64 err.strerror)
64 err.strerror)
65 lastblackbox = blackbox
65 lastblackbox = blackbox
66
66
67 def setrepo(self, repo):
67 def setrepo(self, repo):
68 try:
68 try:
69 self._blackbox = repo.opener('blackbox.log', 'a')
69 self._blackbox = repo.opener('blackbox.log', 'a')
70 except IOError, err:
70 except (IOError, OSError), err:
71 self.debug('warning: cannot write to blackbox.log: %s\n' %
71 self.debug('warning: cannot write to blackbox.log: %s\n' %
72 err.strerror)
72 err.strerror)
73 self._blackbox = None
73 self._blackbox = None
74
74
75 ui.__class__ = blackboxui
75 ui.__class__ = blackboxui
76
76
77 def uisetup(ui):
77 def uisetup(ui):
78 wrapui(ui)
78 wrapui(ui)
79
79
80 def reposetup(ui, repo):
80 def reposetup(ui, repo):
81 # During 'hg pull' a httppeer repo is created to represent the remote repo.
81 # During 'hg pull' a httppeer repo is created to represent the remote repo.
82 # It doesn't have a .hg directory to put a blackbox in, so we don't do
82 # It doesn't have a .hg directory to put a blackbox in, so we don't do
83 # the blackbox setup for it.
83 # the blackbox setup for it.
84 if not repo.local():
84 if not repo.local():
85 return
85 return
86
86
87 ui.setrepo(repo)
87 ui.setrepo(repo)
88
88
89 @command('^blackbox',
89 @command('^blackbox',
90 [('l', 'limit', 10, _('the number of events to show')),
90 [('l', 'limit', 10, _('the number of events to show')),
91 ],
91 ],
92 _('hg blackbox [OPTION]...'))
92 _('hg blackbox [OPTION]...'))
93 def blackbox(ui, repo, *revs, **opts):
93 def blackbox(ui, repo, *revs, **opts):
94 '''view the recent repository events
94 '''view the recent repository events
95 '''
95 '''
96
96
97 if not os.path.exists(repo.join('blackbox.log')):
97 if not os.path.exists(repo.join('blackbox.log')):
98 return
98 return
99
99
100 limit = opts.get('limit')
100 limit = opts.get('limit')
101 blackbox = repo.opener('blackbox.log', 'r')
101 blackbox = repo.opener('blackbox.log', 'r')
102 lines = blackbox.read().split('\n')
102 lines = blackbox.read().split('\n')
103
103
104 count = 0
104 count = 0
105 output = []
105 output = []
106 for line in reversed(lines):
106 for line in reversed(lines):
107 if count >= limit:
107 if count >= limit:
108 break
108 break
109
109
110 # count the commands by matching lines like: 2013/01/23 19:13:36 root>
110 # count the commands by matching lines like: 2013/01/23 19:13:36 root>
111 if re.match('^\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} .*> .*', line):
111 if re.match('^\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} .*> .*', line):
112 count += 1
112 count += 1
113 output.append(line)
113 output.append(line)
114
114
115 ui.status('\n'.join(reversed(output)))
115 ui.status('\n'.join(reversed(output)))
General Comments 0
You need to be logged in to leave comments. Login now