##// END OF EJS Templates
hg: Redirect Mercurial stdout/stderr to logging when running as WSGI...
Mads Kiilerich -
r8795:fe050a93 tip stable
parent child Browse files
Show More
@@ -1,74 +1,76 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
5 # (at your option) any later version.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU General Public License
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """WSGI middleware initialization for the Kallithea application."""
14 """WSGI middleware initialization for the Kallithea application."""
15
15
16 from kallithea.config.app_cfg import base_config
16 from kallithea.config.app_cfg import base_config
17 from kallithea.config.middleware.https_fixup import HttpsFixup
17 from kallithea.config.middleware.https_fixup import HttpsFixup
18 from kallithea.config.middleware.permanent_repo_url import PermanentRepoUrl
18 from kallithea.config.middleware.permanent_repo_url import PermanentRepoUrl
19 from kallithea.config.middleware.simplegit import SimpleGit
19 from kallithea.config.middleware.simplegit import SimpleGit
20 from kallithea.config.middleware.simplehg import SimpleHg
20 from kallithea.config.middleware.simplehg import SimpleHg
21 from kallithea.config.middleware.wrapper import RequestWrapper
21 from kallithea.config.middleware.wrapper import RequestWrapper
22 from kallithea.lib.utils2 import asbool
22 from kallithea.lib.utils2 import asbool
23 from kallithea.lib.vcs.utils import hgcompat
23
24
24
25
25 __all__ = ['make_app']
26 __all__ = ['make_app']
26
27
27
28
28 def wrap_app(app):
29 def wrap_app(app):
29 """Wrap the TG WSGI application in Kallithea middleware"""
30 """Wrap the TG WSGI application in Kallithea middleware"""
30 config = app.config
31 config = app.config
31
32
32 # we want our low level middleware to get to the request ASAP. We don't
33 # we want our low level middleware to get to the request ASAP. We don't
33 # need any stack middleware in them - especially no StatusCodeRedirect buffering
34 # need any stack middleware in them - especially no StatusCodeRedirect buffering
34 app = SimpleHg(app, config)
35 app = SimpleHg(app, config)
35 app = SimpleGit(app, config)
36 app = SimpleGit(app, config)
36
37
37 # Enable https redirects based on HTTP_X_URL_SCHEME set by proxy
38 # Enable https redirects based on HTTP_X_URL_SCHEME set by proxy
38 if config.get('url_scheme_variable') or asbool(config.get('force_https')) or asbool(config.get('use_htsts')):
39 if config.get('url_scheme_variable') or asbool(config.get('force_https')) or asbool(config.get('use_htsts')):
39 app = HttpsFixup(app, config)
40 app = HttpsFixup(app, config)
40
41
41 app = PermanentRepoUrl(app, config)
42 app = PermanentRepoUrl(app, config)
42
43
43 # Optional and undocumented wrapper - gives more verbose request/response logging, but has a slight overhead
44 # Optional and undocumented wrapper - gives more verbose request/response logging, but has a slight overhead
44 if asbool(config.get('use_wsgi_wrapper')):
45 if asbool(config.get('use_wsgi_wrapper')):
45 app = RequestWrapper(app, config)
46 app = RequestWrapper(app, config)
46
47
47 return app
48 return app
48
49
49
50
50 def make_app(global_conf, **app_conf):
51 def make_app(global_conf, **app_conf):
51 """Return WSGI app with logging Mercurial stdout/stderr - to be used as
52 """Return WSGI app with logging Mercurial stdout/stderr - to be used as
52 Paste or mod_wsgi entry point"""
53 Paste or mod_wsgi entry point"""
54 hgcompat.redirect_stdio_to_logging()
53 return make_app_raw(global_conf, **app_conf)
55 return make_app_raw(global_conf, **app_conf)
54
56
55
57
56 def make_app_raw(global_conf, **app_conf):
58 def make_app_raw(global_conf, **app_conf):
57 """
59 """
58 Set up Kallithea with the settings found in the PasteDeploy configuration
60 Set up Kallithea with the settings found in the PasteDeploy configuration
59 file used.
61 file used.
60
62
61 :param global_conf: The global settings for Kallithea (those
63 :param global_conf: The global settings for Kallithea (those
62 defined under the ``[DEFAULT]`` section).
64 defined under the ``[DEFAULT]`` section).
63 :return: The Kallithea application with all the relevant middleware
65 :return: The Kallithea application with all the relevant middleware
64 loaded.
66 loaded.
65
67
66 This is the PasteDeploy factory for the Kallithea application.
68 This is the PasteDeploy factory for the Kallithea application.
67
69
68 ``app_conf`` contains all the application-specific settings (those defined
70 ``app_conf`` contains all the application-specific settings (those defined
69 under ``[app:main]``.
71 under ``[app:main]``.
70 """
72 """
71 assert app_conf.get('sqlalchemy.url') # must be called with a Kallithea .ini file, which for example must have this config option
73 assert app_conf.get('sqlalchemy.url') # must be called with a Kallithea .ini file, which for example must have this config option
72 assert global_conf.get('here') and global_conf.get('__file__') # app config should be initialized the paste way ...
74 assert global_conf.get('here') and global_conf.get('__file__') # app config should be initialized the paste way ...
73
75
74 return base_config.make_wsgi_app(global_conf, app_conf, wrap_app=wrap_app)
76 return base_config.make_wsgi_app(global_conf, app_conf, wrap_app=wrap_app)
@@ -1,17 +1,47 b''
1 """
1 """
2 Mercurial libs compatibility
2 Mercurial libs compatibility
3 """
3 """
4
4
5 import logging
6
5 import mercurial.encoding
7 import mercurial.encoding
6 import mercurial.localrepo
8 import mercurial.localrepo
7
9
8
10
11 class MercurialStdLogger:
12 def __init__(self, logger):
13 self.logger = logger
14
15 def write(self, message):
16 try:
17 self.logger(message.decode().rstrip())
18 except:
19 self.logger(message)
20
21 def flush(self):
22 pass
23
9 def monkey_do():
24 def monkey_do():
10 """Apply some Mercurial monkey patching"""
25 """Apply some Mercurial monkey patching"""
11 # workaround for 3.3 94ac64bcf6fe and not calling largefiles reposetup correctly, and test_archival failing
26 # workaround for 3.3 94ac64bcf6fe and not calling largefiles reposetup correctly, and test_archival failing
12 mercurial.localrepo.localrepository._lfstatuswriters = [lambda *msg, **opts: None]
27 mercurial.localrepo.localrepository._lfstatuswriters = [lambda *msg, **opts: None]
13 # 3.5 7699d3212994 added the invariant that repo.lfstatus must exist before hitting overridearchive
28 # 3.5 7699d3212994 added the invariant that repo.lfstatus must exist before hitting overridearchive
14 mercurial.localrepo.localrepository.lfstatus = False
29 mercurial.localrepo.localrepository.lfstatus = False
15
30
16 # Minimize potential impact from custom configuration
31 # Minimize potential impact from custom configuration
17 mercurial.encoding.environ[b'HGPLAIN'] = b'1'
32 mercurial.encoding.environ[b'HGPLAIN'] = b'1'
33
34
35 hglog = logging.getLogger("mercurial")
36
37
38 def redirect_stdio_to_logging():
39 # Capture Mercurial stdout/stderr and send to a 'mercurial' logger
40 try:
41 import mercurial.utils.procutil as procutil
42 if not isinstance(procutil.stdout, MercurialStdLogger):
43 procutil.stdout = MercurialStdLogger(hglog.info)
44 if not isinstance(procutil.stderr, MercurialStdLogger):
45 procutil.stderr = MercurialStdLogger(hglog.warning)
46 except Exception as e:
47 hglog.error("Exception installing procutil stdout/stderr: %s", e)
General Comments 0
You need to be logged in to leave comments. Login now