我使用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行代码即可看到这一点。
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中注册这个中间件类,如下所示:
app.middleware("http")(AppInsightsMiddleware(app, sampler=samplers.AlwaysOnSampler()))发布于 2022-07-26 12:25:41
显式处理处理API请求时可能发生的任何异常。这允许您完成对请求的跟踪,将状态代码设置为500。然后可以重新抛出异常,以确保应用程序引发预期的异常。
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 exceptionhttps://stackoverflow.com/questions/73108795
复制相似问题