Skip to content

Commit

Permalink
[#9641] Add new API for agent statistics
Browse files Browse the repository at this point in the history
  • Loading branch information
intr3p1d committed Jan 27, 2023
1 parent 6e8fdb7 commit b7d0ecf
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import com.navercorp.pinpoint.web.vo.timeline.inspector.InspectorTimeline;
import com.navercorp.pinpoint.web.view.tree.SimpleTreeView;
import com.navercorp.pinpoint.web.view.tree.TreeView;
import com.navercorp.pinpoint.web.vo.tree.SortByAgentInfo;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -59,6 +60,8 @@ public class AgentInfoController {

private final AgentEventService agentEventService;

private SortByAgentInfo.Rules DEFAULT_SORTBY = SortByAgentInfo.Rules.AGENT_ID_ASC;

public AgentInfoController(AgentInfoService agentInfoService, AgentEventService agentEventService) {
this.agentInfoService = Objects.requireNonNull(agentInfoService, "agentInfoService");
this.agentEventService = Objects.requireNonNull(agentEventService, "agentEventService");
Expand All @@ -76,7 +79,7 @@ public TreeView<TreeNode<AgentAndStatus>> getAgentList(
@RequestParam("to") long to) {
AgentStatusFilter filter = new DefaultAgentStatusFilter(from);
long timestamp = to;
AgentsMapByApplication allAgentsList = this.agentInfoService.getAllAgentsList(filter, Range.between(from, to));
AgentsMapByApplication<AgentAndStatus> allAgentsList = this.agentInfoService.getAllAgentsList(filter, Range.between(from, to));
return treeView(allAgentsList);
}

Expand All @@ -88,7 +91,7 @@ public TreeView<TreeNode<AgentAndStatus>> getAgentList(
return treeView(allAgentsList);
}

private static TreeView<TreeNode<AgentAndStatus>> treeView(AgentsMapByApplication agentsListsList) {
private static TreeView<TreeNode<AgentAndStatus>> treeView(AgentsMapByApplication<AgentAndStatus> agentsListsList) {
List<InstancesList<AgentAndStatus>> list = agentsListsList.getAgentsListsList();
return new SimpleTreeView<>(list, InstancesList::getGroupName, InstancesList::getInstancesList);
}
Expand All @@ -108,7 +111,12 @@ public TreeView<TreeNode<AgentStatusAndLink>> getAgentList(
new DefaultAgentStatusFilter(from)
);
long timestamp = to;
AgentsMapByHost list = this.agentInfoService.getAgentsListByApplicationName(currentRunFilter, applicationName, Range.between(from, to));
AgentsMapByHost list = this.agentInfoService.getAgentsListByApplicationName(
currentRunFilter,
applicationName,
Range.between(from, to),
DEFAULT_SORTBY
);
return treeView(list);
}

Expand All @@ -119,7 +127,11 @@ public TreeView<TreeNode<AgentStatusAndLink>> getAgentList(
AgentStatusFilter runningAgentFilter = new AgentStatusFilterChain(
AgentStatusFilter::filterRunning
);
AgentsMapByHost list = this.agentInfoService.getAgentsListByApplicationName(runningAgentFilter, applicationName, Range.between(timestamp, timestamp));
AgentsMapByHost list = this.agentInfoService.getAgentsListByApplicationName(runningAgentFilter,
applicationName,
Range.between(timestamp, timestamp),
DEFAULT_SORTBY
);
return treeView(list);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.navercorp.pinpoint.web.vo.agent.AgentStatusFilterChain;
import com.navercorp.pinpoint.web.vo.agent.AgentStatusAndLink;
import com.navercorp.pinpoint.web.vo.agent.DefaultAgentStatusFilter;
import com.navercorp.pinpoint.web.vo.agent.DetailedAgentInfo;
import com.navercorp.pinpoint.web.vo.tree.InstancesList;
import com.navercorp.pinpoint.web.vo.tree.AgentsMapByApplication;
import com.navercorp.pinpoint.web.vo.tree.AgentsMapByHost;
Expand Down Expand Up @@ -51,19 +52,18 @@ public TreeView<InstancesList<AgentAndStatus>> getAllAgentsList(
@RequestParam("from") long from,
@RequestParam("to") long to) {
AgentStatusFilter filter = new DefaultAgentStatusFilter(from);
AgentsMapByApplication allAgentsList = this.agentInfoService.getAllAgentsList(
AgentsMapByApplication<AgentAndStatus> allAgentsList = this.agentInfoService.getAllAgentsList(
filter,
Range.between(from, to)
);
return treeView(allAgentsList);
}

private static TreeView<InstancesList<AgentAndStatus>> treeView(AgentsMapByApplication agentsListsList) {
List<InstancesList<AgentAndStatus>> list = agentsListsList.getAgentsListsList();
private static <T> TreeView<InstancesList<T>> treeView(AgentsMapByApplication<T> agentsListsList) {
List<InstancesList<T>> list = agentsListsList.getAgentsListsList();
return new StaticTreeView<>(list);
}


@GetMapping(value = "/search-application", params = {"application"})
public TreeView<InstancesList<AgentStatusAndLink>> getAgentsList(
@RequestParam("application") String applicationName,
Expand Down Expand Up @@ -106,4 +106,26 @@ private static TreeView<InstancesList<AgentStatusAndLink>> treeView(AgentsMapByH
return new StaticTreeView<>(list);
}

@GetMapping(value = "/statistics")
public TreeView<InstancesList<DetailedAgentInfo>> getAllAgentStatistics(
) {
long timestamp = System.currentTimeMillis();
AgentsMapByApplication<DetailedAgentInfo> allAgentsList = this.agentInfoService.getAllAgentsStatisticsList(
AgentStatusFilter::accept,
Range.between(timestamp, timestamp)
);
return treeView(allAgentsList);
}

@GetMapping(value = "/statistics", params = {"from", "to"})
public TreeView<InstancesList<DetailedAgentInfo>> getAllAgentStatistics(
@RequestParam("from") long from,
@RequestParam("to") long to
) {
AgentsMapByApplication<DetailedAgentInfo> allAgentsList = this.agentInfoService.getAllAgentsStatisticsList(
AgentStatusFilter::accept,
Range.between(from, to)
);
return treeView(allAgentsList);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,6 @@ public interface AgentInfoDao {
* No ServerMetaData, No JvmInfo
*/
List<AgentInfo> getSimpleAgentInfos(List<String> agentIds, long timestamp);

List<DetailedAgentInfo> getDetailedAgentInfos(List<String> agentIds, long timestamp, boolean withServerMetadata, boolean withJVM);
}
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,12 @@ public List<AgentInfo> getAgentInfos(List<String> agentIds, long timestamp) {
return getAgentInfos0(agentIds, timestamp, agentInfoResultsExtractor, AgentInfoColumn.simple());
}

@Override
public List<DetailedAgentInfo> getDetailedAgentInfos(List<String> agentIds, long timestamp, boolean withServerMetadata, boolean withJVM) {
return getAgentInfos0(agentIds, timestamp, detailedAgentInfoResultsExtractor, new AgentInfoColumn(true, withServerMetadata, withJVM));
}

@Override
public List<AgentInfo> getSimpleAgentInfos(List<String> agentIds, long timestamp) {
return getAgentInfos0(agentIds, timestamp, agentInfoResultsExtractor, AgentInfoColumn.simple());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.navercorp.pinpoint.web.service;

import com.navercorp.pinpoint.common.server.util.time.Range;
import com.navercorp.pinpoint.web.vo.agent.DetailedAgentInfo;
import com.navercorp.pinpoint.web.vo.tree.AgentsMapByApplication;
import com.navercorp.pinpoint.web.vo.tree.ApplicationAgentHostList;
import com.navercorp.pinpoint.web.vo.tree.AgentsMapByHost;
Expand All @@ -41,8 +42,9 @@ public interface AgentInfoService {

int NO_DURATION = -1;

AgentsMapByApplication getAllAgentsList(AgentStatusFilter filter, Range range);
AgentsMapByApplication<AgentAndStatus> getAllAgentsList(AgentStatusFilter filter, Range range);

AgentsMapByApplication<DetailedAgentInfo> getAllAgentsStatisticsList(AgentStatusFilter filter, Range range);
AgentsMapByHost getAgentsListByApplicationName(AgentStatusFilter filter, String applicationName, Range range);

AgentsMapByHost getAgentsListByApplicationName(AgentStatusFilter filter, String applicationName, Range range, SortByAgentInfo.Rules sortBy);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public AgentInfoServiceImpl(AgentEventService agentEventService,
}

@Override
public AgentsMapByApplication getAllAgentsList(AgentStatusFilter filter, Range range) {
public AgentsMapByApplication<AgentAndStatus> getAllAgentsList(AgentStatusFilter filter, Range range) {
Objects.requireNonNull(filter, "filter");

List<Application> applications = applicationIndexDao.selectAllApplicationNames();
Expand All @@ -115,7 +115,23 @@ public AgentsMapByApplication getAllAgentsList(AgentStatusFilter filter, Range r
agents.addAll(getAgentsByApplicationName(application.getName(), range.getTo()));
}

return AgentsMapByApplication.newAgentsMapByApplication(
return AgentsMapByApplication.newAgentAndStatusMap(
filter,
agents
);
}

@Override
public AgentsMapByApplication<DetailedAgentInfo> getAllAgentsStatisticsList(AgentStatusFilter filter, Range range) {
Objects.requireNonNull(filter, "filter");

List<Application> applications = applicationIndexDao.selectAllApplicationNames();
List<DetailedAgentAndStatus> agents = new ArrayList<>();
for (Application application : applications) {
agents.addAll(getDetailedAgentsByApplicationName(application.getName(), range.getTo()));
}

return AgentsMapByApplication.newDetailedAgentInfoMap(
filter,
agents
);
Expand Down Expand Up @@ -279,6 +295,37 @@ public List<AgentInfo> getAgentsByApplicationNameWithoutStatus0(String applicati

}

public Set<DetailedAgentAndStatus> getDetailedAgentsByApplicationName(String applicationName, long timestamp) {
List<DetailedAgentInfo> agentInfos = this.getDetailedAgentsByApplicationNameWithoutStatus0(applicationName, timestamp);

List<DetailedAgentAndStatus> result = new ArrayList<>(agentInfos.size());

AgentStatusQuery query = AgentStatusQuery.buildGenericQuery(agentInfos, DetailedAgentInfo::getAgentInfo, Instant.ofEpochMilli(timestamp));
List<Optional<AgentStatus>> agentStatus = this.agentLifeCycleDao.getAgentStatus(query);

for (int i = 0; i < agentStatus.size(); i++) {
Optional<AgentStatus> status = agentStatus.get(i);
DetailedAgentInfo agentInfo = agentInfos.get(i);
result.add(new DetailedAgentAndStatus(agentInfo, status.orElse(null)));
}

return new HashSet<>(result);
}

public List<DetailedAgentInfo> getDetailedAgentsByApplicationNameWithoutStatus0(String applicationName, long timestamp) {
Objects.requireNonNull(applicationName, "applicationName");
if (timestamp < 0) {
throw new IllegalArgumentException("timestamp must not be less than 0");
}

List<String> agentIds = this.applicationIndexDao.selectAgentIds(applicationName);
List<DetailedAgentInfo> agentInfos = this.agentInfoDao.getDetailedAgentInfos(agentIds, timestamp, false, true);

return agentInfos.stream()
.filter(Objects::nonNull)
.collect(Collectors.toList());
}

@Override
public Set<AgentAndStatus> getRecentAgentsByApplicationName(String applicationName, long timestamp, long timeDiff) {
if (timeDiff > timestamp) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ public static AgentStatusQuery buildQuery(Collection<AgentInfo> agentInfos, Inst
return buildQuery(agentInfos, AgentStatusQuery::apply, timestamp);
}

public static <T> AgentStatusQuery buildGenericQuery(Collection<T> agentInfos, Function<T, AgentInfo> agentInfoFunction, Instant timestamp) {
return buildQuery(agentInfos, agentInfoFunction.andThen(AgentStatusQuery::apply), timestamp);
}

private static SimpleAgentKey apply(AgentInfo agentInfo) {
if (agentInfo == null) {
return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,45 +1,83 @@
package com.navercorp.pinpoint.web.vo.tree;

import com.navercorp.pinpoint.web.vo.agent.AgentAndStatus;
import com.navercorp.pinpoint.web.vo.agent.AgentInfo;
import com.navercorp.pinpoint.web.vo.agent.AgentStatusFilter;
import com.navercorp.pinpoint.web.vo.agent.AgentStatus;
import com.navercorp.pinpoint.web.vo.agent.DetailedAgentAndStatus;
import com.navercorp.pinpoint.web.vo.agent.DetailedAgentInfo;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;

public class AgentsMapByApplication {
public class AgentsMapByApplication<T> {

private final InstancesListMap<AgentAndStatus> instancesListMap;
private final InstancesListMap<T> instancesListMap;

private AgentsMapByApplication(InstancesListMap<AgentAndStatus> instancesListMap) {
private AgentsMapByApplication(InstancesListMap<T> instancesListMap) {
this.instancesListMap = Objects.requireNonNull(instancesListMap, "agentsListMap");
}

public List<InstancesList<AgentAndStatus>> getAgentsListsList() {
public List<InstancesList<T>> getAgentsListsList() {
return new ArrayList<>(instancesListMap.getListMap());
}

public static AgentsMapByApplication newAgentsMapByApplication(AgentStatusFilter filter,
Collection<AgentAndStatus> agentCollection) {
public static AgentsMapByApplication<AgentAndStatus> newAgentAndStatusMap(
AgentStatusFilter filter,
Collection<AgentAndStatus> agentAndStatuses
) {
return AgentsMapByApplication.newAgentsMapByApplication(
filter,
agentAndStatuses,
AgentAndStatus::getAgentInfo,
AgentAndStatus::getStatus,
Function.identity()
);
}

public static AgentsMapByApplication<DetailedAgentInfo> newDetailedAgentInfoMap(
AgentStatusFilter filter,
Collection<DetailedAgentAndStatus> agentAndStatuses
) {
return AgentsMapByApplication.newAgentsMapByApplication(
filter,
agentAndStatuses,
DetailedAgentInfo::getAgentInfo,
DetailedAgentAndStatus::getStatus,
DetailedAgentAndStatus::getDetailedAgentInfo
);
}

public static <I, T> AgentsMapByApplication<T> newAgentsMapByApplication(
AgentStatusFilter filter,
Collection<I> agentCollection,
Function<T, AgentInfo> agentInfoSupplier,
Function<I, AgentStatus> agentStatusSupplier,
Function<I, T> finisher
) {
Objects.requireNonNull(filter, "filter");
Objects.requireNonNull(agentCollection, "agentCollection");

InstancesListMapBuilder<AgentAndStatus, AgentAndStatus> instancesListMapBuilder =
new InstancesListMapBuilder<>(
AgentsMapByApplication::byApplicationName,
InstancesListMapBuilder<I, T> instancesListMapBuilder =
new InstancesListMapBuilder<I, T>(
agentInfoSupplier.andThen(AgentsMapByApplication::byApplicationName),
Comparator.naturalOrder(),
SortByAgentInfo.agentIdAsc(AgentAndStatus::getAgentInfo).getComparator(),
SortByAgentInfo.agentIdAsc(agentInfoSupplier).getComparator(),
agentCollection
);

instancesListMapBuilder.withFilter((AgentAndStatus a) -> filter.filter(a.getStatus()));
return new AgentsMapByApplication(instancesListMapBuilder.build());
instancesListMapBuilder.withFilter((I x) -> filter.filter(agentStatusSupplier.apply(x)));
instancesListMapBuilder.withFinisher(finisher);
return new AgentsMapByApplication<T>(instancesListMapBuilder.build());
}

private static String byApplicationName(AgentAndStatus agentAndStatus) {
return agentAndStatus.getAgentInfo().getApplicationName();
private static String byApplicationName(AgentInfo agentInfo) {
return agentInfo.getApplicationName();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public void groupByApplicationName() {
AgentAndStatus app2Agent2 = createAgentInfo("APP_2", "app2-agent2", "Host22", true);
List<AgentAndStatus> agentAndStatusList = shuffleAgentInfos(app1Agent1, app1Agent2, app2Agent1, app2Agent2);

AgentsMapByApplication agentsMapByApplication = AgentsMapByApplication.newAgentsMapByApplication(AgentStatusFilter::accept, agentAndStatusList);
AgentsMapByApplication<AgentAndStatus> agentsMapByApplication = AgentsMapByApplication.newAgentAndStatusMap(AgentStatusFilter::accept, agentAndStatusList);
List<InstancesList<AgentAndStatus>> instancesLists = agentsMapByApplication.getAgentsListsList();

Assertions.assertEquals(2, instancesLists.size());
Expand Down

0 comments on commit b7d0ecf

Please sign in to comment.