Apach CamelのMessage Historyパターンで、メッセージのフローを確認する

# はじめに

今回紹介するMessage Historyパターンは、Eneterprise Integration Patternsの1つになります。

Camelではコンポーネントやプロセッサー間はメッセージを介しており疎結合になっています。
そのため、具体的にメッセージがどのようなフローでルートを通ってきたかが分からなくなります。
Message Historyパターンではメッセージに履歴（足跡みたいなもの）をつけていくことで、デバッグや解析に役立てることができます。

![MessageHistory.gif](https://qiita-image-store.s3.amazonaws.com/0/179607/4aabee5d-5ef1-dada-8362-8b9debaeb1f5.gif)

画像の出典：[Enterprise Integration Patterns - Message History](https://www.enterpriseintegrationpatterns.com/patterns/messaging/MessageHistory.html)


# 例外発生時のMessage History

Camelで開発していてMessage Historyを見る機会の代表例は例外発生時です。
CamelではMessage Historyパターンが自動で適用され、例外発生時にデフォルトでMessage Historyが表示されるようになっています。

以下のXMLはルートの途中で強制的にRuntimeExceptionを発生させています。

```xml
		<route>
			<from uri="timer:trigges?repeatCount=1" />
			<to uri="direct:a" />
			<to uri="direct:b" />
			<log message="body: ${body}" />
		</route>
		<route>
			<from uri="direct:a" />
			<log message="route a" />
		</route>
		<route>
			<from uri="direct:b" />
			<throwException exceptionType="java.lang.RuntimeException" message="test exception" />
			<log message="route b" />
		</route>
```

このルートを実行すると以下のログが出力されます。
"Message History"の文字列以下がMessage Historyの表示です。
メッセージが通った順番にRoute Id, Processor Id, Processorと実行時間（Elapsed）が表示されています。また、今回は例外のため、Exchange中のStackTraceの情報も表示されています。

```
[2019-02-14 22:15:52.294], [ERROR], o.a.c.p.DefaultErrorHandler, Camel (camel-1) thread #1 - timer://trigges, org.apache.camel.processor.DefaultErrorHandler, Failed delivery for (MessageId: ID-mky-PC-1550150150431-0-2 on ExchangeId: ID-mky-PC-1550150150431-0-1). Exhausted after delivery attempt: 1 caught: java.lang.RuntimeException: test exception

Message History
---------------------------------------------------------------------------------------------------------------------------------------
RouteId              ProcessorId          Processor                                                                        Elapsed (ms)
[route1            ] [route1            ] [timer://trigges?repeatCount=1                                                 ] [        16]
[route1            ] [to1               ] [direct:a                                                                      ] [         8]
[route2            ] [log2              ] [log                                                                           ] [         5]
[route1            ] [to2               ] [direct:b                                                                      ] [         0]
[route3            ] [throwException1   ] [throwException[ref:null]                                                      ] [         1]

Stacktrace
---------------------------------------------------------------------------------------------------------------------------------------
java.lang.RuntimeException: test exception
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:1.8.0_172]
～省略～
```


# XML DSLでMessage Historyを表示する

最初の例は例外発生時にMessage Historyを表示させることを確認しましたが、明示的にMessage Historyを表示させるやり方を見ていきましょう。

XML DSLでMessage Historyを明示的に表示するには、messageHistoryプロパティを使用します。
messageHistoryプロパティを使用したルートの例は以下のようになります。

```xml
		<route>
			<from uri="timer:trigges?repeatCount=1" />
			<to uri="direct:a" />
			<to uri="direct:b" />
			<log message="body: ${body}" />
		</route>
		<route>
			<from uri="direct:a" />
			<log message="route a" />
		</route>
		<route>
			<from uri="direct:b" />
			<log message="${messageHistory}" />
			<log message="route b" />
		</route>
```

このルートを実行すると以下のようにMessage Historyが表示されます。
例外発生時のMessage Historyとほぼ同じ内容ですが、今回は例外ではないためStackTraceは表示されません。

```
Message History
---------------------------------------------------------------------------------------------------------------------------------------
RouteId              ProcessorId          Processor                                                                        Elapsed (ms)
[route1            ] [route1            ] [timer://trigges?repeatCount=1                                                 ] [        14]
[route1            ] [to1               ] [direct:a                                                                      ] [         7]
[route2            ] [log2              ] [log                                                                           ] [         4]
[route1            ] [to2               ] [direct:b                                                                      ] [         0]
[route3            ] [log3              ] [log                                                                           ] [         0]

Exchange
---------------------------------------------------------------------------------------------------------------------------------------
Exchange[
	Id                  ID-mky-PC-1550150269136-0-1
	ExchangePattern     InOnly
	Headers             {breadcrumbId=ID-mky-PC-1550150269136-0-1, firedTime=Thu Feb 14 22:17:50 JST 2019}
	BodyType            null
	Body                [Body is null]
```


# Java DSLでMessage Historyを表示する

次にJava DSLでも明示的にMessage Historyを表示してみます。
こちらもmessageHistoryプロパティを使用するだけです。出力されるMessage HistoryはXML DSLと同じであるため省略します。


```java
					from("timer:trigger?repeatCount=1")
						.to("direct:a")
						.to("direct:b")
						.log("Body-before: ${body}")
						.log("Body-after: ${body}");
					from("direct:a")
						.log("route a");
					from("direct:b")
						.log("${messageHistory}")
						.log("route b");
```


# プロセッサ中でMessage Historyを表示する

プロセッサ中でMessage Historyを出力するには、MessageHelperクラスのdumpMessageHistoryStacktraceメソッドを使用します。dumpMessageHistoryStacktraceメソッドを使用することで整形された文字列でMessage Historyを取得することができます。

以下はプロセッサーのprocessメソッドでdumpMessageHistoryStacktraceメソッドを使用して、Message Historyを標準出力に表示した例になります。

```java
			    public void process(Exchange exchange) {
			    	String msgHist = MessageHelper.dumpMessageHistoryStacktrace(exchange, new DefaultExchangeFormatter(), false);
					System.out.println(msgHist);
			    }
```

dumpMessageHistoryStacktraceメソッドの3番目の引数はStackTraceを表示するかどうかのフラグです。
trueにしておくと例外発生時にStackTraceが一緒に表示されるようになります。この例中では"false"に設定しています。


# 参考

- [Message History（公式サイト）](http://camel.apache.org/message-history.html)