[IADP Series] 誰說一定要每個錯誤都要覆寫 Crash Report? 由 Exception 來決定吧。

Crash Report 的原理部份 Alex Lee 大已經有寫一篇文章說明,這裡我就不贅述,不過如果要為每個錯誤都覆寫一次 DefaultCrashReport,那如果應用程式中有上百種錯誤,那豈不是要寫上百個 Crash Report?累死人也 … 那如果可以把 Crash Report 的資料交由 Exception 來決定,開發人員只要簡單的產生自訂的 Exception 的話,那不就變得很簡單?

Crash Report 是 IADP SDK 的功能之一,作用是用來在 IADP-Compliant 應用程式發生錯誤時,將錯誤資料傳回 Intel AppUp Center 中,供開發人員查詢與除錯之用,就像是 Windows Error Reporting 的功能一樣,雖然在 SDK 中已經有一個內建的 DefaultCrashReport,但我想不會有開發人員想用它吧,因為它提供的資料並不多,然而它有保留一個 Custom Fields 的擴充功能,可以允許開發人員使用最多 20 個欄位,以存放一些必要的除錯輔助資料。

Crash Report 的原理部份 Alex Lee 大已經有寫一篇文章說明,這裡我就不贅述,不過如果要為每個錯誤都覆寫一次 DefaultCrashReport,那如果應用程式中有上百種錯誤,那豈不是要寫上百個 Crash Report?累死人也 … 那如果可以把 Crash Report 的資料交由 Exception 來決定,開發人員只要簡單的產生自訂的 Exception 的話,那不就變得很簡單?

是的,本文要介紹的就是這樣的功能,而且程式碼並不難,只是要了解一下 .NET Framework 的 Metadata 機制 (也就是 Attribute),我之前寫過一篇介紹文,若讀者不了解的話可參考一下。

OK,那就進入正題吧,其實它的程式碼一點都不難:

public class IadpCrashReport : com.intel.adp.DefaultCrashReport
{
    public override void PopulateCrashReportFields()
    {
        PropertyInfo[] properties = this.UnhandledException.GetType().GetProperties();

        foreach (PropertyInfo property in properties)
        {
            IadpAppCustomErrorItemAttribute[] errorItems = 
                property.GetCustomAttributes(typeof(IadpAppCustomErrorItemAttribute), true)
                as IadpAppCustomErrorItemAttribute[];

            if (errorItems != null && errorItems.Length > 0)
            {
                com.intel.adp.ADP_CrashReportField field = new com.intel.adp.ADP_CrashReportField()
                {
                    name = property.Name,
                    value = (property.GetValue(this.UnhandledException, null) == null)
                            ? string.Empty
                            : property.GetValue(this.UnhandledException, null).ToString()
                };

                this._customField.Add(field);
            }
        }
    }

    public override void PopulateCategory()
    {
        if (this.UnhandledException is IadpAppException)
            this._category = 
            this.UnhandledException.GetType().GetProperty("Category").GetValue(this.UnhandledException, null).ToString();
        else
            this._category = this.UnhandledException.GetType().FullName;
    }
}

IadpCrashReport 是繼承自 com.intel.adp.DefaultCrashReport 的一個自訂 Crash Report,它只覆寫了 PopulateCrashReportFields() 以及 PopulateCategory() 兩個方法,其實 DefaultCrashReport 有很多方法可以覆寫,如:

image

在表格中的 Source 是標註 Developer 的項目,均有提供 Populate 的方法可以覆寫,開發人員可以自己設定那些欄位要怎麼設定,不過大多數的情況下,我們不需要動到 ModuleName, LineNumber, Message 以及 ErrorData (StackTrace) 四項資料 (這四個會由 DefaultCrashReport 自動由 Exception 中抽取),而我們需要的是不會在 Exception 中出現的 Category 以及 custom fields,所以 IadpCrashReport 覆寫了這兩個方法,同時它會檢查 Exception 的種類,如果是 IadpAppException 或衍生類別的話,它會將 Category 屬性加到 Crash Report 中,否則會把 Exception 的全名加到 Crash Report。

再來最重要的就是 custom fields 了,IadpCrashReport 會判斷 IadpAppException 與其衍生類別中有沒有屬性被標註 IadpAppCustomErrorItem,如果有的話會寫入到 Crash Report 的自訂欄位中,若否則忽略,這也代表欄位可以由 IadpAppException 決定。

而 IadpAppException 的程式也很簡單:

public class IadpAppException : Exception
{
    public string Category { get; set; }

    public IadpAppException(string Category)
    {
        this.Category = Category;
    }

    public IadpAppException(string Category, string Message) : base(Message)
    {
        this.Category = Category;
    }
}

至於 IadpAppCustomErrorItem 的程式也沒什麼,它只是為了標註屬性要被寫入 Crash Report,因此也不需要什麼特別的處理:

public class IadpAppCustomErrorItemAttribute : Attribute
{
}

至此,我們的 Crash Report 就完成了,而開發人員只要由 IadpAppException 衍生自己的 Exception 類別,並且在要保存到 Crash Report 中的自訂屬性上加入 [IadpAppCustomErrorItem] 即可,例如:

public class IadpSDKException : IadpAppException
{
   
[IadpAppCustomErrorItem]
    public com.intel.adp.ADP_RET_CODE Code { get; private set; }

    public IadpSDKException(string Category, com.intel.adp.ADP_RET_CODE Code, string Message) : base(Category, Message)
    {
        this.Code = Code;
    }
}

然後要在初始化 AdpApplication 時,設定 AdpApplication 使用 IadpCrashReport:

this._adpApplication.SetCrashReport(new IadpCrashReport());

就能在應用程式執行發生錯誤時自動由 Exception 來決定並產生 Crash Report 了。

 

Reference:

IADP SDK
IADP SDK Developer's Guide