Changeset - fe050a93936b
[Not reviewed]
stable
0 2 0
Mads Kiilerich (kiilerix) - 9 months ago 2024-09-22 19:13:23
mads@kiilerich.com
Grafted from: 5c7fed35a182
hg: Redirect Mercurial stdout/stderr to logging when running as WSGI

Any "console" output from Mercurial when Kallithea is running from WSGI
should end up in Kallithea's logs. That seems like a nice general feature.

This will however also solve another rare but more critical problem:

Mercurial is writing to sys.stdout / sys.stderr, using several layers of
wrapping. Since Mercurial 5.5 (with
https://repo.mercurial-scm.org/hg/rev/8e04607023e5 ), all writes are given a
memoryview.

Apache httpd mod_wsgi is invoking the WSGI with a custom mod_wsgi.Log injected
in sys.stdout / sys.stderr . This logger can however not handle memoryview -
https://github.com/GrahamDumpleton/mod_wsgi/issues/863 .
2 files changed with 32 insertions and 0 deletions:
0 comments (0 inline, 0 general) First comment
kallithea/config/application.py
Show inline comments
 
@@ -20,6 +20,7 @@ from kallithea.config.middleware.simpleg
 
from kallithea.config.middleware.simplehg import SimpleHg
 
from kallithea.config.middleware.wrapper import RequestWrapper
 
from kallithea.lib.utils2 import asbool
 
from kallithea.lib.vcs.utils import hgcompat
 

	
 

	
 
__all__ = ['make_app']
 
@@ -50,6 +51,7 @@ def wrap_app(app):
 
def make_app(global_conf, **app_conf):
 
    """Return WSGI app with logging Mercurial stdout/stderr - to be used as
 
    Paste or mod_wsgi entry point"""
 
    hgcompat.redirect_stdio_to_logging()
 
    return make_app_raw(global_conf, **app_conf)
 

	
 

	
kallithea/lib/vcs/utils/hgcompat.py
Show inline comments
 
@@ -2,10 +2,25 @@
 
Mercurial libs compatibility
 
"""
 

	
 
import logging
 

	
 
import mercurial.encoding
 
import mercurial.localrepo
 

	
 

	
 
class MercurialStdLogger:
 
    def __init__(self, logger):
 
        self.logger = logger
 

	
 
    def write(self, message):
 
        try:
 
            self.logger(message.decode().rstrip())
 
        except:
 
            self.logger(message)
 

	
 
    def flush(self):
 
        pass
 

	
 
def monkey_do():
 
    """Apply some Mercurial monkey patching"""
 
    # workaround for 3.3 94ac64bcf6fe and not calling largefiles reposetup correctly, and test_archival failing
 
@@ -15,3 +30,18 @@ def monkey_do():
 

	
 
    # Minimize potential impact from custom configuration
 
    mercurial.encoding.environ[b'HGPLAIN'] = b'1'
 

	
 

	
 
hglog = logging.getLogger("mercurial")
 

	
 

	
 
def redirect_stdio_to_logging():
 
    # Capture Mercurial stdout/stderr and send to a 'mercurial' logger
 
    try:
 
        import mercurial.utils.procutil as procutil
 
        if not isinstance(procutil.stdout, MercurialStdLogger):
 
            procutil.stdout = MercurialStdLogger(hglog.info)
 
        if not isinstance(procutil.stderr, MercurialStdLogger):
 
            procutil.stderr = MercurialStdLogger(hglog.warning)
 
    except Exception as e:
 
        hglog.error("Exception installing procutil stdout/stderr: %s", e)
0 comments (0 inline, 0 general) First comment
You need to be logged in to comment. Login now