
org.glowroot.agent.live.ThreadDumpService Maven / Gradle / Ivy
/*
* Copyright 2015 the original author or authors.
*
* Licensed 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 org.glowroot.agent.live;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import org.glowroot.agent.shaded.google.common.collect.Lists;
import org.glowroot.agent.shaded.google.common.collect.Maps;
import org.glowroot.agent.shaded.google.common.collect.Ordering;
import org.glowroot.agent.shaded.google.common.primitives.Ints;
import org.glowroot.agent.shaded.google.common.primitives.Longs;
import org.glowroot.agent.impl.TransactionCollector;
import org.glowroot.agent.impl.TransactionRegistry;
import org.glowroot.agent.model.Transaction;
import org.glowroot.common.live.ImmutableAllThreads;
import org.glowroot.common.live.ImmutableOneThread;
import org.glowroot.common.live.LiveJvmService.AllThreads;
import org.glowroot.common.live.LiveJvmService.OneThread;
import static org.glowroot.agent.shaded.google.common.base.Preconditions.checkNotNull;
class ThreadDumpService {
private final TransactionRegistry transactionRegistry;
private final TransactionCollector transactionCollector;
ThreadDumpService(TransactionRegistry transactionRegistry,
TransactionCollector transactionCollector) {
this.transactionRegistry = transactionRegistry;
this.transactionCollector = transactionCollector;
}
AllThreads getAllThreads() {
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
Map transactionsBefore = Maps.newHashMap();
for (Transaction transaction : transactionRegistry.getTransactions()) {
transactionsBefore.put(transaction.getThreadId(), transaction);
}
ThreadInfo[] threadInfos =
threadBean.getThreadInfo(threadBean.getAllThreadIds(), Integer.MAX_VALUE);
final Map matchedTransactions = Maps.newHashMap();
for (Transaction transaction : transactionRegistry.getTransactions()) {
if (transactionsBefore.get(transaction.getThreadId()) == transaction) {
matchedTransactions.put(transaction.getThreadId(), transaction);
}
}
long currentThreadId = Thread.currentThread().getId();
ThreadInfo currentThreadInfo = null;
List matchedThreadInfos = Lists.newArrayList();
List unmatchedThreadInfos = Lists.newArrayList();
for (ThreadInfo threadInfo : threadInfos) {
long threadId = threadInfo.getThreadId();
if (threadId == currentThreadId) {
currentThreadInfo = threadInfo;
} else if (matchedTransactions.containsKey(threadId)) {
matchedThreadInfos.add(threadInfo);
} else {
unmatchedThreadInfos.add(threadInfo);
}
}
// sort descending by total time
Collections.sort(matchedThreadInfos, new MatchedThreadInfoOrdering(matchedTransactions));
// sort descending by stack trace length
Collections.sort(unmatchedThreadInfos, new UnmatchedThreadInfoOrdering());
List matchedThreads = Lists.newArrayList();
for (ThreadInfo threadInfo : matchedThreadInfos) {
Transaction matchedTransaction = matchedTransactions.get(threadInfo.getThreadId());
matchedThreads.add(createOneThread(threadInfo, matchedTransaction));
}
List unmatchedThreads = Lists.newArrayList();
for (ThreadInfo threadInfo : unmatchedThreadInfos) {
unmatchedThreads.add(createOneThread(threadInfo, null));
}
OneThread currentThread = null;
if (currentThreadInfo != null) {
Transaction matchedTransaction =
matchedTransactions.get(currentThreadInfo.getThreadId());
currentThread = createOneThread(currentThreadInfo, matchedTransaction);
}
return ImmutableAllThreads.builder()
.matchedThreads(matchedThreads)
.unmatchedThreads(unmatchedThreads)
.currentThread(currentThread)
.build();
}
private OneThread createOneThread(ThreadInfo threadInfo,
@Nullable Transaction matchedTransaction) {
ImmutableOneThread.Builder builder = ImmutableOneThread.builder();
builder.name(threadInfo.getThreadName());
builder.state(threadInfo.getThreadState().name());
builder.lockName(threadInfo.getLockName());
for (StackTraceElement stackTraceElement : threadInfo.getStackTrace()) {
builder.addStackTraceElements(stackTraceElement.toString());
}
if (matchedTransaction != null) {
builder.transactionType(matchedTransaction.getTransactionType());
builder.transactionName(matchedTransaction.getTransactionName());
builder.transactionTotalNanos(matchedTransaction.getDurationNanos());
if (transactionCollector.shouldStoreSlow(matchedTransaction)) {
builder.traceId(matchedTransaction.getId());
}
}
return builder.build();
}
private static class MatchedThreadInfoOrdering extends Ordering {
private final Map matchedTransactions;
private MatchedThreadInfoOrdering(Map matchedTransactions) {
this.matchedTransactions = matchedTransactions;
}
@Override
public int compare(ThreadInfo left, ThreadInfo right) {
Transaction leftTransaction = matchedTransactions.get(left.getThreadId());
Transaction rightTransaction = matchedTransactions.get(right.getThreadId());
// left and right are from matchedThreadInfos so have corresponding transactions
checkNotNull(leftTransaction);
checkNotNull(rightTransaction);
return Longs.compare(rightTransaction.getDurationNanos(),
leftTransaction.getDurationNanos());
}
}
private static class UnmatchedThreadInfoOrdering extends Ordering {
@Override
public int compare(ThreadInfo left, ThreadInfo right) {
if (left.getThreadId() == Thread.currentThread().getId()) {
return 1;
} else if (right.getThreadId() == Thread.currentThread().getId()) {
return -1;
}
int result = Ints.compare(right.getStackTrace().length, left.getStackTrace().length);
if (result == 0) {
return left.getThreadName().compareToIgnoreCase(right.getThreadName());
}
return result;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy