【UiPath】エラーハンドリングについて考える（前編）

##はじめに
この記事の執筆は以下の環境で行っています。
Studio 2021.10.3 (Community License)
言語：日本語

###この記事は
UiPath Adventカレンダーの5日目の記事になります。

https://qiita.com/advent-calendar/2021/uipath

###なにをするの？
UiPathでエラーが発生した際に、その内容をログに残したり通知したりする仕組みのうち、
特にアクティビティ名などエラー時の情報を集める方法を紹介します。

※既にいろんな方が紹介済みの内容ですので、筆者自身の備忘録の意味合いが強い記事になります

##エラー時の情報収集の仕方

###トライキャッチ(Try Catch)
エラーハンドリングでおなじみの「トライキャッチ」アクティビティを使用すると、
Tryの中で発生したエラー情報をCatchesで取得することができます。

このとき取得できるエラー情報の内容は、エラーの発生元が「ワークフロー ファイルを呼び出し(Invoke Workflow File)」アクティビティを介しているか否かで異なります。

試しに、Excelファイルを読み取る操作でエラーを起こして、
Catchesの中でエラー情報にどのような内容が格納されているか確認してみます。

こちらが直接「トライキャッチ」で囲った時の様子です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545766/b647ad0f-61f2-cb04-02d1-188ef57de77b.png)

次に、こちらが「ワークフロー ファイルを呼び出し」を介して「トライキャッチ」で囲った時の様子です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545766/088d571f-5e61-bee2-2641-3ab6bd90eb4e.png)

パッと見では同じように見えますが、後者では情報を集める上で重要な情報が**Data**と**Source**に値が格納されています。

まずは簡単な**Source**について値を確認してみると、String型でエラー発生源のアクティビティに付けた名前(＝DisplayName)が格納されています。
そのため、`exception.Source`と記述することで、簡単にエラー発生源を記載することができます。

次に**Data**に格納されている値を確認してみると、IDictionary型で`FaultedDetails`というものが格納されています。
内容をさらに詳しく見てみると、**Source**に格納されていた情報に加え**何のアクティビティが使用された**という情報と
エラーが発生した**ワークフローファイルのフルパス**が格納されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545766/965208b0-6e33-c8b1-b5b5-8c411c5538ae.png)

例のようにExcelからデータを読み取る場合、DisplayNameだけではExcel配下とWorkbook配下どちらを使用したか分からなくなる場合があります。
そういった際に、ActivityFullNameを参照すれば使用したアクティビティを特定できるので、エラー原因の特定に貢献することができます。

難点があるとすれば、`FaultedDetails`の情報を取り出すにはやや複雑な式を書く必要がある点が挙げられます。
式についてはForumで回答がありますので、以下を参考にしてみてください。

https://forum.uipath.com/t/topic/323722

https://forum.uipath.com/t/how-to-get-displayname-of-an-activity/182583

ここまでで紹介した内容をまとめると、
「トライキャッチ」と「ワークフローを呼び出し」を**組み合わせる**ことでエラー情報を集められることが分かりました。

では、「ワークフローを呼び出し」を使用しなければ、エラー発生源を示す情報を集めることはできないのでしょうか？
そんな事はなく、次に紹介する「グローバルハンドラー」を使用することでも、同様以上の情報を集めることができます。

###グローバルハンドラー
「グローバルハンドラー」の利用にはいくつか方法がありますが、基本的にはプロジェクト内で新規にワークフローを作成する際に選択して作成します。
或いは、既存のワークフローを右クリックした時に表示されるメニューから設定することも可能です
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545766/2e402605-ef56-354b-cf2c-cb697437dd4b.png)　　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545766/35a82615-69f6-2013-8e59-ebc8d2d7fda0.png)

「グローバルハンドラー」に設定されたワークフローが**プロジェクト内**に存在する場合、
「トライキャッチ」を使用していない箇所であっても、エラーが発生した際に処理が「グローバルハンドラー」に設定されたワークフローに遷移します。
新規に作成した「グローバルハンドラー」には`UiPath.Activities.Contracts.ExceptionHandlerArgs`という特殊な型で作成された引数**errorInfo**が作成されており、トライキャッチで補足できた情報の他に、実行時に読み込まれていた変数や引数の一覧なども参照することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545766/29bf5c7c-964e-c3c8-bddb-01ef84ba191c.png)
変数の一覧からは、「繰り返し (コレクションの各要素)(For Each)」などを使用することでそれぞれの値をログに出力することが可能です。
しかし、この方法を用いるとプライベート設定の有無に関わらず変数の中身を出力してしまうため、扱いには注意が必要です。

非常に強力で便利な「グローバルハンドラー」ですが、**意識して**使ったことがある方はあまりいらっしゃらないように思えます。(筆者の主観です)
しかし、多くの方が実は**無意識に**使ったことがある機能でもあります。

何故かと言うと、StudioXで作成したプロジェクトにおいては、自動的に`GlobalHandlerX.xaml`という名前のワークフローが生成されており「グローバルハンドラー」として設定されているからです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545766/91a70085-3a6c-dd85-9736-0d5fc10b2801.png)

開発者がエラー処理（ログ出力など）を考えずに作成できるのが、StudioXで開発する際のメリットになりますが、
その秘密を担っているのが「グローバルハンドラー」の仕組みだったのです。
##さいごに
いかがでしたでしょうか。
本記事を通じて、エラーハンドリングにおいて重要なエラー情報の取得方法について理解を深めていただければ幸いです。

後編の記事では「Attended Framework」や「REFramework」の中で実際にどのようなエラーハンドリングが行われているのかを紹介したいと思っております。