Exemplo n.º 1
0
def test_context_eventlet(request):
    try:
        import eventlet
    except ImportError:
        pytest.skip('eventlet must be installed')

    request.addfinalizer(enable_eventlet_context())

    def f1():
        assert Context.logging.flat == {}
        Context.logging.push({'f1': 1})
        Context.track('gevent', 1.0)
        assert Context.logging.flat == {'f1': 1}
        assert Context.current().tracking['gevent'].count == 1
        eventlet.sleep(0.2)  # yield to let f2 run
        assert Context.logging.flat == {'f1': 1}
        assert Context.current().tracking['gevent'].count == 1

    def f2():
        assert Context.logging.flat == {}
        Context.logging.push({'f2': 2})
        Context.track('gevent', 1.0)
        assert Context.current().tracking['gevent'].count == 1
        assert Context.logging.flat == {'f2': 2}

    pool = eventlet.GreenPool()
    pool.spawn(f1)
    pool.spawn(f2)
    pool.waitall()
    # Resetting Context
    Context.clear()
    Context.current().request_id = None
    Context.current().tracking = {}
Exemplo n.º 2
0
def test_context_gevent(request):
    try:
        import gevent
    except ImportError:
        pytest.skip('gevent must be installed')

    request.addfinalizer(enable_gevent_context())

    def f1():
        assert Context.logging.flat == {}
        Context.logging.push({'f1': 1})
        Context.track('gevent', 1.0)
        assert Context.logging.flat == {'f1': 1}
        assert Context.current().tracking['gevent'].count == 1
        gevent.sleep(0.2)  # yield to let f2 run
        assert Context.logging.flat == {'f1': 1}
        assert Context.current().tracking['gevent'].count == 1

    def f2():
        assert Context.logging.flat == {}
        Context.logging.push({'f2': 2})
        Context.track('gevent', 1.0)
        assert Context.current().tracking['gevent'].count == 1
        assert Context.logging.flat == {'f2': 2}

    g1 = gevent.spawn(f1)
    g2 = gevent.spawn(f2)
    gevent.joinall([g1, g2], timeout=2)
    # Resetting Context
    Context.clear()
    Context.current().request_id = None
    Context.current().tracking = {}
Exemplo n.º 3
0
 def f1():
     assert Context.logging.flat == {}
     Context.logging.push({'f1': 1})
     Context.track('gevent', 1.0)
     assert Context.logging.flat == {'f1': 1}
     assert Context.current().tracking['gevent'].count == 1
     eventlet.sleep(0.2)  # yield to let f2 run
     assert Context.logging.flat == {'f1': 1}
     assert Context.current().tracking['gevent'].count == 1
Exemplo n.º 4
0
def test_tracking():
    Context.new()
    Context.track('sql', 1.0)
    Context.track('sql', 2.0)
    Context.track('http', 3.0)

    assert Context.current().tracking['sql'].count == 2
    assert Context.current().tracking['sql'].time == 3.0
    assert Context.current().tracking['http'].count == 1
    assert Context.current().tracking['http'].time == 3.0
Exemplo n.º 5
0
 def worker():
     Context.new()
     Context.logging.push(a=2)
     Context.track('test', 1.0)
     e1.set()
     e2.wait()
     assert Context.logging.flat == {'a': 2}
     Context.logging.pop()
     e1.set()
     assert Context.logging.flat == {}
     assert Context.current().tracking['test'].count == 1
Exemplo n.º 6
0
def test_null_context():
    Context.request_id = 'test'
    Context.set_debug()
    Context.soft_timeout = 10
    Context.set_relative_deadline(10)
    Context.track('sql', 1.0)

    assert Context.request_id is None
    assert Context.debug is False
    assert Context.soft_timeout == -1
    assert Context.deadline_timeout() is None
    assert Context.current().tracking == {}

    with Context.logging(foo='bar'):
        assert Context.logging.flat == {}
Exemplo n.º 7
0
def test_context_api():
    Context.new()
    Context.logging.push(a=1)
    Context.request_id = 'id'
    Context.track('test', 1.0)
    assert Context.current().logging.flat == {'a': 1}
    assert Context.current().request_id == 'id'
    assert Context.current().tracking['test'].count == 1
    assert Context.current().tracking['test'].time == 1.0

    Context.clear()
    assert Context.current().logging.flat == {}
    assert Context.current().request_id is None
    assert Context.current().tracking == {}
Exemplo n.º 8
0
def test_context_thread():

    e1 = threading.Event()
    e2 = threading.Event()

    def worker():
        Context.new()
        Context.logging.push(a=2)
        Context.track('test', 1.0)
        e1.set()
        e2.wait()
        assert Context.logging.flat == {'a': 2}
        Context.logging.pop()
        e1.set()
        assert Context.logging.flat == {}
        assert Context.current().tracking['test'].count == 1

    t = threading.Thread(target=worker)

    Context.new()
    Context.track('test', 1.0)
    Context.logging.push(a=1)
    assert Context.logging.flat == {'a': 1}

    t.start()
    e1.wait()
    e1.clear()

    assert Context.logging.flat == {'a': 1}
    assert Context.current().tracking['test'].count == 1

    e2.set()
    e1.wait()

    assert Context.logging.flat == {'a': 1}
    t.join()
Exemplo n.º 9
0
 def f():
     result['timeout'] = Context.current().deadline
     result['soft_timeout'] = Context.soft_timeout
Exemplo n.º 10
0
 def f2():
     assert Context.logging.flat == {}
     Context.logging.push({'f2': 2})
     Context.track('gevent', 1.0)
     assert Context.current().tracking['gevent'].count == 1
     assert Context.logging.flat == {'f2': 2}
Exemplo n.º 11
0
    def __call__(self, environ, start_response):
        Context.new()
        config = talisker.get_config()

        # setup environment
        environ['start_time'] = Context.current().start_time
        if self.environ:
            environ.update(self.environ)
        # ensure request id
        if config.wsgi_id_header not in environ:
            environ[config.wsgi_id_header] = str(uuid.uuid4())
        rid = environ[config.wsgi_id_header]
        environ['REQUEST_ID'] = rid
        # needs to be different from request id, as request can be passed on to
        # upstream services
        environ['SENTRY_ID'] = uuid.uuid4().hex

        Context.request_id = rid
        Context.soft_timeout = config.soft_request_timeout

        # calculate ip route
        route = None
        try:
            forwarded = environ.get('HTTP_X_FORWARDED_FOR')
            if forwarded:
                route = [a.strip() for a in forwarded.split(',')]
            elif "REMOTE_ADDR" in environ:
                route = [environ["REMOTE_ADDR"]]
        except Exception as e:
            logger.exception(e)
        else:
            if route is not None:
                environ['ACCESS_ROUTE'] = route
                environ['CLIENT_ADDR'] = route[-1]

        if 'HTTP_X_DEBUG' in environ:
            if config.is_trusted_addr(environ.get('CLIENT_ADDR')):
                Context.set_debug()
            else:
                logger.warning('X-Debug header set but not trusted IP address',
                               extra={
                                   "access_route":
                                   ','.join(environ.get('ACCESS_ROUTE')),
                                   "x_debug":
                                   environ['HTTP_X_DEBUG'],
                               })

        set_deadline = False
        header_deadline = environ.get('HTTP_X_REQUEST_DEADLINE')
        if header_deadline:
            try:
                deadline = datetime.strptime(
                    header_deadline,
                    "%Y-%m-%dT%H:%M:%S.%fZ",
                )
            except ValueError:
                pass
            else:
                # set deadline directly
                # TODO: validate deadline is in future?
                Context.set_absolute_deadline(datetime_to_timestamp(deadline))
                set_deadline = True

        if not set_deadline and config.request_timeout is not None:
            Context.set_relative_deadline(config.request_timeout)

        # create the response container
        request = TaliskerWSGIRequest(environ, start_response, self.headers)

        # track in-flight requests
        if rid in REQUESTS:
            logger.warning('duplicate request id received by gunicorn worker',
                           extra={'request_id': rid})
        else:
            REQUESTS[rid] = request

        try:
            response_iter = self.app(environ, request.start_response)
        except Exception as e:
            # store details for later
            request.exc_info = sys.exc_info()
            if isinstance(e, RequestTimeout):
                request.timedout = True
            # switch to generating an error response
            response_iter = request.error(request.exc_info)
        except SystemExit as e:
            if e.code != 0:
                request.exc_info = sys.exc_info()
                request.finish_request()
            raise

        return request.wrap_response(response_iter)
Exemplo n.º 12
0
    def get_metadata(self):
        """Return an ordered dictionary of request metadata for logging."""
        environ = self.environ
        extra = OrderedDict()

        if self.headers is None:
            headers = {}
        else:
            headers = dict((k.lower(), v) for k, v in self.headers)

        extra['method'] = environ.get('REQUEST_METHOD')
        script = environ.get('SCRIPT_NAME', '')
        path = environ.get('PATH_INFO', '')
        extra['path'] = script + '/' + path.lstrip('/')
        qs = environ.get('QUERY_STRING')
        if qs:
            extra['qs'] = environ.get('QUERY_STRING')
        if self.status_code:
            extra['status'] = self.status_code
        if 'VIEW_NAME' in environ:
            extra['view'] = environ['VIEW_NAME']
        elif 'x-view-name' in headers:
            extra['view'] = headers['x-view-name']
        extra['duration_ms'] = round(self.duration * 1000, 3)
        extra['ip'] = environ.get('REMOTE_ADDR', None)
        extra['proto'] = environ.get('SERVER_PROTOCOL')
        if self.content_length:
            extra['length'] = self.content_length
        if self.file_path is not None:
            extra['filepath'] = self.file_path
        request_length = environ.get('CONTENT_LENGTH')
        if request_length:
            try:
                extra['request_length'] = int(request_length)
            except ValueError:
                pass
        content_type = environ.get('CONTENT_TYPE')
        if content_type:
            extra['request_type'] = content_type
        referrer = environ.get('HTTP_REFERER', None)
        if referrer is not None:
            extra['referrer'] = environ.get('HTTP_REFERER', None)
        if 'HTTP_X_FORWARDED_FOR' in environ:
            extra['forwarded'] = environ['HTTP_X_FORWARDED_FOR']
        if 'HTTP_USER_AGENT' in environ:
            extra['ua'] = environ['HTTP_USER_AGENT']

        if self.timedout:
            extra['timeout'] = True

        if self.exc_info and self.exc_info[0]:
            extra['exc_type'] = str(self.exc_info[0].__name__)
            extra['trailer'] = ''.join(
                traceback.format_exception(*self.exc_info))

        tracking = Context.current().tracking
        for name, tracker in sorted(tracking.items()):
            extra[name + '_count'] = tracker.count
            extra[name + '_time_ms'] = tracker.time

        return extra