Changeset - 5240fbde6ddb
[Not reviewed]
default
0 2 0
Mads Kiilerich - 6 years ago 2019-10-19 22:53:21
mads@kiilerich.com
Grafted from: 8e257159269a
wsgi: reintroduce the "wrapper" middleware for logging request timing, but guarded by optional use_wsgi_wrapper=true
2 files changed with 27 insertions and 8 deletions:
0 comments (0 inline, 0 general)
kallithea/config/app_cfg.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
"""
 
Global configuration file for TurboGears2 specific settings in Kallithea.
 

	
 
This file complements the .ini file.
 
"""
 

	
 
import logging
 
import os
 
import platform
 
import sys
 

	
 
import alembic.config
 
import mercurial
 
import tg
 
from alembic.migration import MigrationContext
 
from alembic.script.base import ScriptDirectory
 
from sqlalchemy import create_engine
 
from tg import hooks
 
from tg.configuration import AppConfig
 
from tg.support.converters import asbool
 

	
 
import kallithea.lib.locale
 
import kallithea.model.base
 
from kallithea.lib.auth import set_available_permissions
 
from kallithea.lib.middleware.https_fixup import HttpsFixup
 
from kallithea.lib.middleware.permanent_repo_url import PermanentRepoUrl
 
from kallithea.lib.middleware.simplegit import SimpleGit
 
from kallithea.lib.middleware.simplehg import SimpleHg
 
from kallithea.lib.middleware.wrapper import RequestWrapper
 
from kallithea.lib.utils import check_git_version, load_rcextensions, make_ui, set_app_settings, set_indexer_config, set_vcs_config
 
from kallithea.lib.utils2 import str2bool
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class KallitheaAppConfig(AppConfig):
 
    # Note: AppConfig has a misleading name, as it's not the application
 
    # configuration, but the application configurator. The AppConfig values are
 
    # used as a template to create the actual configuration, which might
 
    # overwrite or extend the one provided by the configurator template.
 

	
 
    # To make it clear, AppConfig creates the config and sets into it the same
 
    # values that AppConfig itself has. Then the values from the config file and
 
    # gearbox options are loaded and merged into the configuration. Then an
 
    # after_init_config(conf) method of AppConfig is called for any change that
 
    # might depend on options provided by configuration files.
 

	
 
    def __init__(self):
 
        super(KallitheaAppConfig, self).__init__()
 

	
 
        self['package'] = kallithea
 

	
 
        self['prefer_toscawidgets2'] = False
 
        self['use_toscawidgets'] = False
 

	
 
        self['renderers'] = []
 

	
 
        # Enable json in expose
 
        self['renderers'].append('json')
 

	
 
        # Configure template rendering
 
        self['renderers'].append('mako')
 
        self['default_renderer'] = 'mako'
 
        self['use_dotted_templatenames'] = False
 

	
 
        # Configure Sessions, store data as JSON to avoid pickle security issues
 
        self['session.enabled'] = True
 
        self['session.data_serializer'] = 'json'
 

	
 
        # Configure the base SQLALchemy Setup
 
        self['use_sqlalchemy'] = True
 
        self['model'] = kallithea.model.base
 
        self['DBSession'] = kallithea.model.meta.Session
 

	
 
        # Configure App without an authentication backend.
 
        self['auth_backend'] = None
 
@@ -154,52 +155,57 @@ def setup_configuration(app):
 
                      'to your .ini file to skip the check.\n' % (' '.join(current_heads), ' '.join(available_heads)))
 
            sys.exit(1)
 

	
 
    # store some globals into kallithea
 
    kallithea.CELERY_ON = str2bool(config.get('use_celery'))
 
    kallithea.CELERY_EAGER = str2bool(config.get('celery.always.eager'))
 
    kallithea.CONFIG = config
 

	
 
    load_rcextensions(root_path=config['here'])
 

	
 
    set_available_permissions(config)
 
    repos_path = make_ui().configitems('paths')[0][1]
 
    config['base_path'] = repos_path
 
    set_app_settings(config)
 

	
 
    instance_id = kallithea.CONFIG.get('instance_id', '*')
 
    if instance_id == '*':
 
        instance_id = '%s-%s' % (platform.uname()[1], os.getpid())
 
        kallithea.CONFIG['instance_id'] = instance_id
 

	
 
    # update kallithea.CONFIG with the meanwhile changed 'config'
 
    kallithea.CONFIG.update(config)
 

	
 
    # configure vcs and indexer libraries (they are supposed to be independent
 
    # as much as possible and thus avoid importing tg.config or
 
    # kallithea.CONFIG).
 
    set_vcs_config(kallithea.CONFIG)
 
    set_indexer_config(kallithea.CONFIG)
 

	
 
    check_git_version()
 

	
 

	
 
hooks.register('configure_new_app', setup_configuration)
 

	
 

	
 
def setup_application(app):
 
    config = app.config
 

	
 
    # we want our low level middleware to get to the request ASAP. We don't
 
    # need any stack middleware in them - especially no StatusCodeRedirect buffering
 
    app = SimpleHg(app, config)
 
    app = SimpleGit(app, config)
 

	
 
    # Enable https redirects based on HTTP_X_URL_SCHEME set by proxy
 
    if any(asbool(config.get(x)) for x in ['https_fixup', 'force_https', 'use_htsts']):
 
        app = HttpsFixup(app, config)
 

	
 
    app = PermanentRepoUrl(app, config)
 

	
 
    # Optional and undocumented wrapper - gives more verbose request/response logging, but has a slight overhead
 
    if str2bool(config.get('use_wsgi_wrapper')):
 
        app = RequestWrapper(app, config)
 

	
 
    return app
 

	
 

	
 
hooks.register('before_config', setup_application)
kallithea/lib/middleware/wrapper.py
Show inline comments
 
# -*- coding: utf-8 -*-
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
"""
 
kallithea.lib.middleware.wrapper
 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
request time measuring app
 
Wrap app to measure request and response time ... until the response starts.
 

	
 
This file was forked by the Kallithea project in July 2014.
 
Original author and date, and relevant copyright and licensing information is below:
 
:created_on: May 23, 2013
 
:author: marcink
 
:copyright: (c) 2013 RhodeCode GmbH, and others.
 
:license: GPLv3, see LICENSE.md for more details.
 
"""
 

	
 
import logging
 
import time
 

	
 
from kallithea.lib.base import _get_access_path, _get_ip_addr
 
from kallithea.lib.utils2 import safe_unicode
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class Meter:
 

	
 
    def __init__(self):
 
        self._start = time.time()
 

	
 
    def duration(self):
 
        return time.time() - self._start
 

	
 

	
 
class RequestWrapper(object):
 

	
 
    def __init__(self, app, config):
 
        self.application = app
 
        self.config = config
 

	
 
    def __call__(self, environ, start_response):
 
        start = time.time()
 
        meter = Meter()
 
        description = "Request from %s for %s" % (
 
            _get_ip_addr(environ),
 
            safe_unicode(_get_access_path(environ)),
 
        )
 
        try:
 
            return self.application(environ, start_response)
 
            result = self.application(environ, start_response)
 
        finally:
 
            log = logging.getLogger('kallithea.' + self.__class__.__name__)
 
            log.info('IP: %s Request to %s time: %.3fs' % (
 
                _get_ip_addr(environ),
 
                safe_unicode(_get_access_path(environ)), time.time() - start)
 
            )
 
            log.info("%s responding after %.3fs", description, meter.duration())
 
        return result
0 comments (0 inline, 0 general)