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"}, }
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
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 }, }
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
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()
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