/**
* 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;
}
}