【问题标题】:How does HTTP Trigger in Azure Functions v1 return async stack trace?Azure Functions v1 中的 HTTP 触发器如何返回异步堆栈跟踪?
【发布时间】:2018-07-06 19:32:20
【问题描述】:

我创建了一个带有 HTTP 触发器的 Azure 函数。当我在本地运行它时,我注意到未捕获的异常在 HTTP 响应中返回了一个干净的异步感知堆栈跟踪。但是,在异常上调用 ToString() 会给出旧的笨重异常格式。哪个组件执行干净的异步感知堆栈跟踪格式化?我们可以在代码中使用它吗?我在 Azure Functions Runtime v1 上运行,它在 .NET Framework 上运行,而不是在 .NET Core 上运行。

public static class Function1
{
    [FunctionName("Function1")]
    public static async Task<HttpResponseMessage> Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req,
        TraceWriter log)
    {
        await A();
        return req.CreateResponse(HttpStatusCode.OK);
    }

    private static async Task A()
    {
        await B();
    }

    private static async Task B()
    {
        await C();
    }

    private static async Task C()
    {
        await D();
    }

    private static async Task D()
    {
        await Task.Delay(1);
        throw new InvalidOperationException();
    }

这是未捕获异常的 HTTP 响应中返回的干净的异步感知堆栈跟踪:

Microsoft.Azure.WebJobs.Host.FunctionInvocationException : Exception while executing function: Function1 ---> System.InvalidOperationException : Operation is not valid due to the current state of the object.
   at async FunctionApp1.Function1.D()
   at async FunctionApp1.Function1.C()
   at async FunctionApp1.Function1.B()
   at async FunctionApp1.Function1.A()
   at async FunctionApp1.Function1.Run(HttpRequestMessage req,TraceWriter log)
   at async Microsoft.Azure.WebJobs.Host.Executors.FunctionInvoker`2.InvokeAsync[TReflected,TReturnValue](Object instance,Object[] arguments)
   at async Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.InvokeAsync(IFunctionInvoker invoker,ParameterHelper parameterHelper,CancellationTokenSource timeoutTokenSource,CancellationTokenSource functionCancellationTokenSource,Boolean throwOnTimeout,TimeSpan timerInterval,IFunctionInstance instance)
   at async Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.ExecuteWithWatchersAsync(IFunctionInstance instance,ParameterHelper parameterHelper,TraceWriter traceWriter,CancellationTokenSource functionCancellationTokenSource)
   at async Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.ExecuteWithLoggingAsync(??)
   at async Microsoft.Azure.WebJobs.Host.Executors.FunctionExecutor.ExecuteWithLoggingAsync(??)

这是在异常上调用ToString() 的结果:

System.InvalidOperationException: Operation is not valid due to the current state of the object.
   at FunctionApp1.Function1.<D>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at FunctionApp1.Function1.<C>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at FunctionApp1.Function1.<B>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at FunctionApp1.Function1.<A>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at FunctionApp1.Function1.<Run>d__0.MoveNext()

【问题讨论】:

    标签: c# .net async-await azure-functions stack-trace


    【解决方案1】:

    此功能在 ExceptionFormatter 类中实现,该类是 Azure WebJobs SDK 本身的一部分。要利用它,只需调用GetFormattedException 方法:

    try
    {
        await A();
        return req.CreateResponse(HttpStatusCode.OK);
    }
    catch (Exception ex)
    {
        return req.CreateResponse(
            HttpStatusCode.InternalServerError, 
            ExceptionFormatter.GetFormattedException(ex),   // ← here
            MediaTypeNames.Text.Plain);
    }
    

    结果:

    System.InvalidOperationException : Operation is not valid due to the current state of the object.
       at async FunctionApp1.Function1.D()
       at async FunctionApp1.Function1.C()
       at async FunctionApp1.Function1.B()
       at async FunctionApp1.Function1.A()
       at async FunctionApp1.Function1.Run(HttpRequestMessage req,TraceWriter log)
    

    如果您未在 Azure 上运行(并且不想引用该 SDK),则在名为 Ben.Demystifier 的 NuGet 包中实现了类似(且更丰富)的功能。安装上述包并在异常情况下调用ToStringDemystified()

    try
    {
        await A();
        return req.CreateResponse(HttpStatusCode.OK);
    }
    catch (Exception ex)
    {
        return req.CreateResponse(
            HttpStatusCode.InternalServerError, 
            ex.ToStringDemystified(),   // ← here
            MediaTypeNames.Text.Plain);
    }
    

    结果:

    System.InvalidOperationException: Operation is not valid due to the current state of the object.
       at async Task FunctionApp1.Function1.D() in ...
       at async Task FunctionApp1.Function1.C() in ...
       at async Task FunctionApp1.Function1.B() in ...
       at async Task FunctionApp1.Function1.A() in ...
       at async Task<HttpResponseMessage> FunctionApp1.Function1.Run(HttpRequestMessage req, TraceWriter log) in ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-02-25
      • 2018-02-21
      • 2013-02-24
      • 2011-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-10
      相关资源
      最近更新 更多