/** * Copyright 2005-2016 Red Hat, Inc. * * Red Hat licenses this file to you under the Apache License, version * 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. */ package io.fabric8.apmagent.metrics; import io.fabric8.apmagent.ApmConfiguration; import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicReference; public class ThreadMetrics { private final AtomicReference<ThreadContextMethodMetricsStack> methodStackRef; private final ApmAgentContext apmAgentContext; private final ThreadInfo threadInfo; private final Thread thread; private final ThreadMXBean threadMXBean; private final ConcurrentMap<String, ThreadContextMethodMetrics> methods = new ConcurrentHashMap<>(); private final MonitoredThreadMethodMetrics monitoredThreadMethodMetrics; public ThreadMetrics(ApmAgentContext apmAgentContext, Thread thread) { this.methodStackRef = new AtomicReference<>(new ThreadContextMethodMetricsStack()); this.apmAgentContext = apmAgentContext; this.threadMXBean = ManagementFactory.getThreadMXBean(); this.threadInfo = threadMXBean.getThreadInfo(thread.getId()); this.thread = thread; ApmConfiguration configuration = apmAgentContext.getConfiguration(); this.monitoredThreadMethodMetrics = new MonitoredThreadMethodMetrics(thread, apmAgentContext); this.monitoredThreadMethodMetrics.setMonitorSize(configuration.getThreadMetricDepth()); } public String getName() { return thread.getName() + "[" + thread.getId() + "]"; } Thread getThread() { return thread; } public boolean isDead() { return !thread.isAlive(); } public long getCpuTime() { return threadMXBean.getThreadCpuTime(thread.getId()); } public long getUserTime() { return threadMXBean.getThreadUserTime(thread.getId()); } public ThreadInfo getThreadInfo() { return threadInfo; } public void setMonitorSize(int monitorSize) { monitoredThreadMethodMetrics.setMonitorSize(monitorSize); } public void enter(String methodName, boolean alwaysActive) { ThreadContextMethodMetrics threadContextMethodMetrics = methods.get(methodName); if (threadContextMethodMetrics == null) { threadContextMethodMetrics = new ThreadContextMethodMetrics(thread, this.methodStackRef, methodName); threadContextMethodMetrics.setActive(apmAgentContext.isMonitorByDefault()); methods.putIfAbsent(methodName, threadContextMethodMetrics); } if (alwaysActive || threadContextMethodMetrics.isActive()) { threadContextMethodMetrics.onEnter(); } } public long exit(String methodName, boolean alwaysActive) { long result = -1; ThreadContextMethodMetrics threadContextMethodMetrics = methods.get(methodName); if (threadContextMethodMetrics != null) { if (alwaysActive || threadContextMethodMetrics.isActive()) { result = threadContextMethodMetrics.onExit(); } } else { //something weird happended reset the stack methodStackRef.set(new ThreadContextMethodMetricsStack()); } return result; } public String toString() { return "ThreadMetrics:" + getName(); } public void destroy() { monitoredThreadMethodMetrics.destroy(); } public ThreadContextMethodMetrics remove(String fullMethodName) { ThreadContextMethodMetrics result = methods.remove(fullMethodName); return result; } public void calculateMethodMetrics() { List<ThreadContextMethodMetrics> list = (List<ThreadContextMethodMetrics>) MethodMetrics.sortedMetrics(this.methods.values()); monitoredThreadMethodMetrics.calculateMethodMetrics(list); } public void setActive(String methodName, boolean flag) { ThreadContextMethodMetrics threadContextMethodMetrics = methods.get(methodName); if (threadContextMethodMetrics != null) { threadContextMethodMetrics.setActive(flag); } } public boolean isActive(String methodName) { ThreadContextMethodMetrics threadContextMethodMetrics = methods.get(methodName); return threadContextMethodMetrics != null ? threadContextMethodMetrics.isActive() : false; } }