/*
* Copyright 2017 NAVER Corp.
*
* 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 com.navercorp.pinpoint.profiler.receiver.service;
import com.navercorp.pinpoint.common.util.JvmUtils;
import com.navercorp.pinpoint.profiler.context.active.ActiveTraceInfo;
import com.navercorp.pinpoint.profiler.context.active.ActiveTraceRepository;
import com.navercorp.pinpoint.profiler.receiver.ProfilerRequestCommandService;
import com.navercorp.pinpoint.profiler.util.ActiveThreadDumpUtils;
import com.navercorp.pinpoint.profiler.util.ThreadDumpUtils;
import com.navercorp.pinpoint.thrift.dto.command.TActiveThreadDump;
import com.navercorp.pinpoint.thrift.dto.command.TCmdActiveThreadDump;
import com.navercorp.pinpoint.thrift.dto.command.TCmdActiveThreadDumpRes;
import com.navercorp.pinpoint.thrift.dto.command.TThreadDump;
import org.apache.thrift.TBase;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @Author Taejin Koo
*/
public class ActiveThreadDumpService implements ProfilerRequestCommandService {
private final ActiveTraceRepository activeTraceRepository;
public ActiveThreadDumpService(ActiveTraceRepository activeTraceRepository) {
this.activeTraceRepository = activeTraceRepository;
}
@Override
public TBase<?, ?> requestCommandService(TBase tBase) {
TCmdActiveThreadDump request = (TCmdActiveThreadDump) tBase;
List<TActiveThreadDump> activeThreadDumpList = getActiveThreadDumpList(request);
TCmdActiveThreadDumpRes response = new TCmdActiveThreadDumpRes();
response.setType("JAVA");
response.setSubType(JvmUtils.getType().name());
response.setVersion(JvmUtils.getVersion().name());
response.setThreadDumps(activeThreadDumpList);
return response;
}
private List<TActiveThreadDump> getActiveThreadDumpList(TCmdActiveThreadDump request) {
List<ActiveTraceInfo> activeTraceInfoList = activeTraceRepository.collect();
int limit = request.getLimit();
if (limit > 0) {
Collections.sort(activeTraceInfoList, ActiveThreadDumpUtils.getActiveTraceInfoComparator());
} else {
limit = Integer.MAX_VALUE;
}
return getActiveThreadDumpList(request, limit, activeTraceInfoList);
}
private List<TActiveThreadDump> getActiveThreadDumpList(TCmdActiveThreadDump request, int limit, List<ActiveTraceInfo> activeTraceInfoList) {
int targetThreadNameListSize = request.getThreadNameListSize();
int localTraceIdListSize = request.getLocalTraceIdListSize();
boolean filterEnable = (targetThreadNameListSize + localTraceIdListSize) > 0;
List<TActiveThreadDump> activeThreadDumpList = new ArrayList<TActiveThreadDump>(Math.min(limit, activeTraceInfoList.size()));
if (filterEnable) {
for (ActiveTraceInfo activeTraceInfo : activeTraceInfoList) {
if (!ActiveThreadDumpUtils.isTraceThread(activeTraceInfo, request.getThreadNameList(), request.getLocalTraceIdList())) {
continue;
}
TActiveThreadDump activeThreadDump = createActiveThreadDump(activeTraceInfo);
if (activeThreadDump != null) {
if (limit > activeThreadDumpList.size()) {
activeThreadDumpList.add(activeThreadDump);
}
}
}
} else {
for (ActiveTraceInfo activeTraceInfo : activeTraceInfoList) {
TActiveThreadDump activeThreadDump = createActiveThreadDump(activeTraceInfo);
if (activeThreadDump != null) {
if (limit > activeThreadDumpList.size()) {
activeThreadDumpList.add(activeThreadDump);
}
}
}
}
return activeThreadDumpList;
}
private TActiveThreadDump createActiveThreadDump(ActiveTraceInfo activeTraceInfo) {
Thread thread = activeTraceInfo.getThread();
TThreadDump threadDump = createThreadDump(thread, true);
if (threadDump != null) {
return createTActiveThreadDump(activeTraceInfo, threadDump);
}
return null;
}
private TThreadDump createThreadDump(Thread thread, boolean isIncludeStackTrace) {
if (thread == null) {
return null;
}
if (isIncludeStackTrace) {
return ThreadDumpUtils.createTThreadDump(thread);
} else {
return ThreadDumpUtils.createTThreadDump(thread, 0);
}
}
private TActiveThreadDump createTActiveThreadDump(ActiveTraceInfo activeTraceInfo, TThreadDump threadDump) {
TActiveThreadDump activeThreadDump = new TActiveThreadDump();
activeThreadDump.setStartTime(activeTraceInfo.getStartTime());
activeThreadDump.setLocalTraceId(activeTraceInfo.getLocalTraceId());
activeThreadDump.setThreadDump(threadDump);
if (activeTraceInfo.isSampled()) {
activeThreadDump.setSampled(true);
activeThreadDump.setTransactionId(activeTraceInfo.getTransactionId());
activeThreadDump.setEntryPoint(activeTraceInfo.getEntryPoint());
}
return activeThreadDump;
}
@Override
public Class<? extends TBase> getCommandClazz() {
return TCmdActiveThreadDump.class;
}
}