Theolizer  Version.1.2.0
serializer for C++ / Do you want to update your classes easily ?
エラー報告

ここではTheolizerが検出するエラーの受け取り方とその後処理について説明します。


1.Theolizerエラー・クラス

1-1.ErrorInfoクラス

Theolzierのエラーは report.h で定義している theolizer::ErrorInfo クラスで表現します。
主な公開メンバは以下の通りです。

メンバ名意味
theolizer::ErrorType getErrorType() const;エラー種別コード返却
theolizer::ErrorKind getErrorKind() const;エラー分類コード返却
std::string getString() const;全エラー情報を含むエラー・メッセージ返却
bool isError() const;エラーならtrue
operator bool() const;エラーか警告ならtrue
bool operator!() const;エラーも警告もないならtrue

1-2.ErrorType枚挙型

theolizer::ErrorTypeはenum型で以下のシンボルを持ちます。

シンボル名意味
Noneエラーでも警告でも無い
Warning警告
Errorエラー

1-3.ErrorKind枚挙型

theolizer::ErrorKindはenum型で以下のシンボルを持ちます。

シンボル名意味
Unclassified未分類
WrongUsing使い方間違い
IOErrorI/O動作エラー
UnknownData非対応シリアライズ・データ・フォーマット
UnknownVerson非対応バージョン(未知のグローバル・バージョン番号)

1-4.ErrorInfoのgetString()のフォーマット

ErrorInfoのgetString()で取得できる文字列は次のようなフォーマットです。

ErrorType(ErrorKind),エラーを検出したインスタンス{ソース・ファイル名(行番号)} : エラー・メッセージ

エラーを検出したインスタンス直後の"{ソース・ファイル名(行番号)}"は可能な時のみ表示されます。

シリアライザのコンストラクタでエラー検出した時(型チェック・エラー)の例

Error(UnknownData),IntrusiveBase2.mULongLong : Unmatch type.{core_serializer.cpp(1570)}

なお、このエラー・メッセージに含まれるソース・ファイルと行番号は、当該エラーを検出したTheolizerのソースと行番号です。

THEOLIZER_PROCESS()等のマクロ内でエラー検出した時の例

Error(UnknownData),aInt{test_basic_process.cpp(212)} : Logical Error on stream.


2.Theolizerで検出したエラーの記録

Theolizerは2種類のエラー記録を持っています。 どちらとも複数回エラーか警告が発生した場合、最後のエラーが記録されます。
ただし、エラー記録を優先するため、エラー発生後の警告はエラーが解除(resetError)されるまで記録されません。

2-1.シリアライザのインスタンス

シリアライザ・インスタンス毎に当該シリアライザで発生したエラー(もしくは警告)を保持します。
警告ではないエラーが発生している場合、シリアライザへの要求は全て処理されず、WrongUsingとなります。
回復するためには、ストリームの再同期とresetError()呼び出しが必要です。

エラー情報に関するメンバ関数は「3-1-2.メンバ関数 」を参照下さい。

2-2.ErrorReporterシングルトン

theolizer::ErrorReporterはthread_localなシングルトンですのでスレッド毎に一つだけ存在します。
当該スレッドで発生した最後のエラーか警告を保持します。
シングルトンですのでコンストラクト、コピー、ムーブできません。

以下のstatic関数が公開されています。

メンバ名意味
static theolizer::ErrorInfo const& getErrorInfo() noexcept;エラー情報を返却します。
static bool isError() noexcept;エラーが発生している時trueを返却します。
static void resetError() noexcept;エラー状態を解除します。


3.Theolizerで検出したエラーの通知方法

シリアライザからのエラー通知方法は2つあります。

  1. 例外許可の場合
    シリアライザ・コンストラクタのiNoThrowExceptionパラメータをfalse(デフォルト)として、シリアライザをコンストラクトすると例外が許可されます。
    エラーを検出した時に theolizer::ErrorInfo 例外を throw します。

  2. 例外禁止の場合
    シリアライザ・コンストラクタのiNoThrowExceptionパラメータをtrueにして、シリアライザをコンストラクトすると例外が禁止されます。
    エラーを検出しても例外を投げません。getErrorInfo()等でエラー情報を受け取って下さい。
シリアライザにエラー状態が残ったままデストラクトしないで下さい
エラーの受け取り忘れを防止するため、エラーが発生しているのにresetError()せずにデストラクトするとプログラムを強制終了させていますので、例外を禁止している時は、必ずエラーを受け取りresetError()してからデストラクトするようにして下さい。(6.サンプル・ソース 参照)

なお、例外許可時はエラーの受け取り損ないは発生しないためresetError()してなくても強制終了しません。


4.エラー状態の回復方法

シリアライザのエラー状態を解除するには、下記の手順で行います。

  1. シリアライザへ渡しているストリームを同期する。
    次に読むべきデータ先頭から読み出せる状態にします。
    この処理はユーザ・プログラムにて行って下さい。

  2. シリアライザのエラーをリセットする。
    シリアライザ・インスタンス.resetError()により行います。

ただし、一般にファイルからの回復時にエラーが発生した時の原因は下記ですので、ファイルへの保存/回復の場合はストリームをオープンしたままエラー回復する操作を行うことは原則としてありません。

  • プログラムのバグ(Theolizerが非対応な変更をしたプログラムで回復しようとした。)
  • ファイル指定ミス(指定したフォーマットと実際のフォーマットの不一致)
  • ファイル破壊

通信による受信時にエラーが発生した時は、再同期することでリカバリすることが可能です。
なお、通信回線の同期はTheolizerによるサポートはありません。ユーザ・プログラムにて再同期して下さい。


5.エラー・ログ

TheolizerはTheolizerで検出したエラーをログ・ファイルへ記録する機能をサポートしています。

5-1.THEOLIZER_ERRORLOG_FILE()マクロの指定方法

THEOLIZER_ERRORLOG_FILE()マクロをユーザ・プログラム内で1箇所だけ書くことで有効になります。

グローバル名前空間で以下を記述します。

THEOLIZER_ERRORLOG_FILE("LogFilePath%1%.log");
  • "LogFilePath"の部分でエラー・ログのパスを指定します。
    相対パスで指定した場合、プログラム起動時のカレント・フォルダからの相対になります。

  • "%1%"はTheolizerがログ・ファイルの番号として使います。
    ログ・ファイル番号は0開始です。
    ログ・ファイルはデフォルトでは1MBytesを超えると次のログ・ファイルへ切り替わります。その時、ログ・ファイル番号をインクリメントします。
    ただし、デフォルトでは最大2個までに制限していますので、ログ・ファイル番号1の次は0のログ・ファイルへ「上書き」します。
    これにより、ほっておいてもログ・ファイルが無限に増えることを防止しています。

  • ".log"は自由に指定して下さい。

5-2.ログ・ファイルのフォーマット

ログ・ファイルは後処理するのに便利のため簡易的なcsvフォーマットにしています。以下の通りです。

  • 先頭行
    シーケンシャル番号です。これはログ・ファイルを生成する度に1つ増えます。
    unsigned型で循環します。

  • 2行目以降
    ,年-月-日,時間:分:秒.mSec,同期待ち時間(uSec),スレッドID,ErrorType(ErrorKind),エラー検出インスタンス : エラー・メッセージ

ログ・ファイル例:

0
,2017-05-04,13:32:38.671,000001,___________12712,Error(UnknownData),IntrusiveBase2.mULongLong : Unmatch type.{core_serializer.cpp(1570)}
,2017-05-04,13:32:38.673,000000,___________12712,Error(UnknownData),IntrusiveBase2.mULongLong : Unmatch type.{core_serializer.cpp(1570)}
,2017-05-04,13:32:38.673,000000,___________12712,Error(WrongUsing),mIntrusiveBase2{test_serializer_base02.cpp(91)} : Unmatch type.
,2017-05-04,13:32:38.673,000000,___________12712,Error(UnknownData),IntrusiveBase2.mULongLong : Unmatch type.{core_serializer.cpp(1654)}
,2017-05-04,13:32:38.674,000000,___________12712,Error(UnknownData),IntrusiveBase2.mULongLong : Unmatch type.{core_serializer.cpp(1654)}
,2017-05-04,13:32:38.674,000000,___________12712,Error(WrongUsing),mIntrusiveBase2{test_serializer_base02.cpp(123)} : Unmatch type.

5-3.同期待ち時間について

エラー・ログ出力は、マルチ・スレッドに対応しています。
他のスレッドがエラー・ログ出力処理中に出力しようとした場合、後から出力する方は待たされます。
その待ち時間を uSec で記録します。

5-4.スレッドIDについて

当該ログを出力したスレッドIDをstd::this_thread::get_id()で獲得して記録します。


6.サンプル・ソース

サンプル・ソース(source/reference_and_test/basic/test_basic_process.cpp)

// ---<<< 例外許可 >>>---
try
{
std::ifstream aStream("tutorise_basic.json");
theolizer::JsonISerializer<> aSerializer(aStream);
int aInt;
THEOLIZER_PROCESS(aSerializer, aInt); // Type mismatch発生
}
{
std::cout << "exception : " << e.getString() << std::endl;
}
// ---<<< 例外禁止 >>>---
try
{
std::ifstream aStream("tutorise_basic.json");
theolizer::JsonISerializer<> aSerializer(aStream, true);
short ashort;
THEOLIZER_PROCESS(aSerializer, ashort); // Type mismatch発生
theolizer::ErrorInfo aErrorInfo=aSerializer.getErrorInfo();
if (aErrorInfo)
{
std::cout << "no-exception : " << aErrorInfo.getString() << std::endl;
aSerializer.resetError(); // エラー状態を解除する
}
}
{
std::cout << "exception : " << e.getString() << std::endl;
}

これの出力は以下のようになります。

exception : Error(UnknownData),aInt{test_basic_process.cpp(241)} : Logical Error on stream.
no-exception : Error(UnknownData),ashort{test_basic_process.cpp(256)} : Logical Error on stream.


7.エラー検出の網羅的テスト

7-1.エラー報告全体

テスト用のソース・コードは、source/test_library/reportフォルダに置いています。
下記の組合せでテストしています。

ソース・ファイルテスト内容
test_report1.cpp エラー・ログが適切に保存されること
エラー・ログ・ファイルの指定ミス
マルチ・スレッドに対応できていること
test_report1_child.cpp エラー・ログ・ファイル指定ミスのテスト用の子プロセス
test_report2.cpp THEOLIZER_ERRORLOG_FILE未指定
test_report3.cpp
test_report4.cpp
THEOLIZER_ERRORLOG_FILE多重登録
test_report4.cpp ErrorReproterのAPIテスト

7-2.downVersion/upVersionのコンパイル・エラー

プリミティブ型とenum型以外のメンバ変数への値設定が禁止できていることをテストしています。

ソース・コードは、source/reference_and_test/ver3b/test_modify_complex.hにて、ERROR1, ERROR2マクロが定義されている時にコンパイル・エラーになるように定義しています。そして、source/reference_and_test/CMakeLists.txtのver3bERROR1, ver3bERROR2にてコンパイル・エラーが発生することをチェックしています。

7-3.グローバル・バージョン番号テーブルのエラー検出

バージョン・アップに伴い、一度シリアライズ指定したクラスやenum型をソース・コードから完全に削除した場合に、グローバル・バージョン番号テーブルから手動で削除する必要があります。(3-4-4.クラスやenum型を削除する際の注意事項 参照。)
その削除を忘れた場合にコンパイル・エラーになることを確認しています。

ソース・コードは、source/reference_and_test/ver3b/test_modify_complex.hにて、ERROR3マクロが定義されている時にコンパイル・エラーになるように定義しています。そして、source/reference_and_test/CMakeLists.txtのver3bERROR3にてコンパイル・エラーが発生することをチェックしています。

7-4.エラー・リカバリ

デシリアライズ中のエラー発生後にリカバリするテストを行っています。 Json, BinaryシリアライザのNoTypCheck, TypeCheck, TypeCheckByIndexについて、現バージョンと1つ前のバージョンからの回復についてリカバリできることを確認しています。

ソース・コードは、source/reference_and_test/ver2a/test_modify_complex.cppのtutoriseModifyComplex()関数です。