前几个星期在公司的测试服务器上搭建了 Exceptionless 对公司的 Asp.net core 项目进行遥测。在之前都是远程桌面登录上去,然后去翻日志文件看有没有异常,效率极其的低。用了 Exceptionless 之后,效率高了不少,而且能收集到更多信息了。

最近准备要过年了,项目也上线了一段时间趋于稳定,算是比较闲了一点。想着要不把手上的 UWP 项目也加上 Exceptionless 进行遥测吧,毕竟微软商店的 Dashboard 那异常也几乎是看不出啥的,而且这测试服务器性能又是过剩的,不用白不用。

但我一操作起来,就发现了个大问题,Exceptionless 官方并没有提供 UWP 的库(Winform、WPF、asp.net core 的都有)。翻查了 github 上相关的 issue,官方建议是用 .net standard 版本的。然而实际操作之后,我发现还需要额外的代码来处理 UWP 中的 UnhandledException,本文就记录一下。

首先当然是在 Exceptionless 平台上创建项目获取 ApiKey 了,这个就不多说了。然后 UWP 项目引用 Exceptionless 的 nuget 包

在 App.xaml.cs 的构造函数中添加 SetUpExceptionless 代码:

public App()
{
    this.InitializeComponent();
    this.Suspending += OnSuspending;
    SetUpExceptionless();
}

然后先初步实现 SetUpExceptionless 方法:

private void SetUpExceptionless()
{
    var client = ExceptionlessClient.Default;
    client.Configuration.ServerUrl = "";
    client.Configuration.ApiKey = "";

    client.Startup();
}

由于是自建 Exceptionless 平台,所以需要配置一下 ServerUrl。ApiKey 配置为从平台获取到的 ApiKey。

接下来是处理 UnhandledException,在 UWP 平台中,有两种情况,一种是在 App 类上触发的,另一种是在 AppDomain 上触发的。这两种我们都要监听到。但如何监听呢,这里先看看官方在 WPF 平台是如何实现的:

主要是图上红框的两行,第一行主要是捕获线程的异常,第二行捕获了 App 的异常。而捕获线程异常的方法内部用到了 Winform 的类,这里我们就忽略,因为 UWP 里没有这些类,而且 UWP 中非 UI 线程的异常是可以通过 AppDomain.UnhandledException 事件来捕获的。这里我们看第二行的实现

可见是对 System.Windows.Application.Current.DispatcherUnhandledException 事件进行了订阅,然后给 Exceptionless。

依样画葫芦,完善我们的 SetUpExceptionless 方法:

private void SetUpExceptionless()
{
    var client = ExceptionlessClient.Default;
    client.Configuration.ServerUrl = "";
    client.Configuration.ApiKey = "";

    UnhandledException += (sender, args) =>
    {
        var contextData = new ContextData();
        contextData.MarkAsUnhandledError();
        contextData.SetSubmissionMethod("App_UnhandledException");

        args.Exception.ToExceptionless(contextData, ExceptionlessClient.Default).Submit();

        client.ProcessQueue();
    };
    AppDomain.CurrentDomain.UnhandledException += (sender, args) =>
    {
        var exception = args.ExceptionObject as Exception;
        if (exception == null)
        {
            return;
        }

        var contextData = new ContextData();
        contextData.MarkAsUnhandledError();
        contextData.SetSubmissionMethod("AppDomain_UnhandledException");

        exception.ToExceptionless(contextData, ExceptionlessClient.Default).Submit();

        client.ProcessQueue();
    };

    client.Startup();
}

接下来我们测试一下是否起效,先手动抛个异常,我就直接建一个 Button,然后 Click 抛个异常好了。

private void TestButton_Click(object sender, RoutedEventArgs e)
{
    throw new Exception("测试 Exceptionless 集成");
}

运行后,点击按钮,然后 App 炸掉之后我们去看 Exceptionless 平台。

完美!

02-11 04:44