##// END OF EJS Templates
blackbox: fix literal block syntax
Takumi IINO -
r19162:27013ace stable
parent child Browse files
Show More
@@ -1,157 +1,157 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 [blackbox]
24 [blackbox]
25 # limit the size of a log file
25 # limit the size of a log file
26 maxsize = 1.5 MB
26 maxsize = 1.5 MB
27 # rotate up to N log files when the current one gets too big
27 # rotate up to N log files when the current one gets too big
28 maxfiles = 3
28 maxfiles = 3
29
29
30 """
30 """
31
31
32 from mercurial import util, cmdutil
32 from mercurial import util, cmdutil
33 from mercurial.i18n import _
33 from mercurial.i18n import _
34 import errno, os, re
34 import errno, os, re
35
35
36 cmdtable = {}
36 cmdtable = {}
37 command = cmdutil.command(cmdtable)
37 command = cmdutil.command(cmdtable)
38 testedwith = 'internal'
38 testedwith = 'internal'
39 lastblackbox = None
39 lastblackbox = None
40
40
41 def wrapui(ui):
41 def wrapui(ui):
42 class blackboxui(ui.__class__):
42 class blackboxui(ui.__class__):
43 @util.propertycache
43 @util.propertycache
44 def track(self):
44 def track(self):
45 return self.configlist('blackbox', 'track', ['*'])
45 return self.configlist('blackbox', 'track', ['*'])
46
46
47 def _openlogfile(self):
47 def _openlogfile(self):
48 def rotate(oldpath, newpath):
48 def rotate(oldpath, newpath):
49 try:
49 try:
50 os.unlink(newpath)
50 os.unlink(newpath)
51 except OSError, err:
51 except OSError, err:
52 if err.errno != errno.ENOENT:
52 if err.errno != errno.ENOENT:
53 self.debug("warning: cannot remove '%s': %s\n" %
53 self.debug("warning: cannot remove '%s': %s\n" %
54 (newpath, err.strerror))
54 (newpath, err.strerror))
55 try:
55 try:
56 if newpath:
56 if newpath:
57 os.rename(oldpath, newpath)
57 os.rename(oldpath, newpath)
58 except OSError, err:
58 except OSError, err:
59 if err.errno != errno.ENOENT:
59 if err.errno != errno.ENOENT:
60 self.debug("warning: cannot rename '%s' to '%s': %s\n" %
60 self.debug("warning: cannot rename '%s' to '%s': %s\n" %
61 (newpath, oldpath, err.strerror))
61 (newpath, oldpath, err.strerror))
62
62
63 fp = self._bbopener('blackbox.log', 'a')
63 fp = self._bbopener('blackbox.log', 'a')
64 maxsize = self.configbytes('blackbox', 'maxsize', 1048576)
64 maxsize = self.configbytes('blackbox', 'maxsize', 1048576)
65 if maxsize > 0:
65 if maxsize > 0:
66 st = os.fstat(fp.fileno())
66 st = os.fstat(fp.fileno())
67 if st.st_size >= maxsize:
67 if st.st_size >= maxsize:
68 path = fp.name
68 path = fp.name
69 fp.close()
69 fp.close()
70 maxfiles = self.configint('blackbox', 'maxfiles', 7)
70 maxfiles = self.configint('blackbox', 'maxfiles', 7)
71 for i in xrange(maxfiles - 1, 1, -1):
71 for i in xrange(maxfiles - 1, 1, -1):
72 rotate(oldpath='%s.%d' % (path, i - 1),
72 rotate(oldpath='%s.%d' % (path, i - 1),
73 newpath='%s.%d' % (path, i))
73 newpath='%s.%d' % (path, i))
74 rotate(oldpath=path,
74 rotate(oldpath=path,
75 newpath=maxfiles > 0 and path + '.1')
75 newpath=maxfiles > 0 and path + '.1')
76 fp = self._bbopener('blackbox.log', 'a')
76 fp = self._bbopener('blackbox.log', 'a')
77 return fp
77 return fp
78
78
79 def log(self, event, *msg, **opts):
79 def log(self, event, *msg, **opts):
80 global lastblackbox
80 global lastblackbox
81 super(blackboxui, self).log(event, *msg, **opts)
81 super(blackboxui, self).log(event, *msg, **opts)
82
82
83 if not '*' in self.track and not event in self.track:
83 if not '*' in self.track and not event in self.track:
84 return
84 return
85
85
86 if util.safehasattr(self, '_blackbox'):
86 if util.safehasattr(self, '_blackbox'):
87 blackbox = self._blackbox
87 blackbox = self._blackbox
88 elif util.safehasattr(self, '_bbopener'):
88 elif util.safehasattr(self, '_bbopener'):
89 try:
89 try:
90 self._blackbox = self._openlogfile()
90 self._blackbox = self._openlogfile()
91 except (IOError, OSError), err:
91 except (IOError, OSError), err:
92 self.debug('warning: cannot write to blackbox.log: %s\n' %
92 self.debug('warning: cannot write to blackbox.log: %s\n' %
93 err.strerror)
93 err.strerror)
94 del self._bbopener
94 del self._bbopener
95 self._blackbox = None
95 self._blackbox = None
96 blackbox = self._blackbox
96 blackbox = self._blackbox
97 else:
97 else:
98 # certain ui instances exist outside the context of
98 # certain ui instances exist outside the context of
99 # a repo, so just default to the last blackbox that
99 # a repo, so just default to the last blackbox that
100 # was seen.
100 # was seen.
101 blackbox = lastblackbox
101 blackbox = lastblackbox
102
102
103 if blackbox:
103 if blackbox:
104 date = util.datestr(None, '%Y/%m/%d %H:%M:%S')
104 date = util.datestr(None, '%Y/%m/%d %H:%M:%S')
105 user = util.getuser()
105 user = util.getuser()
106 formattedmsg = msg[0] % msg[1:]
106 formattedmsg = msg[0] % msg[1:]
107 try:
107 try:
108 blackbox.write('%s %s> %s' % (date, user, formattedmsg))
108 blackbox.write('%s %s> %s' % (date, user, formattedmsg))
109 except IOError, err:
109 except IOError, err:
110 self.debug('warning: cannot write to blackbox.log: %s\n' %
110 self.debug('warning: cannot write to blackbox.log: %s\n' %
111 err.strerror)
111 err.strerror)
112 lastblackbox = blackbox
112 lastblackbox = blackbox
113
113
114 def setrepo(self, repo):
114 def setrepo(self, repo):
115 self._bbopener = repo.opener
115 self._bbopener = repo.opener
116
116
117 ui.__class__ = blackboxui
117 ui.__class__ = blackboxui
118
118
119 def uisetup(ui):
119 def uisetup(ui):
120 wrapui(ui)
120 wrapui(ui)
121
121
122 def reposetup(ui, repo):
122 def reposetup(ui, repo):
123 # During 'hg pull' a httppeer repo is created to represent the remote repo.
123 # During 'hg pull' a httppeer repo is created to represent the remote repo.
124 # It doesn't have a .hg directory to put a blackbox in, so we don't do
124 # It doesn't have a .hg directory to put a blackbox in, so we don't do
125 # the blackbox setup for it.
125 # the blackbox setup for it.
126 if not repo.local():
126 if not repo.local():
127 return
127 return
128
128
129 ui.setrepo(repo)
129 ui.setrepo(repo)
130
130
131 @command('^blackbox',
131 @command('^blackbox',
132 [('l', 'limit', 10, _('the number of events to show')),
132 [('l', 'limit', 10, _('the number of events to show')),
133 ],
133 ],
134 _('hg blackbox [OPTION]...'))
134 _('hg blackbox [OPTION]...'))
135 def blackbox(ui, repo, *revs, **opts):
135 def blackbox(ui, repo, *revs, **opts):
136 '''view the recent repository events
136 '''view the recent repository events
137 '''
137 '''
138
138
139 if not os.path.exists(repo.join('blackbox.log')):
139 if not os.path.exists(repo.join('blackbox.log')):
140 return
140 return
141
141
142 limit = opts.get('limit')
142 limit = opts.get('limit')
143 blackbox = repo.opener('blackbox.log', 'r')
143 blackbox = repo.opener('blackbox.log', 'r')
144 lines = blackbox.read().split('\n')
144 lines = blackbox.read().split('\n')
145
145
146 count = 0
146 count = 0
147 output = []
147 output = []
148 for line in reversed(lines):
148 for line in reversed(lines):
149 if count >= limit:
149 if count >= limit:
150 break
150 break
151
151
152 # count the commands by matching lines like: 2013/01/23 19:13:36 root>
152 # count the commands by matching lines like: 2013/01/23 19:13:36 root>
153 if re.match('^\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} .*> .*', line):
153 if re.match('^\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} .*> .*', line):
154 count += 1
154 count += 1
155 output.append(line)
155 output.append(line)
156
156
157 ui.status('\n'.join(reversed(output)))
157 ui.status('\n'.join(reversed(output)))
General Comments 0
You need to be logged in to leave comments. Login now