def test_elasticapm_structlog_log_correlation_ecs_fields(spec_validator):
    apm = elasticapm.Client({"SERVICE_NAME": "apm-service", "DISABLE_SEND": True})
    stream = StringIO()
    logger = structlog.PrintLogger(stream)
    logger = structlog.wrap_logger(
        logger, processors=[structlog_processor, ecs_logging.StructlogFormatter()]
    )
    log = logger.new()

    apm.begin_transaction("test-transaction")
    try:
        with elasticapm.capture_span("test-span"):
            span_id = elasticapm.get_span_id()
            trace_id = elasticapm.get_trace_id()
            transaction_id = elasticapm.get_transaction_id()

            log.info("test message")
    finally:
        apm.end_transaction("test-transaction")

    ecs = json.loads(spec_validator(stream.getvalue().rstrip()))
    ecs.pop("@timestamp")
    assert ecs == {
        "ecs": {"version": "1.6.0"},
        "log.level": "info",
        "message": "test message",
        "span": {"id": span_id},
        "trace": {"id": trace_id},
        "transaction": {"id": transaction_id},
        "service": {"name": "apm-service"},
    }
Esempio n. 2
0
    def _run_message_process(
        self,
        method_frame: pika.spec.Basic.Deliver,
        header_frame: pika.spec.BasicProperties,
        message_body: bytes,
        handler_function: Callable,
        _queue_name: str,
    ) -> CallbackResult:
        if self.apm_client:
            if header_frame.headers and "traceparent" in header_frame.headers:
                parent = elasticapm.trace_parent_from_string(
                    header_frame.headers["traceparent"])
                self.apm_client.begin_transaction("RabbitMQ",
                                                  trace_parent=parent)

        callback_result: CallbackResult = handler_function(
            method_frame=method_frame,
            header_frame=header_frame,
            message_body=message_body,
        )

        trace_id = elasticapm.get_trace_id()
        logger.debug(
            f"{callback_result.action.value.title()} message on Queue<{_queue_name}> with "
            f"delivery_tag: {method_frame.delivery_tag} trace_id: {trace_id}")

        if trace_id:
            tran_result = ("success" if callback_result.action == MQAction.ack
                           else "failure")
            self.apm_client.end_transaction(name=f"MQ QUEUE {_queue_name}",
                                            result=tran_result)

        return callback_result
Esempio n. 3
0
def get_extra_logging_payload():
    payload = {
        "transaction.id": elasticapm.get_transaction_id(),
        "span.id": elasticapm.get_span_id(),
        "trace.id": elasticapm.get_trace_id(),
        "event.dataset": event_dataset
    }
    return payload
def test_elastic_apm_stdlib_with_filter_log_correlation_ecs_fields():
    apm = elasticapm.Client({
        "SERVICE_NAME": "apm-service",
        "DISABLE_SEND": True
    })
    stream = StringIO()
    logger = logging.getLogger("apm-logger")
    handler = logging.StreamHandler(stream)
    handler.setFormatter(
        ecs_logging.StdlibFormatter(
            exclude_fields=["@timestamp", "process", "log.origin.file.line"]))
    handler.addFilter(LoggingFilter())
    logger.addHandler(handler)
    logger.setLevel(logging.DEBUG)

    apm.begin_transaction("test-transaction")
    try:
        with elasticapm.capture_span("test-span"):
            span_id = elasticapm.get_span_id()
            trace_id = elasticapm.get_trace_id()
            transaction_id = elasticapm.get_transaction_id()

            logger.info("test message")
    finally:
        apm.end_transaction("test-transaction")

    ecs = json.loads(stream.getvalue().rstrip())
    assert ecs == {
        "ecs": {
            "version": "1.5.0"
        },
        "log": {
            "level": "info",
            "logger": "apm-logger",
            "origin": {
                "file": {
                    "name": "test_apm.py"
                },
                "function":
                "test_elastic_apm_stdlib_with_filter_log_correlation_ecs_fields",
            },
            "original": "test message",
        },
        "message": "test message",
        "span": {
            "id": span_id
        },
        "trace": {
            "id": trace_id
        },
        "transaction": {
            "id": transaction_id
        },
    }
Esempio n. 5
0
def checkout(request: Purchase = Body(...)):
    """Signup user.
    """
    result = {
        'id': time.time(),
        'username': request.username,
        'email': request.email,
        'cost_spend': request.cost_spend,
        'item_count': request.item_count,
        'billing_amount': request.cost_spend * request.item_count,
    }

    #Different logging levels
    logger.debug('This is a debug message')
    logger.info('This is an info message')
    logger.warning('This is a warning message')
    logger.error('This is an error message')
    logger.critical('This is a critical message')
    logger.exception("This is an exception")

    # add extra field to logstash message
    extra = {
        'test_string': 'python version: ' + repr(sys.version_info),
        'test_boolean': True,
        'test_dict': {
            'a': 1,
            'b': 'c'
        },
        'test_float': 1.23,
        'test_integer': 123,
        'test_list': [1, 2, '3'],
    }
    logger.info('test extra fields', extra=extra)

    #Capture an arbitrary exception by calling capture_exception:
    try:
        1 / 0
    except ZeroDivisionError:
        apm_client.capture_exception()

    # Log a generic message with capture_message:
    apm_client.capture_message('hello, world!')

    # Alternatively, a parameterized message as a dictionary.
    apm_client.capture_message(
        param_message={
            'message': 'Billing process for %s succeeded. Amount: %s',
            'params': (result['id'], result['billing_amount']),
        })

    # Get the id of the current transaction.
    transaction_id = elasticapm.get_transaction_id()
    logger.info('Current transaction_id: ' + str(transaction_id))

    # Get the trace_id of the current transaction’s trace.
    trace_id = elasticapm.get_trace_id()
    logger.info('Current trace_id: ' + str(trace_id))

    # Get the id of the current span.
    span_id = elasticapm.get_span_id()
    logger.info('Current span_id: ' + str(span_id))

    return result
Esempio n. 6
0
 def get_parent_id(self):
     """
     :return: returns the parent ID of the current transaction.
     """
     return "{:02x}-{}-{}-{:02x}".format(0, get_trace_id(), get_span_id(),
                                         1)
def test_get_trace_id(elasticapm_client):
    trace_parent = TraceParent.from_string("00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-03")
    elasticapm_client.begin_transaction("test", trace_parent=trace_parent)
    assert trace_parent.trace_id == elasticapm.get_trace_id()
Esempio n. 8
0
    def publish(
        self,
        *,
        exchange_name: str,
        message_body: Dict,
        event_name: str = None,
        properties: Dict = None,
        routing_key: str = "",
        max_retry: int = None,
        max_delay_on_retry: int = 30,
    ) -> None:
        """
        Publish message using sync http request
        :param event_name: key event name like `app-release, user-register`
        :param exchange_name: target exchange name
        :param message_body: message body, should be able to call json.dumps
        :param properties: message properties
        :param routing_key: routing key
        :param max_retry: max retry count, will use global_max_retry when it set as empty
        :param max_delay_on_retry: max delay when retrying to send message
        :return:
        """
        # setup trace context
        traceparent_string = self._start_trace(event_name=event_name)

        if max_retry is None:
            max_retry = self.global_max_retry

        # Prepare message and url
        message = self._build_message_json(
            message_body=message_body,
            properties=properties,
            routing_key=routing_key,
            traceparent_string=traceparent_string,
            event_name=event_name,
        )
        url = f"{self.scheme}://{self.host}/api/exchanges/{quote_plus(self.virtual_host)}/{exchange_name}/publish"

        try:
            # Retry for n times before give up.
            for attempt in Retrying(
                stop=stop_after_attempt(max_retry),
                reraise=True,
                wait=wait_random(min=1, max=max_delay_on_retry),
            ):
                with attempt:
                    self._sync_publish(
                        url=url,
                        message=message,
                    )

            trace_id = elasticapm.get_trace_id()
            logger.debug(
                f"Successfully send MQ message to exchange: {exchange_name} trace_id: {trace_id}"
            )
            if self.apm_client:
                self.apm_client.end_transaction(name=f"MQ PUBLISH {event_name}", result="success")
        except Exception as e:
            logger.warning(
                "Failed to send MQ message to exchange: {exchange_name} trace_id: {trace_id}"
            )
            if self.apm_client:
                self.apm_client.capture_exception()
                self.apm_client.end_transaction(name=f"MQ PUBLISH {event_name}", result="failure")
            raise e