diff --git a/apm-network/src/main/proto/JVMMetricsService.proto b/apm-network/src/main/proto/JVMMetricsService.proto index 4db326e68bb47fab66f4bc5389e4a26929bfe834..6e5973efbb83ff7e15d8cc178fb1113487d17640 100644 --- a/apm-network/src/main/proto/JVMMetricsService.proto +++ b/apm-network/src/main/proto/JVMMetricsService.proto @@ -24,7 +24,6 @@ message JVMMetric { } message CPU { - int64 time = 1; double usagePercent = 2; } @@ -37,8 +36,8 @@ message Memory { } message MemoryPool { - bool isHeap = 1; - PoolType type = 2; + PoolType type = 1; + bool isHeap = 2; int64 init = 3; int64 max = 4; int64 used = 5; diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/JVMService.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/JVMService.java new file mode 100644 index 0000000000000000000000000000000000000000..3fb217ee8786b38f589c096d4e6951300c4276cf --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/JVMService.java @@ -0,0 +1,53 @@ +package org.skywalking.apm.agent.core.jvm; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import org.skywalking.apm.agent.core.boot.BootService; +import org.skywalking.apm.agent.core.jvm.cpu.CPUProvider; +import org.skywalking.apm.agent.core.jvm.memory.MemoryProvider; +import org.skywalking.apm.agent.core.jvm.memorypool.MemoryPoolProvider; +import org.skywalking.apm.network.proto.JVMMetric; + +/** + * @author wusheng + */ +public class JVMService implements BootService, Runnable { + private SimpleDateFormat sdf = new SimpleDateFormat("ss"); + private volatile ScheduledFuture scheduledFuture; + + @Override + public void beforeBoot() throws Throwable { + + } + + @Override + public void boot() throws Throwable { + ScheduledExecutorService service = Executors + .newSingleThreadScheduledExecutor(); + scheduledFuture = service.scheduleAtFixedRate(this, 0, 1, TimeUnit.SECONDS); + } + + @Override + public void afterBoot() throws Throwable { + + } + + @Override + public void run() { + long currentTimeMillis = System.currentTimeMillis(); + Date day = new Date(currentTimeMillis); + String second = sdf.format(day); + + if (Integer.parseInt(second) % 15 == 0) { + JVMMetric.Builder JVMBuilder = JVMMetric.newBuilder(); + JVMBuilder.setTime(currentTimeMillis); + JVMBuilder.setCpu(CPUProvider.INSTANCE.getCpuMetric()); + JVMBuilder.addAllMemory(MemoryProvider.INSTANCE.getMemoryMetricList()); + JVMBuilder.addAllMemoryPool(MemoryPoolProvider.INSTANCE.getMemoryPoolMetricList()); + } + } +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/cpu/CPUMetricAccessor.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/cpu/CPUMetricAccessor.java new file mode 100644 index 0000000000000000000000000000000000000000..e0dc1a6fbaeea8097fa85defd4d9f78a8df8b581 --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/cpu/CPUMetricAccessor.java @@ -0,0 +1,32 @@ +package org.skywalking.apm.agent.core.jvm.cpu; + +import org.skywalking.apm.network.proto.CPU; + +/** + * @author wusheng + */ +public abstract class CPUMetricAccessor { + private long lastCPUTimeNs; + private long lastSampleTimeNs; + private final int cpuCoreNum; + + public CPUMetricAccessor(int cpuCoreNum) { + this.cpuCoreNum = cpuCoreNum; + } + + protected void init() { + lastCPUTimeNs = this.getCpuTime(); + this.lastSampleTimeNs = System.nanoTime(); + } + + protected abstract long getCpuTime(); + + public CPU getCPUMetric() { + long cpuTime = this.getCpuTime(); + long cpuCost = cpuTime - lastCPUTimeNs; + long now = System.nanoTime(); + + CPU.Builder cpuBuilder = CPU.newBuilder(); + return cpuBuilder.setUsagePercent(cpuCost * 1.0d / (now - lastSampleTimeNs) * cpuCoreNum).build(); + } +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/cpu/CPUProvider.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/cpu/CPUProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..781016ad786d53122c97787b4e690c6ce82eee12 --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/cpu/CPUProvider.java @@ -0,0 +1,30 @@ +package org.skywalking.apm.agent.core.jvm.cpu; + +import org.skywalking.apm.agent.core.os.ProcessorUtil; +import org.skywalking.apm.logging.ILog; +import org.skywalking.apm.logging.LogManager; +import org.skywalking.apm.network.proto.CPU; + +/** + * @author wusheng + */ +public enum CPUProvider { + INSTANCE; + private CPUMetricAccessor cpuMetricAccessor; + + CPUProvider() { + int processorNum = ProcessorUtil.getNumberOfProcessors(); + try { + CPUProvider.class.getClassLoader().loadClass("com.sun.management.OperatingSystemMXBean"); + this.cpuMetricAccessor = new SunCpuAccessor(processorNum); + } catch (Exception e) { + this.cpuMetricAccessor = new NoSupportedCPUAccessor(processorNum); + ILog logger = LogManager.getLogger(CPUProvider.class); + logger.error(e, "Only support accessing CPU metric in SUN JVM platform."); + } + } + + public CPU getCpuMetric() { + return cpuMetricAccessor.getCPUMetric(); + } +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/cpu/NoSupportedCPUAccessor.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/cpu/NoSupportedCPUAccessor.java new file mode 100644 index 0000000000000000000000000000000000000000..d04ed95df80970228ed0b1c91b88293d5f8972a0 --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/cpu/NoSupportedCPUAccessor.java @@ -0,0 +1,15 @@ +package org.skywalking.apm.agent.core.jvm.cpu; + +/** + * @author wusheng + */ +public class NoSupportedCPUAccessor extends CPUMetricAccessor { + public NoSupportedCPUAccessor(int cpuCoreNum) { + super(cpuCoreNum); + } + + @Override + protected long getCpuTime() { + return 0; + } +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/cpu/SunCpuAccessor.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/cpu/SunCpuAccessor.java new file mode 100644 index 0000000000000000000000000000000000000000..42e9a8512e2c22424aaa51c64ed6cc463e1226d6 --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/cpu/SunCpuAccessor.java @@ -0,0 +1,22 @@ +package org.skywalking.apm.agent.core.jvm.cpu; + +import com.sun.management.OperatingSystemMXBean; +import java.lang.management.ManagementFactory; + +/** + * @author wusheng + */ +public class SunCpuAccessor extends CPUMetricAccessor { + private final OperatingSystemMXBean osMBean; + + public SunCpuAccessor(int cpuCoreNum) { + super(cpuCoreNum); + this.osMBean = (OperatingSystemMXBean)ManagementFactory.getOperatingSystemMXBean(); + this.init(); + } + + @Override + protected long getCpuTime() { + return osMBean.getProcessCpuTime(); + } +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/memory/MemoryProvider.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/memory/MemoryProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..4cf6d8e71d508d19b796179a8796f0d9c81caebc --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/memory/MemoryProvider.java @@ -0,0 +1,45 @@ +package org.skywalking.apm.agent.core.jvm.memory; + +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryMXBean; +import java.lang.management.MemoryUsage; +import java.util.LinkedList; +import java.util.List; +import org.skywalking.apm.network.proto.Memory; + +/** + * @author wusheng + */ +public enum MemoryProvider { + INSTANCE; + private final MemoryMXBean memoryMXBean; + + MemoryProvider() { + this.memoryMXBean = ManagementFactory.getMemoryMXBean(); + } + + public List getMemoryMetricList() { + List memoryList = new LinkedList(); + + MemoryUsage heapMemoryUsage = memoryMXBean.getHeapMemoryUsage(); + Memory.Builder heapMemoryBuilder = Memory.newBuilder(); + heapMemoryBuilder.setIsHeap(true); + heapMemoryBuilder.setInit(heapMemoryUsage.getInit()); + heapMemoryBuilder.setUsed(heapMemoryUsage.getUsed()); + heapMemoryBuilder.setCommitted(heapMemoryUsage.getCommitted()); + heapMemoryBuilder.setMax(heapMemoryUsage.getMax()); + memoryList.add(heapMemoryBuilder.build()); + + MemoryUsage nonHeapMemoryUsage = memoryMXBean.getNonHeapMemoryUsage(); + Memory.Builder nonHeapMemoryBuilder = Memory.newBuilder(); + nonHeapMemoryBuilder.setIsHeap(false); + nonHeapMemoryBuilder.setInit(nonHeapMemoryUsage.getInit()); + nonHeapMemoryBuilder.setUsed(nonHeapMemoryUsage.getUsed()); + nonHeapMemoryBuilder.setCommitted(nonHeapMemoryUsage.getCommitted()); + nonHeapMemoryBuilder.setMax(nonHeapMemoryUsage.getMax()); + memoryList.add(nonHeapMemoryBuilder.build()); + + return memoryList; + } + +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/memorypool/CMSCollectorModule.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/memorypool/CMSCollectorModule.java new file mode 100644 index 0000000000000000000000000000000000000000..7d4d2e3535d6e85cc142e05e9de04f4295fe31dd --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/memorypool/CMSCollectorModule.java @@ -0,0 +1,37 @@ +package org.skywalking.apm.agent.core.jvm.memorypool; + +import java.lang.management.MemoryPoolMXBean; +import java.util.List; + +/** + * @author wusheng + */ +public class CMSCollectorModule extends MemoryPoolModule { + public CMSCollectorModule(List beans) { + super(beans); + } + + @Override protected String getPermName() { + return "Perm Gen"; + } + + @Override protected String getCodeCacheName() { + return "Code Cache"; + } + + @Override protected String getEdenName() { + return "Eden Space"; + } + + @Override protected String getOldName() { + return "Tenured Gen"; + } + + @Override protected String getSurvivorName() { + return "Survivor Space"; + } + + @Override protected String getMetaspaceName() { + return "Metaspace"; + } +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/memorypool/MemoryPoolMetricAccessor.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/memorypool/MemoryPoolMetricAccessor.java new file mode 100644 index 0000000000000000000000000000000000000000..ba9e5f1ee3abe0140f793e590af4769b6731da82 --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/memorypool/MemoryPoolMetricAccessor.java @@ -0,0 +1,11 @@ +package org.skywalking.apm.agent.core.jvm.memorypool; + +import java.util.List; +import org.skywalking.apm.network.proto.MemoryPool; + +/** + * @author wusheng + */ +public interface MemoryPoolMetricAccessor { + List getMemoryPoolMetricList(); +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/memorypool/MemoryPoolModule.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/memorypool/MemoryPoolModule.java new file mode 100644 index 0000000000000000000000000000000000000000..5e1ccf258b7f21e033810db41f6ef0645f690998 --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/memorypool/MemoryPoolModule.java @@ -0,0 +1,64 @@ +package org.skywalking.apm.agent.core.jvm.memorypool; + +import java.lang.management.MemoryPoolMXBean; +import java.lang.management.MemoryUsage; +import java.util.LinkedList; +import java.util.List; +import org.skywalking.apm.network.proto.MemoryPool; +import org.skywalking.apm.network.proto.PoolType; + +/** + * @author wusheng + */ +public abstract class MemoryPoolModule implements MemoryPoolMetricAccessor { + private List beans; + + public MemoryPoolModule(List beans) { + this.beans = beans; + } + + @Override + public List getMemoryPoolMetricList() { + List poolList = new LinkedList(); + for (MemoryPoolMXBean bean : beans) { + String name = bean.getName(); + PoolType type = null; + if (name.equals(getCodeCacheName())) { + type = PoolType.CODE_CACHE_USAGE; + } else if (name.equals(getEdenName())) { + type = PoolType.NEWGEN_USAGE; + } else if (name.equals(getOldName())) { + type = PoolType.OLDGEN_USAGE; + } else if (name.equals(getSurvivorName())) { + type = PoolType.SURVIVOR_USAGE; + } else if (name.equals(getMetaspaceName())) { + type = PoolType.METASPACE_USAGE; + } else if (name.equals(getPermName())) { + type = PoolType.PERMGEN_USAGE; + } + + if (type != null) { + MemoryUsage usage = bean.getUsage(); + poolList.add(MemoryPool.newBuilder().setType(type) + .setInit(usage.getInit()) + .setMax(usage.getMax()) + .setCommited(usage.getCommitted()) + .setUsed(usage.getUsed()) + .build()); + } + } + return poolList; + } + + protected abstract String getPermName(); + + protected abstract String getCodeCacheName(); + + protected abstract String getEdenName(); + + protected abstract String getOldName(); + + protected abstract String getSurvivorName(); + + protected abstract String getMetaspaceName(); +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/memorypool/MemoryPoolProvider.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/memorypool/MemoryPoolProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..1e8ef532d850e8f62c1038e67ccdb3394ce7a277 --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/memorypool/MemoryPoolProvider.java @@ -0,0 +1,54 @@ +package org.skywalking.apm.agent.core.jvm.memorypool; + +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryPoolMXBean; +import java.util.List; +import org.skywalking.apm.network.proto.MemoryPool; + +/** + * @author wusheng + */ +public enum MemoryPoolProvider { + INSTANCE; + + private MemoryPoolMetricAccessor metricAccessor; + private List beans; + + MemoryPoolProvider() { + beans = ManagementFactory.getMemoryPoolMXBeans(); + for (MemoryPoolMXBean bean : beans) { + String name = bean.getName(); + MemoryPoolMetricAccessor accessor = findByBeanName(name); + if (accessor != null) { + metricAccessor = accessor; + break; + } + } + if (metricAccessor == null) { + metricAccessor = new UnknownMemoryPool(); + } + } + + public List getMemoryPoolMetricList() { + return metricAccessor.getMemoryPoolMetricList(); + } + + private MemoryPoolMetricAccessor findByBeanName(String name) { + if (name.indexOf("PS") > -1) { + //Parallel (Old) collector ( -XX:+UseParallelOldGC ) + return new ParallelCollectorModule(beans); + } else if (name.indexOf("CMS") > -1) { + // CMS collector ( -XX:+UseConcMarkSweepGC ) + return new CMSCollectorModule(beans); + } else if (name.indexOf("G1") > -1) { + // G1 collector ( -XX:+UseG1GC ) + return null; + } else if (name.indexOf("Survivor Space") > -1) { + // Serial collector ( -XX:+UseSerialGC ) + return null; + } else { + // Unknown + return null; + } + } +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/memorypool/ParallelCollectorModule.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/memorypool/ParallelCollectorModule.java new file mode 100644 index 0000000000000000000000000000000000000000..d2c6fda63264abcfeba63687fce58f11547a6cef --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/memorypool/ParallelCollectorModule.java @@ -0,0 +1,38 @@ +package org.skywalking.apm.agent.core.jvm.memorypool; + +import java.lang.management.MemoryPoolMXBean; +import java.util.List; + +/** + * @author wusheng + */ +public class ParallelCollectorModule extends MemoryPoolModule{ + + public ParallelCollectorModule(List beans) { + super(beans); + } + + @Override protected String getPermName() { + return "PS Perm Gen"; + } + + @Override protected String getCodeCacheName() { + return "Code Cache"; + } + + @Override protected String getEdenName() { + return "PS Eden Space"; + } + + @Override protected String getOldName() { + return "PS Old Gen"; + } + + @Override protected String getSurvivorName() { + return "PS Survivor Space"; + } + + @Override protected String getMetaspaceName() { + return "Metaspace"; + } +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/memorypool/UnknownMemoryPool.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/memorypool/UnknownMemoryPool.java new file mode 100644 index 0000000000000000000000000000000000000000..91755cafa4e8bc52327ba8c204ae2c42f6b7fd49 --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/jvm/memorypool/UnknownMemoryPool.java @@ -0,0 +1,23 @@ +package org.skywalking.apm.agent.core.jvm.memorypool; + +import java.util.LinkedList; +import java.util.List; +import org.skywalking.apm.network.proto.MemoryPool; +import org.skywalking.apm.network.proto.PoolType; + +/** + * @author wusheng + */ +public class UnknownMemoryPool implements MemoryPoolMetricAccessor { + @Override + public List getMemoryPoolMetricList() { + List poolList = new LinkedList(); + poolList.add(MemoryPool.newBuilder().setType(PoolType.CODE_CACHE_USAGE).build()); + poolList.add(MemoryPool.newBuilder().setType(PoolType.NEWGEN_USAGE).build()); + poolList.add(MemoryPool.newBuilder().setType(PoolType.OLDGEN_USAGE).build()); + poolList.add(MemoryPool.newBuilder().setType(PoolType.SURVIVOR_USAGE).build()); + poolList.add(MemoryPool.newBuilder().setType(PoolType.PERMGEN_USAGE).build()); + poolList.add(MemoryPool.newBuilder().setType(PoolType.METASPACE_USAGE).build()); + return poolList; + } +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/os/ProcessorUtil.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/os/ProcessorUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..c4736f71ab2d0ef06837d836ac08faea65f35a9b --- /dev/null +++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/os/ProcessorUtil.java @@ -0,0 +1,12 @@ +package org.skywalking.apm.agent.core.os; + +import java.lang.management.ManagementFactory; + +/** + * @author wusheng + */ +public class ProcessorUtil { + public static int getNumberOfProcessors() { + return ManagementFactory.getOperatingSystemMXBean().getAvailableProcessors(); + } +} diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/remote/GRPCChannelManager.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/remote/GRPCChannelManager.java index 8a92a41e44b50055b3b6016109a60d15c25e6b8f..78f109c40e51e00620b4d07286a1e321ef065681 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/remote/GRPCChannelManager.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/remote/GRPCChannelManager.java @@ -95,7 +95,7 @@ public class GRPCChannelManager implements BootService, Runnable { resetNextStartTime(); int waitTime = 5 * 1000; - logger.debug("Selected collector grpc service is not available. Wait {} seconds to try", waitTime); + logger.debug("Selected collector grpc service is not available. Wait {} millis to try", waitTime); try2Sleep(waitTime); } } diff --git a/apm-sniffer/apm-agent-core/src/main/resources/META-INF/services/org.skywalking.apm.agent.core.boot.BootService b/apm-sniffer/apm-agent-core/src/main/resources/META-INF/services/org.skywalking.apm.agent.core.boot.BootService index f0c0504fb0c273191ef34d4245c003f23b508ed0..695dbc331bef37bf4b7d0357becb4a7ee4cbfc49 100644 --- a/apm-sniffer/apm-agent-core/src/main/resources/META-INF/services/org.skywalking.apm.agent.core.boot.BootService +++ b/apm-sniffer/apm-agent-core/src/main/resources/META-INF/services/org.skywalking.apm.agent.core.boot.BootService @@ -3,3 +3,4 @@ org.skywalking.apm.agent.core.context.ContextManager org.skywalking.apm.agent.core.remote.CollectorDiscoveryService org.skywalking.apm.agent.core.sampling.SamplingService org.skywalking.apm.agent.core.remote.GRPCChannelManager +org.skywalking.apm.agent.core.jvm.JVMService