##// END OF EJS Templates
admin-command: add verify command...
admin-command: add verify command Start using the 'admin' namespace by adding a 'verify' command. Invocation is 'admin::verify'. The idea is to progressively add more focused checks than the existing verify command. To do so we need an advanced way to express what we want to check. The first check for admin::verify is 'working-copy.dirstate' which has no options, because it was an easy first check to implement, which verifies the integrity of the dirstate. This changeset was created with the help of Franck Bret.

File last commit:

r51834:4323af38 stable
r51882:752c5a5b default
Show More
blackbox.py
207 lines | 6.2 KiB | text/x-python | PythonLexer
Bryan O'Sullivan
blackbox: fix copyright
r18676 # blackbox.py - log repository events to a file for post-mortem debugging
Durham Goode
blackbox: adds a blackbox extension...
r18669 #
Bryan O'Sullivan
blackbox: fix copyright
r18676 # Copyright 2010 Nicolas Dumazet
Durham Goode
blackbox: adds a blackbox extension...
r18669 # Copyright 2013 Facebook, Inc.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
"""log repository events to a blackbox for debugging
Logs event information to .hg/blackbox.log to help debug and diagnose problems.
Valentin Gatien-Baron
blackbox: disable extremely verbose logging (issue6110)...
r42834 The events that get logged can be configured via the blackbox.track and
blackbox.ignore config keys.
timeless
blackbox: log dirty state...
r28246
Takumi IINO
blackbox: fix literal block syntax
r19162 Examples::
Durham Goode
blackbox: adds a blackbox extension...
r18669
[blackbox]
track = *
Valentin Gatien-Baron
blackbox: disable extremely verbose logging (issue6110)...
r42834 ignore = pythonhook
timeless
blackbox: rewrite dirty documentation noting it is expensive
r28303 # dirty is *EXPENSIVE* (slow);
# each log entry indicates `+` if the repository is dirty, like :hg:`id`.
timeless
blackbox: log dirty state...
r28246 dirty = True
timeless
blackbox: optionally log event source
r28305 # record the source of log messages
logsource = True
Durham Goode
blackbox: adds a blackbox extension...
r18669
[blackbox]
track = command, commandfinish, commandexception, exthook, pythonhook
[blackbox]
track = incoming
Bryan O'Sullivan
blackbox: automatically rotate log files...
r19066 [blackbox]
# limit the size of a log file
maxsize = 1.5 MB
# rotate up to N log files when the current one gets too big
maxfiles = 3
Matt DeVore
blackbox: add configitem for format of log timestamps...
r40466 [blackbox]
Valentin Gatien-Baron
blackbox: correct date format doc...
r49419 # Include microseconds in log entries with %f (see Python function
Matt DeVore
blackbox: add configitem for format of log timestamps...
r40466 # datetime.datetime.strftime)
Simon Sapin
blackbox: Remove misleading quotes in config example...
r47342 date-format = %Y-%m-%d @ %H:%M:%S.%f
Matt DeVore
blackbox: add configitem for format of log timestamps...
r40466
Durham Goode
blackbox: adds a blackbox extension...
r18669 """
Gregory Szorc
blackbox: use absolute_import
r28090
import re
Durham Goode
blackbox: adds a blackbox extension...
r18669 from mercurial.i18n import _
timeless
blackbox: log working directory version...
r28245 from mercurial.node import hex
Gregory Szorc
blackbox: use absolute_import
r28090 from mercurial import (
Gregory Szorc
py3: cast error message to localstr in blackbox.py...
r35685 encoding,
Yuya Nishihara
loggingutil: extract openlogfile() and proxylogger to new module...
r40830 loggingutil,
Yuya Nishihara
registrar: move cmdutil.command to registrar module (API)...
r32337 registrar,
Gregory Szorc
blackbox: use absolute_import
r28090 )
Yuya Nishihara
procutil: bulk-replace function calls to point to new module
r37138 from mercurial.utils import (
dateutil,
procutil,
)
Durham Goode
blackbox: adds a blackbox extension...
r18669
Augie Fackler
extensions: change magic "shipped with hg" string...
r29841 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
Augie Fackler
extensions: document that `testedwith = 'internal'` is special...
r25186 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
# be specifying the version(s) of Mercurial they are tested with, or
# leave the attribute unspecified.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 testedwith = b'ships-with-hg-core'
blackbox: minor code reordering...
r33129
cmdtable = {}
command = registrar.command(cmdtable)
Yuya Nishihara
loggingutil: extract openlogfile() and proxylogger to new module...
r40830 _lastlogger = loggingutil.proxylogger()
Yuya Nishihara
blackbox: extract global last logger to proxylogger class...
r40795
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
py3: use class X: instead of class X(object):...
r49801 class blackboxlogger:
Yuya Nishihara
blackbox: initialize logger with repo instance...
r40797 def __init__(self, ui, repo):
self._repo = repo
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self._trackedevents = set(ui.configlist(b'blackbox', b'track'))
self._ignoredevents = set(ui.configlist(b'blackbox', b'ignore'))
self._maxfiles = ui.configint(b'blackbox', b'maxfiles')
self._maxsize = ui.configbytes(b'blackbox', b'maxsize')
Yuya Nishihara
blackbox: resurrect recursion guard...
r41029 self._inlog = False
Yuya Nishihara
blackbox: extract logger class from ui wrapper...
r40680
Yuya Nishihara
blackbox: extract function to test if log event is tracked...
r40684 def tracked(self, event):
Augie Fackler
formatting: blacken the codebase...
r43346 return (
b'*' in self._trackedevents and event not in self._ignoredevents
) or event in self._trackedevents
Yuya Nishihara
blackbox: extract function to test if log event is tracked...
r40684
Yuya Nishihara
blackbox: unindent "if True" block
r40681 def log(self, ui, event, msg, opts):
Yuya Nishihara
blackbox: resurrect recursion guard...
r41029 # self._log() -> ctx.dirty() may create new subrepo instance, which
# ui is derived from baseui. So the recursion guard in ui.log()
# doesn't work as it's local to the ui instance.
if self._inlog:
return
self._inlog = True
try:
self._log(ui, event, msg, opts)
finally:
self._inlog = False
def _log(self, ui, event, msg, opts):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 default = ui.configdate(b'devel', b'default-date')
Valentin Gatien-Baron
blackbox: add milliseconds to blackbox logs by default...
r49420 dateformat = ui.config(b'blackbox', b'date-format')
if dateformat:
date = dateutil.datestr(default, dateformat)
else:
# We want to display milliseconds (more precision seems
# unnecessary). Since %.3f is not supported, use %f and truncate
# microseconds.
Valentin Gatien-Baron
blackbox: change year in logs to ISO 8601 format...
r49421 date = dateutil.datestr(default, b'%Y-%m-%d %H:%M:%S.%f')[:-3]
Yuya Nishihara
blackbox: unindent "if True" block
r40681 user = procutil.getuser()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 pid = b'%d' % procutil.getpid()
changed = b''
Yuya Nishihara
blackbox: initialize repo attribute properly...
r40682 ctx = self._repo[None]
Yuya Nishihara
blackbox: unindent "if True" block
r40681 parents = ctx.parents()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 rev = b'+'.join([hex(p.node()) for p in parents])
if ui.configbool(b'blackbox', b'dirty') and ctx.dirty(
Augie Fackler
formatting: blacken the codebase...
r43346 missing=True, merge=False, branch=False
):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 changed = b'+'
if ui.configbool(b'blackbox', b'logsource'):
src = b' [%s]' % event
Yuya Nishihara
blackbox: unindent "if True" block
r40681 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 src = b''
Yuya Nishihara
blackbox: unindent "if True" block
r40681 try:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 fmt = b'%s %s @%s%s (%s)%s> %s'
Yuya Nishihara
ui: pass in formatted message to logger.log()...
r40793 args = (date, user, rev, changed, pid, src, msg)
Yuya Nishihara
loggingutil: extract openlogfile() and proxylogger to new module...
r40830 with loggingutil.openlogfile(
Augie Fackler
formatting: blacken the codebase...
r43346 ui,
self._repo.vfs,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 name=b'blackbox.log',
Augie Fackler
formatting: blacken the codebase...
r43346 maxfiles=self._maxfiles,
maxsize=self._maxsize,
) as fp:
Yuya Nishihara
blackbox: unindent "if True" block
r40681 fp.write(fmt % args)
except (IOError, OSError) as err:
Yuya Nishihara
blackbox: change the way of deactivating the logger on write error...
r40791 # deactivate this to avoid failed logging again
Yuya Nishihara
blackbox: do not nullify repo to deactivate the logger on failure...
r40796 self._trackedevents.clear()
Augie Fackler
formatting: blacken the codebase...
r43346 ui.debug(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'warning: cannot write to blackbox.log: %s\n'
Augie Fackler
formatting: blacken the codebase...
r43346 % encoding.strtolocal(err.strerror)
)
Yuya Nishihara
blackbox: just try writing to repo.vfs and update lastlogger on success...
r40828 return
_lastlogger.logger = self
Durham Goode
blackbox: adds a blackbox extension...
r18669
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
ui: manage logger instances and event filtering by core ui...
r40761 def uipopulate(ui):
Yuya Nishihara
blackbox: extract global last logger to proxylogger class...
r40795 ui.setlogger(b'blackbox', _lastlogger)
Yuya Nishihara
ui: manage logger instances and event filtering by core ui...
r40761
Augie Fackler
formatting: blacken the codebase...
r43346
Durham Goode
blackbox: adds a blackbox extension...
r18669 def reposetup(ui, repo):
# During 'hg pull' a httppeer repo is created to represent the remote repo.
# It doesn't have a .hg directory to put a blackbox in, so we don't do
# the blackbox setup for it.
if not repo.local():
return
Yuya Nishihara
ui: manage logger instances and event filtering by core ui...
r40761 # Since blackbox.log is stored in the repo directory, the logger should be
# instantiated per repository.
Yuya Nishihara
blackbox: initialize logger with repo instance...
r40797 logger = blackboxlogger(ui, repo)
Yuya Nishihara
ui: manage logger instances and event filtering by core ui...
r40761 ui.setlogger(b'blackbox', logger)
Jun Wu
blackbox: set lastui even if ui.log is not called (issue5518)...
r34277
Yuya Nishihara
blackbox: extract global last logger to proxylogger class...
r40795 # Set _lastlogger even if ui.log is not called. This gives blackbox a
# fallback place to log
if _lastlogger.logger is None:
_lastlogger.logger = logger
Jun Wu
blackbox: set lastui even if ui.log is not called (issue5518)...
r34277
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo._wlockfreeprefix.add(b'blackbox.log')
Durham Goode
blackbox: adds a 'blackbox' command for viewing recent logs...
r18673
Augie Fackler
formatting: blacken the codebase...
r43346
@command(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'blackbox',
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 [
(b'l', b'limit', 10, _(b'the number of events to show')),
],
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'hg blackbox [OPTION]...'),
Rodrigo Damazio
help: adding a proper declaration for shortlist/basic commands (API)...
r40331 helpcategory=command.CATEGORY_MAINTENANCE,
Augie Fackler
formatting: blacken the codebase...
r43346 helpbasic=True,
)
Durham Goode
blackbox: adds a 'blackbox' command for viewing recent logs...
r18673 def blackbox(ui, repo, *revs, **opts):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """view the recent repository events"""
Durham Goode
blackbox: adds a 'blackbox' command for viewing recent logs...
r18673
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if not repo.vfs.exists(b'blackbox.log'):
Durham Goode
blackbox: adds a 'blackbox' command for viewing recent logs...
r18673 return
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 limit = opts.get('limit')
Matt Harbison
typing: add some assertions that a variable isn't None...
r50748 assert limit is not None # help pytype
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 fp = repo.vfs(b'blackbox.log', b'r')
lines = fp.read().split(b'\n')
Durham Goode
blackbox: adds a 'blackbox' command for viewing recent logs...
r18673
count = 0
output = []
for line in reversed(lines):
if count >= limit:
break
Valentin Gatien-Baron
blackbox: change year in logs to ISO 8601 format...
r49421 # count the commands by matching lines like:
# 2013/01/23 19:13:36 root>
# 2013/01/23 19:13:36 root (1234)>
# 2013/01/23 19:13:36 root @0000000000000000000000000000000000000000 (1234)>
# 2013-01-23 19:13:36.000 root @0000000000000000000000000000000000000000 (1234)>
Valentin Gatien-Baron
blackbox: add milliseconds to blackbox logs by default...
r49420 if re.match(
Valentin Gatien-Baron
blackbox: change year in logs to ISO 8601 format...
r49421 br'^\d{4}[-/]\d{2}[-/]\d{2} \d{2}:\d{2}:\d{2}(.\d*)? .*> .*', line
Valentin Gatien-Baron
blackbox: add milliseconds to blackbox logs by default...
r49420 ):
Durham Goode
blackbox: adds a 'blackbox' command for viewing recent logs...
r18673 count += 1
output.append(line)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.status(b'\n'.join(reversed(output)))