# HG changeset patch # User Yuya Nishihara # Date 2018-11-11 09:08:33 # Node ID 55b053af7196c2965592a485dfefe303c6fdb236 # Parent c93d046d43004b91ed9e4c3680956ae7e11963c6 ui: manage logger instances and event filtering by core ui The setup code in blackbox needs more tweaks since it has lots of black magics. I'll fix them by follow-up patches. To be clear, the goal of this series is to provide a proper way for command server to install its own logger. I need it to debug in-memory repository cache. diff --git a/hgext/blackbox.py b/hgext/blackbox.py --- a/hgext/blackbox.py +++ b/hgext/blackbox.py @@ -53,7 +53,6 @@ from mercurial import ( pycompat, registrar, ui as uimod, - util, ) from mercurial.utils import ( dateutil, @@ -147,9 +146,6 @@ class blackboxlogger(object): def log(self, ui, event, msg, opts): global _lastlogger - if not self.tracked(event): - return - if self._bbvfs: _lastlogger = self elif _lastlogger and _lastlogger._bbvfs: @@ -201,33 +197,20 @@ class blackboxlogger(object): def wrapui(ui): class blackboxui(ui.__class__): - def __init__(self, src=None): - super(blackboxui, self).__init__(src) - if src and r'_bblogger' in src.__dict__: - self._bblogger = src._bblogger - - # trick to initialize logger after configuration is loaded, which - # can be replaced later with blackboxlogger(ui) in uisetup(), where - # both user and repo configurations should be available. - @util.propertycache - def _bblogger(self): - return blackboxlogger(self) - def debug(self, *msg, **opts): super(blackboxui, self).debug(*msg, **opts) if self.debugflag: self.log('debug', '%s', ''.join(msg)) - def log(self, event, *msg, **opts): - super(blackboxui, self).log(event, *msg, **opts) - self._bblogger.log(self, event, msg, opts) - ui.__class__ = blackboxui uimod.ui = blackboxui def uisetup(ui): wrapui(ui) +def uipopulate(ui): + ui.setlogger(b'blackbox', blackboxlogger(ui)) + 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 @@ -235,7 +218,10 @@ def reposetup(ui, repo): if not repo.local(): return - logger = getattr(ui, '_bblogger', None) + # Since blackbox.log is stored in the repo directory, the logger should be + # instantiated per repository. + logger = blackboxlogger(ui) + ui.setlogger(b'blackbox', logger) if logger: logger.setrepo(repo) diff --git a/hgext/logtoprocess.py b/hgext/logtoprocess.py --- a/hgext/logtoprocess.py +++ b/hgext/logtoprocess.py @@ -38,7 +38,6 @@ import os from mercurial import ( pycompat, - util, ) from mercurial.utils import ( procutil, @@ -63,9 +62,7 @@ class processlogger(object): return bool(self._scripts.get(event)) def log(self, ui, event, msg, opts): - script = self._scripts.get(event) - if not script: - return + script = self._scripts[event] env = { b'EVENT': event, b'HGPID': os.getpid(), @@ -77,24 +74,5 @@ class processlogger(object): fullenv = procutil.shellenviron(env) procutil.runbgcommand(script, fullenv, shell=True) -def uisetup(ui): - - class logtoprocessui(ui.__class__): - def __init__(self, src=None): - super(logtoprocessui, self).__init__(src) - if src and r'_ltplogger' in src.__dict__: - self._ltplogger = src._ltplogger - - # trick to initialize logger after configuration is loaded, which - # can be replaced later with processlogger(ui) in uisetup(), where - # both user and repo configurations should be available. - @util.propertycache - def _ltplogger(self): - return processlogger(self) - - def log(self, event, *msg, **opts): - self._ltplogger.log(self, event, msg, opts) - return super(logtoprocessui, self).log(event, *msg, **opts) - - # Replace the class for this instance and all clones created from it: - ui.__class__ = logtoprocessui +def uipopulate(ui): + ui.setlogger(b'logtoprocess', processlogger(ui)) diff --git a/mercurial/ui.py b/mercurial/ui.py --- a/mercurial/ui.py +++ b/mercurial/ui.py @@ -235,6 +235,7 @@ class ui(object): self._fmsgout = src._fmsgout self._fmsgerr = src._fmsgerr self._finoutredirected = src._finoutredirected + self._loggers = src._loggers.copy() self.pageractive = src.pageractive self._disablepager = src._disablepager self._tweaked = src._tweaked @@ -263,6 +264,7 @@ class ui(object): self._fmsgout = self.fout # configurable self._fmsgerr = self.ferr # configurable self._finoutredirected = False + self._loggers = {} self.pageractive = False self._disablepager = False self._tweaked = False @@ -1709,6 +1711,18 @@ class ui(object): '''exists only so low-level modules won't need to import scmutil''' return scmutil.progress(self, topic, unit, total) + def getlogger(self, name): + """Returns a logger of the given name; or None if not registered""" + return self._loggers.get(name) + + def setlogger(self, name, logger): + """Install logger which can be identified later by the given name + + More than one loggers can be registered. Use extension or module + name to uniquely identify the logger instance. + """ + self._loggers[name] = logger + def log(self, event, *msg, **opts): '''hook for logging facility extensions @@ -1720,6 +1734,14 @@ class ui(object): **opts currently has no defined meanings. ''' + if not self._loggers: + return + activeloggers = [l for l in self._loggers.itervalues() + if l.tracked(event)] + if not activeloggers: + return + for logger in activeloggers: + logger.log(self, event, msg, opts) def label(self, msg, label): '''style msg based on supplied label