Ejemplo n.º 1
0
    def create_http_event(self, request):
        # if beeline has not been initialised, just execute request
        if not beeline.get_beeline():
            return self.get_response(request)

        # Code to be executed for each request before
        # the view (and later middleware) are called.
        dr = DjangoRequest(request)

        request_context = self.get_context_from_request(request)
        root_span = beeline.propagate_and_start_trace(request_context, dr)

        response = self.get_response(request)

        # Code to be executed for each request/response after
        # the view is called.
        response_context = self.get_context_from_response(request, response)
        beeline.add_context(response_context)

        # Streaming responses return immediately, but iterate over
        # their `streaming_content` until it's empty; only close the
        # trace then, not now.
        def wrap_streaming_content(content):
            for chunk in content:
                yield chunk
            beeline.finish_trace(root_span)

        if response.streaming:
            response.streaming_content = wrap_streaming_content(
                response.streaming_content)
        else:
            beeline.finish_trace(root_span)

        return response
Ejemplo n.º 2
0
def lambda_handler(event, context):
    """Sample Lambda function reacting to EventBridge events

    Parameters
    ----------
    event: dict, required
        Event Bridge Events Format

        Event doc: https://docs.aws.amazon.com/eventbridge/latest/userguide/event-types.html

    context: object, required
        Lambda Context runtime methods and attributes

        Context doc: https://docs.aws.amazon.com/lambda/latest/dg/python-context-object.html

    Returns
    ------
        Response status code from Slack API call
    """
    master_acct_arn = event["detail"]["additionalEventData"]["SwitchFrom"]
    beeline.add_context({"user_arn": master_acct_arn})
    sm = SlackMessage(master_acct_arn)
    resp = sm.post(os.environ["slackWebhookURL"])

    if resp.status_code != requests.codes.ok:
        resp.raise_for_status()

    logger.info(f"Posting to Slack channel returned {resp}.")
    return resp.status_code
Ejemplo n.º 3
0
    def __call__(self, execute, sql, params, many, context):
        vendor = context['connection'].vendor
        trace_name = "django_%s_query" % vendor

        with beeline.tracer(trace_name):
            beeline.add_context({
                "type": "db",
                "db.query": sql,
                "db.query_args": params,
            })

            try:
                db_call_start = datetime.datetime.now()
                result = execute(sql, params, many, context)
                db_call_diff = datetime.datetime.now() - db_call_start
                beeline.add_context_field("db.duration",
                                          db_call_diff.total_seconds() * 1000)
            except Exception as e:
                beeline.add_context_field("db.error", str(type(e)))
                beeline.add_context_field(
                    "db.error_detail", beeline.internal.stringify_exception(e))
                raise
            else:
                return result
            finally:
                if vendor in ('postgresql', 'mysql'):
                    beeline.add_context({
                        "db.last_insert_id":
                        context['cursor'].cursor.lastrowid,
                        "db.rows_affected":
                        context['cursor'].cursor.rowcount,
                    })
Ejemplo n.º 4
0
    def create_http_event(self, request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.

        trace_id, parent_id, parent_context = _get_trace_context(request)

        request_context = self.get_context_from_request(request)

        trace = beeline.start_trace(context=request_context,
                                    trace_id=trace_id,
                                    parent_span_id=parent_id)

        if isinstance(parent_context, dict):
            for k, v in parent_context.items():
                beeline.add_trace_field(k, v)

        response = self.get_response(request)

        # Code to be executed for each request/response after
        # the view is called.
        response_context = self.get_context_from_response(request, response)
        beeline.add_context(response_context)
        beeline.finish_trace(trace)

        return response
def lambda_handler(event, context):

    trace_context = None
    input = None
    parent_trace = None
    output = {}

    logging.debug(f"event: {json.dumps(event)}")
    init_beeline()

    # Attempt to get trace_context(s) from the input
    input = event.get("Input", None)
    if input:
        trace_context = input.get("trace_context", None)

    # Start trace if it isn't already, otherwise resume
    if trace_context:
        trace_id, parent_id, context = beeline.trace.unmarshal_trace_context(
            trace_context)
        logging.info(f"Resuming trace: {trace_id}")
        trace = beeline.start_trace(trace_id=trace_id,
                                    parent_span_id=parent_id,
                                    context=context)
        # add a field to test context propogation
        beeline.add_trace_field(
            event.get("Path", "UnknownPath").lower(), uuid.uuid4())
        beeline.add_context(
            {"name": event.get("Path", "Missing Path Information")})
        beeline.add_context(
            {"function_name": event.get("Path", "Missing Path Information")})

        random_sleep()
        beeline.finish_span(trace)
    else:
        trace = start_trace()
        beeline.add_trace_field("c3po", "r2d2")
        logging.info(f"Starting Trace")
        with beeline.tracer(
                name=event.get("Path", "Missing Path Information")):
            random_sleep()
        trace_context = beeline.get_beeline(
        ).tracer_impl.marshal_trace_context()

    # If final step close the parent trace
    if event.get("Path") == "Step4":
        # 2019-03-26T20:14:13.192Z
        parent_trace_id, parent_parent_id, parent_context_data = beeline.trace.unmarshal_trace_context(
            trace_context)
        start_time = datetime.strptime(event.get("start_time"),
                                       "%Y-%m-%dT%H:%M:%S.%fZ")
        close_final_trace(parent_trace_id, parent_parent_id,
                          parent_context_data, start_time)

    # Close only (send pending)
    beeline.close()

    # Return the trace_context to the SFN
    output["trace_context"] = trace_context
    return output
Ejemplo n.º 6
0
def honeycomb_middleware(next, root, info, **args):
    with beeline.tracer(name="graphql_execute"):
        beeline.add_context({
            "graphql.parent_type":
            root._meta.name if root and hasattr(root, "_meta") else "",
            "graphql.field_name":
            info.field_name,
            "graphql.args":
            args,
        })
        return next(root, info, **args)
Ejemplo n.º 7
0
def request(_request, instance, args, kwargs):
    span = beeline.start_span(context={"meta.type": "http_client"})

    b = beeline.get_beeline()
    if b and b.http_trace_propagation_hook is not None:
        new_headers = beeline.http_trace_propagation_hook()
        if new_headers:
            b.log(
                "requests lib - adding trace context to outbound request: %s",
                new_headers)
            instance.headers.update(new_headers)
        else:
            b.log("requests lib - no trace context found")

    try:
        resp = None

        # Required as Python treats the `or` keyword differently in string
        # interpolation vs. when assigning a variable.
        method = kwargs.get('method') or args[0]

        beeline.add_context({
            "name": "requests_%s" % method,
            "request.method": method,
            "request.url": kwargs.get('url') or args[1],
        })
        resp = _request(*args, **kwargs)
        return resp
    except Exception as e:
        beeline.add_context({
            "request.error_type":
            str(type(e)),
            "request.error":
            beeline.internal.stringify_exception(e),
        })
        raise
    finally:
        if resp is not None:
            content_type = resp.headers.get('content-type')
            if content_type:
                beeline.add_context_field("response.content_type",
                                          content_type)
            content_length = resp.headers.get('content-length')
            if content_length:
                beeline.add_context_field("response.content_length",
                                          content_length)
            if hasattr(resp, 'status_code'):
                beeline.add_context_field("response.status_code",
                                          resp.status_code)
        beeline.finish_span(span)
Ejemplo n.º 8
0
    def after_cursor_execute(self, conn, cursor, statement, parameters, context, executemany):
        if not current_app:
            return

        query_duration = datetime.datetime.now() - self.query_start_time

        beeline.add_context({
            "db.duration": query_duration.total_seconds() * 1000,
            "db.last_insert_id": getattr(cursor, 'lastrowid', None),
            "db.rows_affected": cursor.rowcount,
        })
        if self.state.span:
            beeline.finish_span(self.state.span)
        self.state.span = None
Ejemplo n.º 9
0
    def _beeline_wrapper(event, context):
        global COLD_START

        # don't blow up the world if the beeline has not been initialized
        if not beeline.get_beeline():
            return handler(event, context)

        try:
            # assume we're going to get bad values sometimes in our headers
            trace_id, parent_id, trace_context = None, None, None
            try:
                trace_id, parent_id, trace_context = _get_trace_data(event)
            except Exception as e:
                beeline.internal.log(
                    'error attempting to extract trace context: %s',
                    beeline.internal.stringify_exception(e))
                pass
            with beeline.tracer(name=handler.__name__,
                                trace_id=trace_id,
                                parent_id=parent_id):
                beeline.add_context({
                    "app.function_name":
                    getattr(context, 'function_name', ""),
                    "app.function_version":
                    getattr(context, 'function_version', ""),
                    "app.request_id":
                    getattr(context, 'aws_request_id', ""),
                    "app.event":
                    event,
                    "meta.cold_start":
                    COLD_START,
                })

                # if there is custom context attached from upstream, add that now
                if isinstance(trace_context, dict):
                    for k, v in trace_context.items():
                        beeline.add_trace_field(k, v)

                resp = handler(event, context)

                if resp is not None:
                    beeline.add_context_field('app.response', resp)

                return resp
        finally:
            # This remains false for the lifetime of the module
            COLD_START = False
            # we have to flush events before the lambda returns
            beeline.get_beeline().client.flush()
Ejemplo n.º 10
0
def request(_request, instance, args, kwargs):
    span = beeline.start_span(context={"meta.type": "http_client"})

    b = beeline.get_beeline()
    if b:
        context = b.tracer_impl.marshal_trace_context()
        if context:
            b.log(
                "requests lib - adding trace context to outbound request: %s",
                context)
            instance.headers['X-Honeycomb-Trace'] = context
        else:
            b.log("requests lib - no trace context found")

    try:
        resp = None
        beeline.add_context({
            "name":
            "requests_%s" % kwargs.get('method') or args[0],
            "request.method":
            kwargs.get('method') or args[0],
            "request.url":
            kwargs.get('url') or args[1],
        })
        resp = _request(*args, **kwargs)
        return resp
    except Exception as e:
        beeline.add_context({
            "request.error_type":
            str(type(e)),
            "request.error":
            beeline.internal.stringify_exception(e),
        })
        raise
    finally:
        if resp:
            content_type = resp.headers.get('content-type')
            if content_type:
                beeline.add_context_field("response.content_type",
                                          content_type)
            content_length = resp.headers.get('content-length')
            if content_length:
                beeline.add_context_field("response.content_length",
                                          content_length)
            if hasattr(resp, 'status_code'):
                beeline.add_context_field("response.status_code",
                                          resp.status_code)
        beeline.finish_span(span)
Ejemplo n.º 11
0
def _urllibopen(_urlopen, instance, args, kwargs):
    # urlopen accepts either a string URL or a Request object as its first arg
    # It's easier to process the info contained in the request and modify it
    # by converting the URL string into a Request
    if type(args[0]) != urllib.request.Request:
        args = (urllib.request.Request(args[0]), ) + tuple(args[1:])

    span = beeline.start_span(context={"meta.type": "http_client"})

    b = beeline.get_beeline()
    if b and b.http_trace_propagation_hook is not None:
        new_headers = beeline.http_trace_propagation_hook()
        if new_headers:
            # Merge the new headers into the existing headers for the outbound request
            b.log("urllib lib - adding trace context to outbound request: %s",
                  new_headers)
            args[0].headers.update(new_headers)

    try:
        resp = None
        beeline.add_context({
            "name": "urllib_%s" % args[0].get_method(),
            "request.method": args[0].get_method(),
            "request.uri": args[0].full_url
        })
        resp = _urlopen(*args, **kwargs)
        return resp
    except Exception as e:
        beeline.add_context({
            "request.error_type":
            str(type(e)),
            "request.error":
            beeline.internal.stringify_exception(e),
        })
        raise
    finally:
        if resp:
            beeline.add_context_field("response.status_code", resp.status)
            content_type = resp.getheader('content-type')
            if content_type:
                beeline.add_context_field("response.content_type",
                                          content_type)
            content_length = resp.getheader('content-length')
            if content_length:
                beeline.add_context_field("response.content_length",
                                          content_length)

        beeline.finish_span(span)
Ejemplo n.º 12
0
    def _beeline_wrapper(event, context):
        global COLD_START

        # don't blow up the world if the beeline has not been initialized
        if not beeline.get_beeline():
            return handler(event, context)

        root_span = None
        try:
            # Create request context
            request_context = {
                "app.function_name": getattr(context, 'function_name', ""),
                "app.function_version": getattr(context, 'function_version',
                                                ""),
                "app.request_id": getattr(context, 'aws_request_id', ""),
                "meta.cold_start": COLD_START,
                "name": handler.__name__
            }
            if record_input:
                request_context["app.event"] = event

            lr = LambdaRequest(event)
            root_span = beeline.propagate_and_start_trace(request_context, lr)

            # Actually run the handler
            resp = handler(event, context)

            if resp is not None and record_output:
                beeline.add_context_field('app.response', resp)

            return resp
        except Exception as e:
            beeline.add_context({
                "app.exception_type":
                str(type(e)),
                "app.exception_string":
                beeline.internal.stringify_exception(e),
                "app.exception_stacktrace":
                traceback.format_exc(),
            })
            raise e
        finally:
            # This remains false for the lifetime of the module
            COLD_START = False
            beeline.finish_trace(root_span)
            # we have to flush events before the lambda returns
            beeline.get_beeline().client.flush()
Ejemplo n.º 13
0
def _urllibopen(_urlopen, instance, args, kwargs):
    if type(args[0]) != urllib.request.Request:
        args[0] = urllib.request.Request(args[0])

    span = beeline.start_span(context={"meta.type": "http_client"})

    b = beeline.get_beeline()
    if b:
        context = b.tracer_impl.marshal_trace_context()
        if context:
            b.log("urllib lib - adding trace context to outbound request: %s",
                  context)
            args[0].headers['X-Honeycomb-Trace'] = context
        else:
            b.log("urllib lib - no trace context found")

    try:
        resp = None
        beeline.add_context({
            "name": "urllib_%s" % args[0].get_method(),
            "request.method": args[0].get_method(),
            "request.uri": args[0].full_url
        })
        resp = _urlopen(*args, **kwargs)
        return resp
    except Exception as e:
        beeline.add_context({
            "request.error_type":
            str(type(e)),
            "request.error":
            beeline.internal.stringify_exception(e),
        })
        raise
    finally:
        if resp:
            beeline.add_context_field("response.status_code", resp.status)
            content_type = resp.getheader('content-type')
            if content_type:
                beeline.add_context_field("response.content_type",
                                          content_type)
            content_length = resp.getheader('content-length')
            if content_length:
                beeline.add_context_field("response.content_length",
                                          content_length)

        beeline.finish_span(span)
Ejemplo n.º 14
0
    def sirivm(self, message):
        try:
            with beeline.tracer(name="sirivm"):
                if self.command is None:
                    self.command = import_bod_avl.Command().do_source()

                response_timestamp = parse_datetime(message["when"])
                beeline.add_context({
                    "items_count": len(message["items"]),
                    "age": (now() - response_timestamp).total_seconds()
                })

                vehicle_cache_keys = [self.command.get_vehicle_cache_key(item) for item in message["items"]]

                with beeline.tracer(name="cache get many"):
                    vehicle_ids = cache.get_many(vehicle_cache_keys)  # code: id

                with beeline.tracer(name="vehicles in bulk"):
                    vehicles = self.command.vehicles.in_bulk(vehicle_ids.values())  # id: vehicle
                    self.command.vehicle_cache = {  # code: vehicle
                        key: vehicles[vehicle_id] for key, vehicle_id in vehicle_ids.items() if vehicle_id in vehicles
                    }

                with beeline.tracer(name="handle items"):
                    for item in message["items"]:
                        self.command.handle_item(item, response_timestamp)

                with beeline.tracer(name="save"):
                    db_wrapper = HoneyDBWrapper()
                    with ExitStack() as stack:
                        for connection in connections.all():
                            stack.enter_context(connection.execute_wrapper(db_wrapper))
                        self.command.save()

                with beeline.tracer(name="set many"):
                    cache.set_many({
                        key: value
                        for key, value in self.command.vehicle_id_cache.items()
                        if key not in vehicle_ids or value != vehicle_ids[key]
                    }, 43200)
        except Exception as e:
            capture_exception(e)
            raise Exception
Ejemplo n.º 15
0
    def create_http_event(self, request):
        # if beeline has not been initialised, just execute request
        if not beeline.get_beeline():
            return self.get_response(request)

        # Code to be executed for each request before
        # the view (and later middleware) are called.
        dr = DjangoRequest(request)

        request_context = self.get_context_from_request(request)
        root_span = beeline.propagate_and_start_trace(request_context, dr)

        response = self.get_response(request)

        # Code to be executed for each request/response after
        # the view is called.
        response_context = self.get_context_from_response(request, response)
        beeline.add_context(response_context)
        beeline.finish_trace(root_span)

        return response
Ejemplo n.º 16
0
def exception_handler(err):
    beeline.add_context("errors.message", err)
    response = jsonify(err.to_dict())
    response.status_code = err.status_code
    return response
Ejemplo n.º 17
0
def log_exception(name, exception):
    beeline.add_context({
        f"{name}.exception_type": str(type(exception)),
        f"{name}.exception_string": str(exception),
        f"{name}.exception_stacktrace": traceback.format_exc(),
    })