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

时间:2018-07-06 19:32:21

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

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

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()

1 个答案:

答案 0 :(得分:2)

此功能在Azure WebJobs SDK本身的ExceptionFormatter类中实现。要利用它,可以简单地调用<span [hidden]="docker.code==0" class="badge badge-danger" ng-bind-html-unsafe="docker.console"></span> 方法:

GetFormattedException

结果:

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

如果您不在Azure上运行(并且不想引用该SDK),则在名为Ben.Demystifier的NuGet程序包中实现了类似(并且功能更丰富)的功能。安装上述软件包,并在例外情况下致电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)

ToStringDemystified()

结果:

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