Exemplo n.º 1
0
class StatusWatcher(object):
    """Middleware that tracks requests"""

    def __init__(self, app, db, table_prefix='',
                 serialize_time=120, serialize_requests=100,
                 _synchronous=False):
        """This wraps the `app` and saves data about each request.

        data is stored in `vaineye.model.RequestTracker`, instantiated
        with the `db` SQLAlchemy connection string.

        Periodically data is written to the database (every
        `serialize_time` seconds, or `serialize_requests` requests,
        whichever comes first).  This writing happens in a background
        thread.

        For debugging purposes you can set `_synchronous` to True to
        have requests written out every request without spawning a
        thread."""
        self.app = app
        self.request_tracker = RequestTracker(db, table_prefix=table_prefix)
        self.serialize_time = serialize_time
        self.serialize_requests = serialize_requests
        self._synchronous = _synchronous
        self.write_pending_lock = threading.Lock()
        self.last_written = time.time()
        self.request_count = 0
        if not _synchronous:
            atexit.register(self.write_pending)

    def write_pending(self):
        """Write all pending requests"""
        if not self.write_pending_lock.acquire(False):
            # Someone else is currently serializing
            return
        try:
            self.request_tracker.write_pending()
            self.last_written = time.time()
            self.request_counts = 0
        finally:
            self.write_pending_lock.release()

    def write_in_thread(self):
        """Write all pending requests, in a background thread"""
        t = threading.Thread(target=self.write_pending)
        t.start()

    def __call__(self, environ, start_response):
        """WSGI interface"""
        self.request_count += 1
        if not self._synchronous and (
            self.request_count > self.serialize_requests
            or time.time() - self.last_written > self.serialize_time):
            self.write_in_thread()
        start_time = time.time()
        def repl_start_response(status, headers, exc_info=None):
            end_time = time.time()
            if 'HTTP_X_REAL_IP' in environ:
                # key for remote ip when nginx is used 
                environ['REMOTE_ADDR'] = environ['HTTP_X_REAL_IP']
            self.request_tracker.add_request(
                environ=environ,
                start_time=start_time,
                end_time=end_time,
                status=status,
                response_headers=headers)
            if self._synchronous:
                self.write_pending()
            return start_response(status, headers, exc_info)
        return self.app(environ, repl_start_response)