Asakusa FrameworkのOperator DSLのロギング演算子(Logging)のメモ。
|
|
ロギング演算子は、ログを出力する演算子。
性能特性はExtract(旧ドキュメントではMap)。[/2016-02-11]
入力 ポート数 |
入力データモデル の制約 |
イメージ | 出力 ポート数 |
出力データモデル の制約 |
入力1レコード に対する 出力レコード数 |
---|---|---|---|---|---|
1 |
![]() |
1 | inと同じ データモデル |
1レコード。 |
ロギング演算子の実装としてログメッセージを返すようにする。
すると、レコード毎にログメッセージが出力される。
ログレベルは以下のものが指定できる。
ロギング演算子はレポートAPIを使ってログ出力しているので、ログの出力先はレポートAPIと同じ。
処理対象の全レコードに対してログ出力するとさすがにログの量が多くなって遅くなりそうなので、ある程度絞ったデータに対してロギング演算子を適用させるべきだろう。
なお、ロギング演算子は特別で、出力をどこにも接続しない場合は自動的に停止演算子(stop)に接続される。とJavadocに書いてある。
AsakusaFW 0.5.1では(テストドライバーに限るが)トレース機能が追加された。
これは、演算子のポートを指定して、そのポートで入出力されるデータモデルの全プロパティーをログ出力するもの。
どのポートでログ出力するのかは(テストドライバーの)実行時に指定するので、Flow DSL本体には手を入れる必要がないのが優れている。
(ロギング演算子の場合は、出力をやめようと思ったらFlow DSLを修正してロギング演算子を取り除かないといけない)
ロギング演算子のコーディング例。
(この図はToad Editorを用いて作っています)
hoge = { value : INT; };
import java.text.MessageFormat; import com.asakusafw.vocabulary.operator.Logging; import com.example.modelgen.dmdl.model.Hoge;
public abstract class ExampleOperator { /** * エラー値を出力する。 * * @param in * データ * @return ログメッセージ */ @Logging(Logging.Level.ERROR) public String error(Hoge in) { return MessageFormat.format("hoge.value = {0}", in.getValueOption()); } }
データモデルを引数に取り、ログメッセージを返すようにする。
@Loggingアノテーションの引数にはログレベルを指定する。
「@Logging(value = Logging.Level.ERROR)
」という書き方も可。
ログレベルを指定しなかった場合はINFOになる。
import com.example.modelgen.dmdl.model.Hoge; import com.example.operator.ExampleOperatorFactory; import com.example.operator.ExampleOperatorFactory.Error;
private final In<Hoge> in; private final Out<Hoge> out;
@Override public void describe() { ExampleOperatorFactory operators = new ExampleOperatorFactory(); // エラー値を出力する Error err = operators.error(this.in); this.out.add(err.out); }
Flow DSLでは、自分が作ったOperatorのFactoryクラス(AsakusaFWのコンパイラーによって生成される)を使用する。
メソッド名はOperatorクラスに書いたメソッド名と同じ。
戻り値の型はAsakusaFWのコンパイラーによって生成されたクラス。(メソッド名を先頭が大文字のキャメルケースに変換したもの)
出力ポートの名前のデフォルトはout。
出力ポート名を変えたい場合は@Loggingアノテーションで指定できる。
この場合、ログレベルは「value =」を使って指定する。@Logging(value = Logging.Level.ERROR, outputPort = "out")
ロギング演算子の単体テストの実装例。
package com.example.operator;
import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; import org.junit.Test; import com.example.modelgen.dmdl.model.Hoge;
/** * {@link ExampleOperator}のテスト. */ public class ExampleOperatorTest { @Test public void error() { ExampleOperator operator = new ExampleOperatorImpl(); Hoge hoge = new Hoge(); hoge.setValue(123); String message = operator.error(hoge); assertThat(message, is("hoge.value = 123")); } }
Operatorのテストクラスは、通常のJavaのJUnitのテストケースクラスとして作成する。
テスト対象のOperatorクラス自身は抽象クラスだが、Operatorクラス名の末尾に「Impl」の付いた具象クラスがAsakusaFWによって生成されるので、それを使う。
ロギング演算子では、入力のデータモデルの他にも引数を指定することが出来る。
こうすると、引数の内容分だけ異なる同じ演算子(処理内容)をいくつかの場所で使用できるようになる。
先の例に値引数を追加する例。
@Logging(Logging.Level.ERROR) public String error(Hoge in, String title) { return MessageFormat.format("{0}: hoge.value = {1}", title, in.getValueOption()); }
出力ポートを示す引数以降を通常のJavaメソッドと同様に自由な引数とすることが出来る。(ただしプリミティブのみ)
import com.example.modelgen.dmdl.model.Hoge; import com.example.operator.ExampleOperatorFactory; import com.example.operator.ExampleOperatorFactory.Error;
private final In<Hoge> in; private final Out<Hoge> out;
@Override
public void describe() {
ExampleOperatorFactory operators = new ExampleOperatorFactory();
// エラー値を出力する
Error err = operators.error(this.in, "エラー出力");
this.out.add(err.out);
}
演算子を使用するFlow DSLで、引数に具体的な値を指定する。
@Test public void error() { ExampleOperator operator = new ExampleOperatorImpl(); Hoge hoge = new Hoge(); hoge.setValue(123); String title = "タイトル"; String message = operator.error(hoge, title); assertThat(message, is("タイトル: hoge.value = 123")); }
AsakusaFW 0.10.3以降では、型引数を指定すると、全データモデルを受け取るロギング演算子を作れる。[2019-06-14]
@Logging public <T> String log(T in) { return in.toString(); }
実はAsakusaFWのドキュメントには以前から「例えば上限境界の無い型引数を定義して、引数の型として利用すると、
すべてのデータを受け取れるようなロギング演算子を定義することができます」と書かれていたのだが、実際には出来なかった(バグだった)らしい。
AsakusaFW 0.10.3で書けるようになった。