Example #1
0
def prerun_callback(sender=None, headers=None, body=None, **kwargs):
    name = kwargs["task"].name

    tr = TrackedRequest.instance()
    tr.mark_real_request()
    span = tr.start_span(operation=("Job/" + name))
    span.tag("queue", "default")
Example #2
0
    def worker_result(self, worker_ctx, result=None, exc_info=None):
        if self._do_nothing:
            return
        tracked_request = TrackedRequest.instance()

        if exc_info:
            tracked_request.tag("error", "true")
        elif isinstance(worker_ctx.entrypoint, HttpRequestHandler):
            # Handle the cases that HttpRequestHandler.response_from_result
            # does
            if isinstance(result, Response):
                status_code = result.status_code
            elif isinstance(result, tuple):
                if len(result) == 3:
                    status_code, _headers, _payload = result
                elif len(result) == 2:
                    status_code, _payload = result
                else:
                    # Nameko doesn't support other formats, so we know it will
                    # turn this into an error
                    status_code = 500
            else:
                status_code = 200

            if 500 <= status_code <= 599:
                tracked_request.tag("error", "true")

        tracked_request.stop_span()
Example #3
0
def executemany_wrapper(wrapped, instance, args, kwargs):
    """
    CursorWrapper.executemany() wrapper for Django < 2.0
    """
    try:
        sql, param_list = _extract_sql_param_list(*args, **kwargs)
    except TypeError:
        sql = None
        param_list = None

    if sql is not None:
        tracked_request = TrackedRequest.instance()
        span = tracked_request.start_span(operation="SQL/Many")
        span.tag("db.statement", sql)

    try:
        return wrapped(*args, **kwargs)
    finally:
        if sql is not None:
            tracked_request.stop_span()
            if tracked_request.n_plus_one_tracker.should_capture_backtrace(
                    sql=sql,
                    duration=span.duration(),
                    count=len(param_list),
            ):
                span.capture_backtrace()
Example #4
0
def wrap_client_index_method(wrapped, instance, args, kwargs):
    # elasticsearch-py 7.5.1 changed the order of arguments for client methods,
    # so to be safe we need to inspect the wrapped method's positional
    # arguments to see if we should pull it from there
    if "index" in kwargs:
        index = kwargs["index"]
    else:
        unwrapped = unwrap_decorators(wrapped)
        pos_args = get_pos_args(unwrapped)
        try:
            index_index = pos_args.index("index")
        except ValueError:  # pragma: no cover
            # This guards against the method not accepting an 'index' argument
            # but they all do - for now
            index = ""
        else:
            try:
                index = args[index_index - 1]  # subtract 'self'
            except IndexError:
                index = ""

    if isinstance(index, (list, tuple)):
        index = ",".join(index)
    if index == "":
        index = "Unknown"
    index = index.title()

    camel_name = "".join(c.title() for c in wrapped.__name__.split("_"))
    operation = "Elasticsearch/{}/{}".format(index, camel_name)
    tracked_request = TrackedRequest.instance()
    with tracked_request.span(operation=operation, ignore_children=True):
        return wrapped(*args, **kwargs)
Example #5
0
    async def wrapped_background_call(wrapped, instance, args, kwargs):
        tracked_request = TrackedRequest.instance()
        tracked_request.is_real_request = True

        with tracked_request.span(operation="Job/{}.{}".format(
                instance.func.__module__, instance.func.__qualname__)):
            return await wrapped(*args, **kwargs)
Example #6
0
    def process_request(self, req, resp):
        if self._do_nothing:
            return
        if self.api is None and self.hug_http_interface is not None:
            self.api = self.hug_http_interface.falcon
        tracked_request = TrackedRequest.instance()
        tracked_request.is_real_request = True
        req.context.scout_tracked_request = tracked_request
        tracked_request.start_span(operation="Middleware",
                                   should_capture_backtrace=False)

        path = req.path
        # Falcon URL parameter values are *either* single items or lists
        url_params = [(k, v) for k, vs in req.params.items()
                      for v in (vs if isinstance(vs, list) else [vs])]
        tracked_request.tag("path", create_filtered_path(path, url_params))
        if ignore_path(path):
            tracked_request.tag("ignore_transaction", True)

        if scout_config.value("collect_remote_ip"):
            # Determine a remote IP to associate with the request. The value is
            # spoofable by the requester so this is not suitable to use in any
            # security sensitive context.
            user_ip = (req.get_header("x-forwarded-for",
                                      default="").split(",")[0]
                       or req.get_header("client-ip", default="").split(",")[0]
                       or req.remote_addr)
            tracked_request.tag("user_ip", user_ip)

        queue_time = req.get_header(
            "x-queue-start", default="") or req.get_header("x-request-start",
                                                           default="")
        track_request_queue_time(queue_time, tracked_request)
Example #7
0
 def __enter__(self):
     # type: () -> instrument
     tracked_request = TrackedRequest.instance()
     self.span = tracked_request.start_span(operation=self.operation)
     for key, value in self.tags.items():
         self.tag(key, value)
     return self
Example #8
0
def db_execute_hook(execute, sql, params, many, context):
    """
    Database instrumentation hook for Django 2.0+
    https://docs.djangoproject.com/en/2.0/topics/db/instrumentation/
    """
    if many:
        operation = "SQL/Many"
    else:
        operation = "SQL/Query"

    if sql is not None:
        tracked_request = TrackedRequest.instance()
        span = tracked_request.start_span(operation=operation)
        span.tag("db.statement", sql)

    try:
        return execute(sql, params, many, context)
    finally:
        if sql is not None:
            tracked_request.stop_span()
            if tracked_request.n_plus_one_tracker.should_capture_backtrace(
                    sql=sql,
                    duration=span.duration(),
                    count=(1 if not many else len(params)),
            ):
                span.capture_backtrace()
Example #9
0
    def __call__(self, request):
        """
        Wrap a single incoming request with start and stop calls.
        This will start timing, but relies on the process_view callback to
        capture more details about what view was really called, and other
        similar info.

        If process_view isn't called, then the request will not
        be recorded.  This can happen if a middleware further along the stack
        doesn't call onward, and instead returns a response directly.
        """
        if not scout_config.value("monitor"):
            return self.get_response(request)

        tracked_request = TrackedRequest.instance()

        # This operation name won't be recorded unless changed later in
        # process_view
        with tracked_request.span(operation="Unknown",
                                  should_capture_backtrace=False):
            response = self.get_response(request)
            track_request_view_data(request, tracked_request)
            if 500 <= response.status_code <= 599:
                tracked_request.tag("error", "true")
            return response
Example #10
0
def tracked_request():
    request = TrackedRequest.instance()
    request.start_span()  # prevent request from finalizing
    try:
        yield request
    finally:
        request.stop_span()
Example #11
0
    def process_exception(self, request, exception):
        tracked_request = TrackedRequest.instance()

        if (hasattr(request, "scout_view_span")
                and tracked_request.current_span() == request.scout_view_span):
            tracked_request.tag("error", "true")
            tracked_request.stop_span()
def prerun_callback(task=None, **kwargs):
    tracked_request = TrackedRequest.instance()
    tracked_request.is_real_request = True

    start = getattr(task.request, "scout_task_start", None)
    if start is not None:
        now = datetime_to_timestamp(dt.datetime.utcnow())
        try:
            queue_time = now - start
        except TypeError:
            pass
        else:
            tracked_request.tag("queue_time", queue_time)

    task_id = getattr(task.request, "id", None)
    if task_id:
        tracked_request.tag("task_id", task_id)
    parent_task_id = getattr(task.request, "parent_id", None)
    if parent_task_id:
        tracked_request.tag("parent_task_id", parent_task_id)

    delivery_info = task.request.delivery_info
    tracked_request.tag("is_eager", delivery_info.get("is_eager", False))
    tracked_request.tag("exchange", delivery_info.get("exchange", "unknown"))
    tracked_request.tag("routing_key", delivery_info.get("routing_key", "unknown"))
    tracked_request.tag("queue", delivery_info.get("queue", "unknown"))

    tracked_request.start_span(operation=("Job/" + task.name))
Example #13
0
        def wrapper(*args, **kwargs):
            try:
                tr = TrackedRequest.instance()
                tr.mark_real_request()
                path = 'Unknown'

                if request.route.name is not None:
                    path = request.route.name
                else:
                    path = request.route.rule

                if path == '/':
                    path = '/home'

                if not path.startswith('/'):
                    path = '/{}'.format(path)

                span = tr.start_span(operation='Controller{}'.format(path))

                try:
                    Context.add('path', path)
                    Context.add('user_ip', request.remote_addr)
                except:
                    pass

                try:
                    response = callback(*args, **kwargs)
                except:
                    tr.tag('error', 'true')
                    raise

            finally:
                tr.stop_span()

            return response
Example #14
0
def sync_home(db: Session = Depends(get_db)):
    from scout_apm.core.tracked_request import TrackedRequest

    print("sync", TrackedRequest.instance())
    x = []
    # for i in range(-100, 0):
    #    x.append(len(db.query(User).filter(User.id >= i).all()))
    return {"users": len(db.query(User).all())}
Example #15
0
def after_cursor_execute(conn, cursor, statement, parameters, context, executemany):
    tr = TrackedRequest.instance()
    span = tr.current_span()
    if span is not None:
        tr.callset.update(statement, 1, span.duration())
        if tr.callset.should_capture_backtrace(statement):
            span.capture_backtrace()
    tr.stop_span()
Example #16
0
def test_ignore_transaction():
    tr = TrackedRequest.instance()

    ignore_transaction()

    tr.finish()

    assert tr.tags["ignore_transaction"]
Example #17
0
def test_background_transaction_start_stop():
    tr = TrackedRequest.instance()

    BackgroundTransaction.start("Foo")
    BackgroundTransaction.stop()

    span = tr.complete_spans[-1]
    assert span.operation == "Job/Foo"
Example #18
0
def test_web_transaction_start_stop():
    tr = TrackedRequest.instance()

    WebTransaction.start("Foo")
    WebTransaction.stop()

    span = tr.complete_spans[-1]
    assert span.operation == "Controller/Foo"
Example #19
0
def test_background_transaction_manual():
    tr = TrackedRequest.instance()

    scout_apm.api.BackgroundTransaction.start("Foo")
    scout_apm.api.BackgroundTransaction.stop()

    span = tr.complete_spans[-1]
    assert (span.operation == "Job/Foo")
Example #20
0
def test_web_transaction_manual():
    tr = TrackedRequest.instance()

    scout_apm.api.WebTransaction.start("Foo")
    scout_apm.api.WebTransaction.stop()

    span = tr.complete_spans[-1]
    assert (span.operation == "Controller/Foo")
Example #21
0
def wrapped_execute(wrapped, instance, args, kwargs):
    tracked_request = TrackedRequest.instance()
    tracked_request.start_span(operation="Redis/MULTI")

    try:
        return wrapped(*args, **kwargs)
    finally:
        tracked_request.stop_span()
Example #22
0
            def execute(original, self, *args, **kwargs):
                tr = TrackedRequest.instance()
                tr.start_span(operation='Redis/MULTI')

                try:
                    return original(*args, **kwargs)
                finally:
                    tr.stop_span()
Example #23
0
def wrap_collection_method(wrapped, instance, args, kwargs):
    tracked_request = TrackedRequest.instance()
    camel_name = "".join(c.title() for c in wrapped.__name__.split("_"))
    operation = "MongoDB/{}.{}".format(instance.name, camel_name)
    with tracked_request.span(operation=operation,
                              ignore_children=True) as span:
        span.tag("name", instance.name)
        return wrapped(*args, **kwargs)
def wrapped_render(wrapped, instance, args, kwargs):
    tracked_request = TrackedRequest.instance()
    span = tracked_request.start_span(operation="Template/Render")
    span.tag("name", instance.name)
    try:
        return wrapped(*args, **kwargs)
    finally:
        tracked_request.stop_span()
        def tracing_method(original, self, *args, **kwargs):
            entry_type, detail = info_func(self, *args, **kwargs)

            operation = entry_type
            if detail["name"] is not None:
                operation = operation + "/" + detail["name"]

            tr = TrackedRequest.instance()
            span = tr.start_span(operation=operation)

            for key in detail:
                span.tag(key, detail[key])

            try:
                return original(*args, **kwargs)
            finally:
                TrackedRequest.instance().stop_span()
Example #26
0
    def process_exception(request, exception):
        tr = TrackedRequest.instance()

        if hasattr(request, 'scout_view_span') and tr.current_span() == request.scout_view_span:
            tr.tag('error', 'true')
            tr.stop_span()

        return None
    async def __call__(self, scope, receive, send):
        if self._do_nothing or scope["type"] != "http":
            return await self.app(scope, receive, send)

        tracked_request = TrackedRequest.instance()
        # Assume the request is real until we determine it's not. This is useful
        # when the asyncio instrumentation is determining if a new Task should
        # reuse the existing tracked request.
        tracked_request.is_real_request = True
        # Can't name controller until post-routing - see final clause
        controller_span = tracked_request.start_span(operation="Controller/Unknown")

        asgi_track_request_data(scope, tracked_request)

        def grab_extra_data():
            if "endpoint" in scope:
                # Rename top span
                endpoint = scope["endpoint"]
                if not hasattr(endpoint, "__qualname__"):
                    endpoint = endpoint.__class__
                controller_span.operation = "Controller/{}.{}".format(
                    endpoint.__module__,
                    endpoint.__qualname__,
                )
            else:
                # Mark the request as not real
                tracked_request.is_real_request = False

            # From AuthenticationMiddleware - bypass request.user because it
            # throws AssertionError if 'user' is not in Scope, and we need a
            # try/except already
            try:
                username = scope["user"].display_name
            except (KeyError, AttributeError):
                pass
            else:
                tracked_request.tag("username", username)

        async def wrapped_send(data):
            type_ = data.get("type", None)
            if type_ == "http.response.start" and 500 <= data.get("status", 200) <= 599:
                tracked_request.tag("error", "true")
            elif type_ == "http.response.body" and not data.get("more_body", False):
                # Finish HTTP span when body finishes sending, not later (e.g.
                # after background tasks)
                grab_extra_data()
                tracked_request.stop_span()
            return await send(data)

        try:
            await self.app(scope, receive, wrapped_send)
        except Exception as exc:
            tracked_request.tag("error", "true")
            raise exc
        finally:
            if tracked_request.end_time is None:
                grab_extra_data()
                tracked_request.stop_span()
Example #28
0
            def render(original, self, *args, **kwargs):
                tr = TrackedRequest.instance()
                span = tr.start_span(operation="Template/Render")
                span.tag("name", self.name)

                try:
                    return original(*args, **kwargs)
                finally:
                    tr.stop_span()
Example #29
0
def tracked_request():
    """
    Create a temporary tracked request for the duration of the test.
    """
    request = TrackedRequest.instance()
    try:
        yield request
    finally:
        request.finish()
Example #30
0
    def start(cls, kind, name, tags={}):
        operation = text(kind) + "/" + text(name)

        tr = TrackedRequest.instance()
        tr.mark_real_request()
        span = tr.start_span(operation=operation)
        for key, value in tags.items():
            tr.tag(key, value)
        return span