親知らずを抜きました。CLBです。
今回は Salesforce の Apex Rest API 開発でメッセージを正しくできなかった失敗と、
どうすれば正しく表示できるのかを調べたけど、ダメそうだった記録です。
ロギングの失敗:表示されないスタックトレース
業務では以下のようなシステムを作成していました。
- フロントエンド(FE)が画面を表示
- Salesforce に パッケージ化 したApexロジックを配置(これがいわゆるバックエンド、BEになります。)
- REST API で通信してロジックを実行。
本当はちょっと違いがありますが、
どこにでもある一般的な Webアプリだと思っていただければ大丈夫です。
図に書いてある通り、例外エラーの時はスタックトレースが出るよう設定していました。
実際のコードとしては以下のような形で、
@HttpPost
global static String doPost() {
String res;
try {
throw new TestException();
} catch (Exception e) {
res = e.getStackTraceString();
}
return res;
}
このメソッドに対応するAPIをコールすると、
{
"FOO.throwException: line 4, column 1 \n BAR.method: line 2, column 1"
}
のような形で表示される形です。
当然ながら開発者はパッケージ化していない状態で確認しているので、普通にスタックトレースを確認することができていました。
がいざ実際にパッケージ化したものをみて見ると
{
"(名前空間)"
}
おおい!名前空間しか表示されていないやないかーい。
原因と解決の試み
https://help.salesforce.com/articleView?id=000319981&type=1&mode=1
に似たような内容が書いてあるのですが、
- 管理パッケージのデバッグログが有効になっている場合、完全なスタックトレースが結果に表示されます。
- スタックトレースの難読化や非表示はすべて、パートナーが独自実装の詳細を公開しないように保護するためのものです。
という仕様があるようです。
ただし、管理パッケージのデバッグログ
に関してはパッケージを作成した組織が
インストールした組織に対してログインして設定を行う場合のみに有効らしい(どなたか詳しい人がいたら教えてください。)
でどうしたか?というと、
以下catch句でエラーログを適当なオブジェクトに保存してあげれば、ええんでね?と思ったがコレも上手く行かず。
@HttpPost
global static String doPost() {
String res;
try {
throw new TestException();
} catch (Exception e) {
// カスタムオブジェクトに保存する
// これも上手く行かない
Error_Log__c customObj = new Error_Log__c(
StackTrace__c = e.getStackTraceString()
);
insert customObj;
}
return res;
}
開発者コンソールからオブジェクトに保存した内容を見ると・・・
StackTrace__c : "(名前空間)"
ううむ・・・厄介だ。
Sentry に送る?
https://github.com/jmather/SentryForSalesforce
非管理パッケージで発生した例外であれば、どうやら例外を保持できるらしいので
非管理パッケージに例外クラスをラップしておけばできるっぽいが、
ソースコードを一切合切公開しないと行けないので、それはそれで無理だよな・・・・
最後に
管理パッケージでトランザクションが開始された場合、情報を再発生させて登録ユーザに戻すのではなく、管理パッケージ内ですべての例外処理および解決策を実行する必要があります。
https://help.salesforce.com/articleView?id=000319981&type=1&mode=1
そんな事ができるなら苦労しないんだけどね・・・
まぁ我々にできる事と言えば、
try {
throw new TestException();
} catch (Exception e) {
return 'エラーです。value=' + val;
}
でしっかりとエラーログを書く事だけですね。