c# - Azure Functions v1 中的 HTTP 触发器如何返回异步堆栈跟踪?

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

我创建了一个带有 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()

最佳答案

此功能在 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 ...

关于c# - Azure Functions v1 中的 HTTP 触发器如何返回异步堆栈跟踪?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51216663/

相关文章:

C#比较两段数据

c# - 在 win 10 通用应用程序中使用 mvvm-light 导航服务时,无法将页面类型的对象转换为类型 'Windows.UI.Xaml.Controls.Frame'

javascript - 使用嵌套的异步请求循环遍历异步请求

c# - 如何实现高效的 WhenEach 流式传输任务结果的 IAsyncEnumerable?

.net - 获取当前登录的 Windows 用户?

c# - TAP的多任务处理

c# - BindingExpression路径错误

c# - SecurityElement.IsValidText 在 "&"上返回 true ... 为什么?

c++ - C++/CLI前向声明

c# - 重温 Thread.Abort() - 它安全吗?