##// END OF EJS Templates
blackbox: defer opening a log file until needed (issue3869)...
Bryan O'Sullivan -
r18831:17f6644a default
parent child Browse files
Show More
@@ -1,115 +1,119 b''
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 elif util.safehasattr(self, '_bbopener'):
51 try:
52 self._blackbox = self._bbopener('blackbox.log', 'a')
53 except (IOError, OSError), err:
54 self.debug('warning: cannot write to blackbox.log: %s\n' %
55 err.strerror)
56 del self._bbopener
57 self._blackbox = None
58 blackbox = self._blackbox
50 else:
59 else:
51 # certain ui instances exist outside the context of
60 # certain ui instances exist outside the context of
52 # a repo, so just default to the last blackbox that
61 # a repo, so just default to the last blackbox that
53 # was seen.
62 # was seen.
54 blackbox = lastblackbox
63 blackbox = lastblackbox
55
64
56 if blackbox:
65 if blackbox:
57 date = util.datestr(None, '%Y/%m/%d %H:%M:%S')
66 date = util.datestr(None, '%Y/%m/%d %H:%M:%S')
58 user = util.getuser()
67 user = util.getuser()
59 formattedmsg = msg[0] % msg[1:]
68 formattedmsg = msg[0] % msg[1:]
60 try:
69 try:
61 blackbox.write('%s %s> %s' % (date, user, formattedmsg))
70 blackbox.write('%s %s> %s' % (date, user, formattedmsg))
62 except IOError, err:
71 except IOError, err:
63 self.debug('warning: cannot write to blackbox.log: %s\n' %
72 self.debug('warning: cannot write to blackbox.log: %s\n' %
64 err.strerror)
73 err.strerror)
65 lastblackbox = blackbox
74 lastblackbox = blackbox
66
75
67 def setrepo(self, repo):
76 def setrepo(self, repo):
68 try:
77 self._bbopener = repo.opener
69 self._blackbox = repo.opener('blackbox.log', 'a')
70 except (IOError, OSError), err:
71 self.debug('warning: cannot write to blackbox.log: %s\n' %
72 err.strerror)
73 self._blackbox = None
74
78
75 ui.__class__ = blackboxui
79 ui.__class__ = blackboxui
76
80
77 def uisetup(ui):
81 def uisetup(ui):
78 wrapui(ui)
82 wrapui(ui)
79
83
80 def reposetup(ui, repo):
84 def reposetup(ui, repo):
81 # During 'hg pull' a httppeer repo is created to represent the remote repo.
85 # 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
86 # It doesn't have a .hg directory to put a blackbox in, so we don't do
83 # the blackbox setup for it.
87 # the blackbox setup for it.
84 if not repo.local():
88 if not repo.local():
85 return
89 return
86
90
87 ui.setrepo(repo)
91 ui.setrepo(repo)
88
92
89 @command('^blackbox',
93 @command('^blackbox',
90 [('l', 'limit', 10, _('the number of events to show')),
94 [('l', 'limit', 10, _('the number of events to show')),
91 ],
95 ],
92 _('hg blackbox [OPTION]...'))
96 _('hg blackbox [OPTION]...'))
93 def blackbox(ui, repo, *revs, **opts):
97 def blackbox(ui, repo, *revs, **opts):
94 '''view the recent repository events
98 '''view the recent repository events
95 '''
99 '''
96
100
97 if not os.path.exists(repo.join('blackbox.log')):
101 if not os.path.exists(repo.join('blackbox.log')):
98 return
102 return
99
103
100 limit = opts.get('limit')
104 limit = opts.get('limit')
101 blackbox = repo.opener('blackbox.log', 'r')
105 blackbox = repo.opener('blackbox.log', 'r')
102 lines = blackbox.read().split('\n')
106 lines = blackbox.read().split('\n')
103
107
104 count = 0
108 count = 0
105 output = []
109 output = []
106 for line in reversed(lines):
110 for line in reversed(lines):
107 if count >= limit:
111 if count >= limit:
108 break
112 break
109
113
110 # count the commands by matching lines like: 2013/01/23 19:13:36 root>
114 # 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):
115 if re.match('^\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} .*> .*', line):
112 count += 1
116 count += 1
113 output.append(line)
117 output.append(line)
114
118
115 ui.status('\n'.join(reversed(output)))
119 ui.status('\n'.join(reversed(output)))
General Comments 0
You need to be logged in to leave comments. Login now