Mercurial > hg
comparison hgext/blackbox.py @ 19066:2cad301a7f06
blackbox: automatically rotate log files
If enabled, log rotation prevents the amount of space used by the
blackbox log from growing without bound. This becomes important in
cases where there are a lot of busy repositories managed by humans
and automation on many machines.
In large deployments, we cannot reasonably track all the repos where
blackbox logs need to be managed, so it is safer to have blackbox
manage its own logs than to move responsibility to an external tool
such as logrotate.
This change adds two configuration keys:
* blackbox.maxsize is the maximum allowable size of the current log
* blackbox.maxfiles is the number of log files to maintain
author | Bryan O'Sullivan <bryano@fb.com> |
---|---|
date | Thu, 18 Apr 2013 16:17:59 -0700 |
parents | 63a783d1ac85 |
children | 27013ace80eb |
comparison
equal
deleted
inserted
replaced
19065:2c4cd1c42365 | 19066:2cad301a7f06 |
---|---|
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] | |
25 # limit the size of a log file | |
26 maxsize = 1.5 MB | |
27 # rotate up to N log files when the current one gets too big | |
28 maxfiles = 3 | |
29 | |
24 """ | 30 """ |
25 | 31 |
26 from mercurial import util, cmdutil | 32 from mercurial import util, cmdutil |
27 from mercurial.i18n import _ | 33 from mercurial.i18n import _ |
28 import os, re | 34 import errno, os, re |
29 | 35 |
30 cmdtable = {} | 36 cmdtable = {} |
31 command = cmdutil.command(cmdtable) | 37 command = cmdutil.command(cmdtable) |
32 testedwith = 'internal' | 38 testedwith = 'internal' |
33 lastblackbox = None | 39 lastblackbox = None |
36 class blackboxui(ui.__class__): | 42 class blackboxui(ui.__class__): |
37 @util.propertycache | 43 @util.propertycache |
38 def track(self): | 44 def track(self): |
39 return self.configlist('blackbox', 'track', ['*']) | 45 return self.configlist('blackbox', 'track', ['*']) |
40 | 46 |
47 def _openlogfile(self): | |
48 def rotate(oldpath, newpath): | |
49 try: | |
50 os.unlink(newpath) | |
51 except OSError, err: | |
52 if err.errno != errno.ENOENT: | |
53 self.debug("warning: cannot remove '%s': %s\n" % | |
54 (newpath, err.strerror)) | |
55 try: | |
56 if newpath: | |
57 os.rename(oldpath, newpath) | |
58 except OSError, err: | |
59 if err.errno != errno.ENOENT: | |
60 self.debug("warning: cannot rename '%s' to '%s': %s\n" % | |
61 (newpath, oldpath, err.strerror)) | |
62 | |
63 fp = self._bbopener('blackbox.log', 'a') | |
64 maxsize = self.configbytes('blackbox', 'maxsize', 1048576) | |
65 if maxsize > 0: | |
66 st = os.fstat(fp.fileno()) | |
67 if st.st_size >= maxsize: | |
68 path = fp.name | |
69 fp.close() | |
70 maxfiles = self.configint('blackbox', 'maxfiles', 7) | |
71 for i in xrange(maxfiles - 1, 1, -1): | |
72 rotate(oldpath='%s.%d' % (path, i - 1), | |
73 newpath='%s.%d' % (path, i)) | |
74 rotate(oldpath=path, | |
75 newpath=maxfiles > 0 and path + '.1') | |
76 fp = self._bbopener('blackbox.log', 'a') | |
77 return fp | |
78 | |
41 def log(self, event, *msg, **opts): | 79 def log(self, event, *msg, **opts): |
42 global lastblackbox | 80 global lastblackbox |
43 super(blackboxui, self).log(event, *msg, **opts) | 81 super(blackboxui, self).log(event, *msg, **opts) |
44 | 82 |
45 if not '*' in self.track and not event in self.track: | 83 if not '*' in self.track and not event in self.track: |
47 | 85 |
48 if util.safehasattr(self, '_blackbox'): | 86 if util.safehasattr(self, '_blackbox'): |
49 blackbox = self._blackbox | 87 blackbox = self._blackbox |
50 elif util.safehasattr(self, '_bbopener'): | 88 elif util.safehasattr(self, '_bbopener'): |
51 try: | 89 try: |
52 self._blackbox = self._bbopener('blackbox.log', 'a') | 90 self._blackbox = self._openlogfile() |
53 except (IOError, OSError), err: | 91 except (IOError, OSError), err: |
54 self.debug('warning: cannot write to blackbox.log: %s\n' % | 92 self.debug('warning: cannot write to blackbox.log: %s\n' % |
55 err.strerror) | 93 err.strerror) |
56 del self._bbopener | 94 del self._bbopener |
57 self._blackbox = None | 95 self._blackbox = None |