ApplicationInsights.xml用のJVMパフォーマンスカウンタ設定

誰もまとめてくれていなかったので`ManagementFactory.getPlatformMBeanServer()`を叩いて作りました。とりあえずCPU、メモリ、GC回数・時間周りを取ってます。

ApplicationInsightsでパフォーマンスカウンタの収集を想定しているJVMアプリケーションを作る場合に使えるんじゃないでしょうか。

GCオプションでPS/CMS/G1のいずれかになるので、その取り分けを行っています。
ただ、今のところ、存在しないカウンタは場合は収集されないようなので、この設定のまま放り込んでもよいと思います。

displayNameはAnalyticsで検索するときの名前になるので、適当に書き換えてよい


``` xml
<?xml version="1.0" encoding="utf-8"?>
<ApplicationInsights
	xmlns="http://schemas.microsoft.com/ApplicationInsights/2013/Settings">
	<PerformanceCounters>
		<UseBuiltIn>False</UseBuiltIn>
		<Jmx>
			<!-- CPU -->
			<Add objectName="java.lang:type=OperatingSystem"
				attribute="ProcessCpuLoad" displayName="CPU Process Load" />
			<Add objectName="java.lang:type=OperatingSystem"
				attribute="SystemCpuLoad" displayName="CPU System Load" />
			<!-- Thread -->
			<Add objectName="java.lang:type=Threading" attribute="ThreadCount"
				displayName="Thread Count" />

			<!-- Memory -->
			<Add objectName="java.lang:type=Memory" attribute="HeapMemoryUsage.used"
				displayName="MEM Heap Used" type="composite" />
			<Add objectName="java.lang:type=Memory" attribute="HeapMemoryUsage.committed"
				displayName="MEM Heap Committed" type="composite" />

			<Add objectName="java.lang:type=Memory" attribute="NonHeapMemoryUsage.used"
				displayName="MEM Non Heap Used" type="composite" />
			<Add objectName="java.lang:type=Memory" attribute="NonHeapMemoryUsage.committed"
				displayName="MEM Non Heap Committed" type="composite" />

			<!-- Memory(Metaspace) JVM 8 over -->
			<Add objectName="java.lang:type=MemoryPool,name=Metaspace" attribute="Usage.used"
				displayName="MEM Metaspace Used" type="composite" />
			<Add objectName="java.lang:type=MemoryPool,name=Metaspace" attribute="Usage.committed"
				displayName="MEM Metaspace Committed" type="composite" />

			<!-- Memory(PS) -->
			<!-- Not works... -->
			<Add objectName="java.lang:type=MemoryPool,name=PS Eden Space" attribute="Usage.used"
				displayName="MEM(PS) New Used" type="composite" />
			<Add objectName="java.lang:type=MemoryPool,name=PS Eden Space" attribute="Usage.committed"
				displayName="MEM(PS) New Committed" type="composite" />
			<Add objectName="java.lang:type=MemoryPool,name=PS Survivor Space" attribute="Usage.used"
				displayName="MEM(PS) Survivor Used" type="composite" />
			<Add objectName="java.lang:type=MemoryPool,name=PS Survivor Space" attribute="Usage.committed"
				displayName="MEM(PS) Survivor Committed" type="composite" />
			<Add objectName="java.lang:type=MemoryPool,name=PS Old Gen" attribute="Usage.used"
				displayName="MEM(PS) Old Used" type="composite" />
			<Add objectName="java.lang:type=MemoryPool,name=PS Old Gen" attribute="Usage.committed"
				displayName="MEM(PS) Old Committed" type="composite" />
			<!-- GC(PS) -->
			<Add objectName="java.lang:type=GarbageCollector,name=PS MarkSweep"
				attribute="CollectionCount" displayName="FGC - Count" />
			<Add objectName="java.lang:type=GarbageCollector,name=PS MarkSweep"
				attribute="CollectionTime" displayName="FGC - Time" />
			<Add objectName="java.lang:type=GarbageCollector,name=PS Scavenge"
				attribute="CollectionTime" displayName="YGC - Time" />
			<Add objectName="java.lang:type=GarbageCollector,name=PS Scavenge"
				attribute="CollectionCount" displayName="YGC - Count" />

			<!-- Memory(CMS) -XX:+UseConcMarkSweepGC -->
			<Add objectName="java.lang:type=MemoryPool,name=Par Eden Space" attribute="Usage.used"
				displayName="MEM(CMS) New Used" type="composite" />
			<Add objectName="java.lang:type=MemoryPool,name=Par Eden Space" attribute="Usage.committed"
				displayName="MEM(CMS) New Committed" type="composite" />
			<Add objectName="java.lang:type=MemoryPool,name=Par Survivor Space" attribute="Usage.used"
				displayName="MEM(CMS) Survivor Used" type="composite" />
			<Add objectName="java.lang:type=MemoryPool,name=Par Survivor Space" attribute="Usage.committed"
				displayName="MEM(CMS) Survivor Committed" type="composite" />
			<Add objectName="java.lang:type=MemoryPool,name=CMS Old Gen" attribute="Usage.used"
				displayName="MEM(CMS) Old Used" type="composite" />
			<Add objectName="java.lang:type=MemoryPool,name=CMS Old Gen" attribute="Usage.committed"
				displayName="MEM(CMS) Old Committed" type="composite" />
			<!-- GC(CMS) -->
			<Add objectName="java.lang:type=GarbageCollector,name=ConcurrentMarkSweep"
				attribute="CollectionCount" displayName="FGC(CMS) Count" />
			<Add objectName="java.lang:type=GarbageCollector,name=ConcurrentMarkSweep"
				attribute="CollectionTime" displayName="FGC(CMS) Time" />
			<Add objectName="java.lang:type=GarbageCollector,name=ParNew"
				attribute="CollectionTime" displayName="YGC(CMS) Time" />
			<Add objectName="java.lang:type=GarbageCollector,name=ParNew"
				attribute="CollectionCount" displayName="YGC(CMS) Count" />

			<!-- Memory(G1GC) -XX:+UseG1GC -->
			<Add objectName="java.lang:type=MemoryPool,name=G1 Eden Space" attribute="Usage.used"
				displayName="MEM(G1) New Used" type="composite" />
			<Add objectName="java.lang:type=MemoryPool,name=G1 Eden Space" attribute="Usage.committed"
				displayName="MEM(G1) New Committed" type="composite" />
			<Add objectName="java.lang:type=MemoryPool,name=G1 Survivor Space" attribute="Usage.used"
				displayName="MEM(G1) Survivor Used" type="composite" />
			<Add objectName="java.lang:type=MemoryPool,name=G1 Survivor Space" attribute="Usage.committed"
				displayName="MEM(G1) Survivor Committed" type="composite" />
			<Add objectName="java.lang:type=MemoryPool,name=G1 Old Gen" attribute="Usage.used"
				displayName="MEM(G1) Old Used" type="composite" />
			<Add objectName="java.lang:type=MemoryPool,name=G1 Old Gen" attribute="Usage.committed"
				displayName="MEM(G1) Old Committed" type="composite" />
			<!-- GC(G1GC) -->
			<Add objectName="java.lang:type=GarbageCollector,name=G1 Young Generation"
				attribute="CollectionCount" displayName="YGC(G1) Count" />
			<Add objectName="java.lang:type=GarbageCollector,name=G1 Young Generation"
				attribute="CollectionTime" displayName="YGC(G1) Time" />
			<Add objectName="java.lang:type=GarbageCollector,name=G1 Old Generation"
				attribute="CollectionTime" displayName="FGC(G1) Time" />
			<Add objectName="java.lang:type=GarbageCollector,name=G1 Old Generation"
				attribute="CollectionCount" displayName="FGC(G1) Count" />
		</Jmx>
	</PerformanceCounters>
</ApplicationInsights>
```


(2019/07/09 追記)

ちなみに、XML中のuseBuiltInをFalseにすると[この辺りのメトリック](https://github.com/microsoft/ApplicationInsights-Java/search?q=PerformanceModule)で`BuiltIn`がついているものを取らなくなります。([処理箇所](https://github.com/microsoft/ApplicationInsights-Java/blob/v2.3.1/core/src/main/java/com/microsoft/applicationinsights/internal/config/TelemetryConfigurationFactory.java#L364))

XMLの細かい設定については以下が良いでしょう。デフォルトで60秒間隔なのでもっと短くしたい場合などは設定を書く必要があります。

https://github.com/microsoft/ApplicationInsights-Java/wiki/ApplicationInsights.XML


また、`java.lang:type=GarbageCollector,name=PS MarkSweep`など一部の値は取得できません。以下のIssueの通りです。
[Cannot fetch jmx counter for GC with Java SDK agent #952](https://github.com/microsoft/ApplicationInsights-Java/issues/952)

(追記ここまで)


上の一覧を作るために`ManagementFactory.getPlatformMBeanServer()`を叩いてた時のコード

``` java
import java.lang.management.ManagementFactory;
import java.util.Set;

import javax.management.Attribute;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.ReflectionException;

public class Test {

	public static void main(String[] s)
			throws ReflectionException, IntrospectionException, InstanceNotFoundException, AttributeNotFoundException,
			MBeanException {
		MBeanServer server = ManagementFactory.getPlatformMBeanServer();
		Set<ObjectName> names = server.queryNames(null, null);
		for (ObjectName name : names) {
			System.out.println(name);

			MBeanInfo beanInfo = server.getMBeanInfo(name);
			for (MBeanAttributeInfo attrInfo : beanInfo.getAttributes()) {
				try {
					Object attrObject = server.getAttribute(name, attrInfo.getName());
					if (attrObject instanceof Attribute) {
						Attribute attr = (Attribute) attrObject;
						Object attrValueObject = ((Attribute) attrObject).getValue();
						System.out.printf("  attribute: %s = %s\n", attrInfo.getName(), attrValueObject);
					} else {
						System.out.printf("  attribute: %s = %s\n", attrInfo.getName(), attrObject);
					}
				} catch (Exception e) {
					System.out.printf("  attribute: %s = %s\n", attrInfo.getName(), "???");
				}
			}
		}
	}
}

```


compositeな属性はcontentsのkey-valueで取る感じになる。（キー値の取り方がわからなかったが、toStringで見える）
例えばメモリとかがそうで、以下のような出力になる。

```
java.lang:type=MemoryPool,name=Metaspace
  ～中略～
  attribute: Usage = javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=java.lang.management.MemoryUsage,items=((itemName=committed,itemType=javax.management.openmbean.SimpleType(name=java.lang.Long)),(itemName=init,itemType=javax.management.openmbean.SimpleType(name=java.lang.Long)),(itemName=max,itemType=javax.management.openmbean.SimpleType(name=java.lang.Long)),(itemName=used,itemType=javax.management.openmbean.SimpleType(name=java.lang.Long)))),contents={committed=6029312, init=0, max=-1, used=5663360})
```

一番後ろの方にcontentsが見える。

この場合、JMX的にはAttribute名が"Usage"でcontentsに"used"だが、ApplicationInsightsのXMLに書くときはattributeに`Usage.used`として、`type="composite"`属性も付与する感じになる。