首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用opencensus跟踪失败的快速请求

使用opencensus跟踪失败的快速请求
EN

Stack Overflow用户
提问于 2022-07-25 11:54:22
回答 1查看 271关注 0票数 0

我使用opencensus-python跟踪在生产中运行的python 法拉皮应用程序的请求,并使用opencensus出口商将信息导出到Azure AppInsights。我遵循了Azure监视器文档,并得到了这一期文章的帮助,它将所有必要的位放在一个有用的中间件类中。

后来才意识到,导致应用程序崩溃的请求,即未处理的5xx类型错误,永远不会被跟踪,因为执行请求逻辑的调用在任何跟踪发生之前都会失败。Azure Monitor文档只讨论通过日志跟踪异常,但这与请求的跟踪是分开的,除非我遗漏了什么。我当然不想失去失败的请求,这些是超级重要的跟踪!我习惯于在应用程序洞察力中使用“故障”选项卡来监控任何失败的请求。

我认为跟踪这些请求的方法是使用try/catch显式处理任何内部异常并导出跟踪,手动将结果代码设置为500。但我发现很奇怪的是,似乎没有这方面的文件,在开放或Azure。

我现在遇到的问题是:这个中间件函数将返回一个" response“对象,该对象然后作为可调用的对象使用(不确定原因)--但如果在底层处理(即在await call_next(request))中发现异常,我就没有任何返回响应。我尝试返回None,但这只会导致进一步的异常(None是不可调用的)。

下面是我的中间件类的版本--它非常类似于我链接的问题帖子,但我正在尝试/捕捉await call_next(request),而不是让它单独失败。向下滚动到最后5行代码即可看到这一点。

代码语言:javascript
复制
import logging

from fastapi import Request
from opencensus.trace import (
    attributes_helper,
    execution_context,
    samplers,
)
from opencensus.ext.azure.trace_exporter import AzureExporter
from opencensus.trace import span as span_module
from opencensus.trace import tracer as tracer_module
from opencensus.trace import utils
from opencensus.trace.propagation import trace_context_http_header_format
from opencensus.ext.azure.log_exporter import AzureLogHandler
from starlette.types import ASGIApp

from src.settings import settings

HTTP_HOST = attributes_helper.COMMON_ATTRIBUTES["HTTP_HOST"]
HTTP_METHOD = attributes_helper.COMMON_ATTRIBUTES["HTTP_METHOD"]
HTTP_PATH = attributes_helper.COMMON_ATTRIBUTES["HTTP_PATH"]
HTTP_ROUTE = attributes_helper.COMMON_ATTRIBUTES["HTTP_ROUTE"]
HTTP_URL = attributes_helper.COMMON_ATTRIBUTES["HTTP_URL"]
HTTP_STATUS_CODE = attributes_helper.COMMON_ATTRIBUTES["HTTP_STATUS_CODE"]

module_logger = logging.getLogger(__name__)
module_logger.addHandler(AzureLogHandler(
    connection_string=settings.appinsights_connection_string
))

class AppInsightsMiddleware:
    """
    Middleware class to handle tracing of fastapi requests and exporting the data to AppInsights. 
    
    Most of the code here is copied from a github issue: https://github.com/census-instrumentation/opencensus-python/issues/1020
    """
    def __init__(
        self,
        app: ASGIApp,
        excludelist_paths=None,
        excludelist_hostnames=None,
        sampler=None,
        exporter=None,
        propagator=None,
    ) -> None:
        self.app = app
        self.excludelist_paths = excludelist_paths
        self.excludelist_hostnames = excludelist_hostnames
        self.sampler = sampler or samplers.AlwaysOnSampler()
        self.propagator = (
            propagator or trace_context_http_header_format.TraceContextPropagator()
        )
        self.exporter = exporter or AzureExporter(
            connection_string=settings.appinsights_connection_string
        )

    async def __call__(self, request: Request, call_next):

        # Do not trace if the url is in the exclude list
        if utils.disable_tracing_url(str(request.url), self.excludelist_paths):
            return await call_next(request)

        try:
            span_context = self.propagator.from_headers(request.headers)

            tracer = tracer_module.Tracer(
                span_context=span_context,
                sampler=self.sampler,
                exporter=self.exporter,
                propagator=self.propagator,
            )
        except Exception:
            module_logger.error("Failed to trace request", exc_info=True)
            return await call_next(request)

        try:
            span = tracer.start_span()
            span.span_kind = span_module.SpanKind.SERVER
            span.name = "[{}]{}".format(request.method, request.url)
            tracer.add_attribute_to_current_span(HTTP_HOST, request.url.hostname)
            tracer.add_attribute_to_current_span(HTTP_METHOD, request.method)
            tracer.add_attribute_to_current_span(HTTP_PATH, request.url.path)
            tracer.add_attribute_to_current_span(HTTP_URL, str(request.url))
            execution_context.set_opencensus_attr(
                "excludelist_hostnames", self.excludelist_hostnames
            )
        except Exception:  # pragma: NO COVER
            module_logger.error("Failed to trace request", exc_info=True)

        try:
            response = await call_next(request)
            tracer.add_attribute_to_current_span(HTTP_STATUS_CODE, response.status_code)
            tracer.end_span()
            return response
        # Explicitly handle any internal exception here, and set status code to 500 
        except Exception as exception:
            module_logger.exception(exception)
            tracer.add_attribute_to_current_span(HTTP_STATUS_CODE, 500)
            tracer.end_span()
            return None

然后,我在main.py中注册这个中间件类,如下所示:

代码语言:javascript
复制
app.middleware("http")(AppInsightsMiddleware(app, sampler=samplers.AlwaysOnSampler()))
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-07-26 12:25:41

显式处理处理API请求时可能发生的任何异常。这允许您完成对请求的跟踪,将状态代码设置为500。然后可以重新抛出异常,以确保应用程序引发预期的异常。

代码语言:javascript
复制
        try:
            response = await call_next(request)
            tracer.add_attribute_to_current_span(HTTP_STATUS_CODE, response.status_code)
            tracer.end_span()
            return response
        # Explicitly handle any internal exception here, and set status code to 500 
        except Exception as exception:
            module_logger.exception(exception)
            tracer.add_attribute_to_current_span(HTTP_STATUS_CODE, 500)
            tracer.end_span()
            raise exception
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73108795

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档