diff --git a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/FilterMapWrap.java b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/FilterMapWrap.java index a613c41c68bf1..19eb14097c7b9 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/FilterMapWrap.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/FilterMapWrap.java @@ -33,7 +33,7 @@ public class FilterMapWrap { public FilterMapWrap(ApplicationMap applicationMap, TimeHistogramFormat timeHistogramFormat) { this.applicationMap = applicationMap; - if(timeHistogramFormat == TimeHistogramFormat.V2) { + if(timeHistogramFormat != TimeHistogramFormat.V1) { for(Node node : applicationMap.getNodes()) { node.setTimeHistogramFormat(timeHistogramFormat); } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/MapWrap.java b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/MapWrap.java index dea57cd3308bc..3e7f484520bd4 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/MapWrap.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/MapWrap.java @@ -31,11 +31,11 @@ public class MapWrap { public MapWrap(ApplicationMap applicationMap, final TimeHistogramFormat timeHistogramFormat) { this.applicationMap = applicationMap; - if(timeHistogramFormat == TimeHistogramFormat.V2) { - for(Node node : applicationMap.getNodes()) { + if (timeHistogramFormat != TimeHistogramFormat.V1) { + for (Node node : applicationMap.getNodes()) { node.setTimeHistogramFormat(timeHistogramFormat); } - for(Link link : applicationMap.getLinks()) { + for (Link link : applicationMap.getLinks()) { link.setTimeHistogramFormat(timeHistogramFormat); } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/histogram/AgentTimeHistogram.java b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/histogram/AgentTimeHistogram.java index 2554f1a5e6d9c..33143dd3243e0 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/histogram/AgentTimeHistogram.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/histogram/AgentTimeHistogram.java @@ -23,6 +23,9 @@ import com.navercorp.pinpoint.web.util.TimeWindow; import com.navercorp.pinpoint.web.view.AgentResponseTimeViewModel; import com.navercorp.pinpoint.web.view.TimeViewModel; +import com.navercorp.pinpoint.web.view.time.LoadChartView; +import com.navercorp.pinpoint.web.view.time.LoadStatsticsChartView; +import com.navercorp.pinpoint.web.view.time.TimeHistogramView; import com.navercorp.pinpoint.web.vo.Application; import com.navercorp.pinpoint.web.vo.stat.SampledApdexScore; import com.navercorp.pinpoint.web.vo.stat.chart.agent.AgentStatPoint; @@ -32,7 +35,9 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; /** @@ -79,6 +84,41 @@ public List createViewModel(TimeHistogramFormat time return result; } + public Map> createTimeSeriesView() { + Map> result = new HashMap<>(); + for (AgentHistogram agentHistogram : agentHistogramList.getAgentHistogramList()) { + Application agentId = agentHistogram.getAgentId(); + List histogramList = sortTimeHistogram(agentHistogram.getTimeHistogram()); + + TimeHistogramView load = new LoadChartView(agentId.getServiceType().getHistogramSchema(), histogramList); + TimeHistogramView loadStatistics = new LoadStatsticsChartView(histogramList); + result.put(agentId.getName(), List.of(load, loadStatistics)); + } + return result; + } + + public Map createLoadChartView() { + Map result = new HashMap<>(); + for (AgentHistogram agentHistogram : agentHistogramList.getAgentHistogramList()) { + Application agentId = agentHistogram.getAgentId(); + List histogramList = sortTimeHistogram(agentHistogram.getTimeHistogram()); + + result.put(agentId.getName(), new LoadChartView(agentId.getServiceType().getHistogramSchema(), histogramList)); + } + return result; + } + + public Map createLoadStatisticsChartView() { + Map result = new HashMap<>(); + for (AgentHistogram agentHistogram : agentHistogramList.getAgentHistogramList()) { + Application agentId = agentHistogram.getAgentId(); + List histogramList = sortTimeHistogram(agentHistogram.getTimeHistogram()); + + result.put(agentId.getName(), new LoadStatsticsChartView(histogramList)); + } + return result; + } + private List sortTimeHistogram(Collection timeMap) { List timeList = new ArrayList<>(timeMap); timeList.sort(TimeHistogram.TIME_STAMP_ASC_COMPARATOR); diff --git a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/histogram/ApplicationTimeHistogram.java b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/histogram/ApplicationTimeHistogram.java index 9da2bc8f6fa13..f453b5732aee4 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/histogram/ApplicationTimeHistogram.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/histogram/ApplicationTimeHistogram.java @@ -16,11 +16,16 @@ package com.navercorp.pinpoint.web.applicationmap.histogram; +import com.navercorp.pinpoint.common.server.util.time.Range; import com.navercorp.pinpoint.web.view.TimeViewModel; +import com.navercorp.pinpoint.web.view.time.LoadChartView; +import com.navercorp.pinpoint.web.view.time.LoadStatsticsChartView; +import com.navercorp.pinpoint.web.view.time.TimeHistogramView; import com.navercorp.pinpoint.web.vo.Application; -import com.navercorp.pinpoint.common.server.util.time.Range; -import java.util.*; +import java.util.Collections; +import java.util.List; +import java.util.Objects; /** * @author emeroad @@ -43,4 +48,12 @@ public ApplicationTimeHistogram(Application application, Range range, List createViewModel(TimeHistogramFormat timeHistogramFormat) { return new TimeViewModel.TimeViewModelBuilder(application, histogramList).setTimeHistogramFormat(timeHistogramFormat).build(); } + + public TimeHistogramView createLoadChartView() { + return new LoadChartView(application.getServiceType().getHistogramSchema(), histogramList); + } + + public TimeHistogramView createLoadStatisticsChartView() { + return new LoadStatsticsChartView(histogramList); + } } \ No newline at end of file diff --git a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/histogram/NodeHistogram.java b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/histogram/NodeHistogram.java index 419f57a26e110..47077dfb26677 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/histogram/NodeHistogram.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/histogram/NodeHistogram.java @@ -19,6 +19,7 @@ import com.navercorp.pinpoint.common.server.util.time.Range; import com.navercorp.pinpoint.web.view.AgentResponseTimeViewModelList; import com.navercorp.pinpoint.web.view.TimeViewModel; +import com.navercorp.pinpoint.web.view.time.TimeHistogramView; import com.navercorp.pinpoint.web.vo.Application; import com.navercorp.pinpoint.web.vo.ResponseTime; import com.navercorp.pinpoint.web.vo.ResponseTimeStatics; @@ -115,10 +116,22 @@ public List getApplicationTimeHistogram(TimeHistogramFormat timeH return applicationTimeHistogram.createViewModel(timeHistogramFormat); } + public TimeHistogramView getApplicationLoadChartView() { + return applicationTimeHistogram.createLoadChartView(); + } + + public TimeHistogramView getApplicationLoadStatisticsChartView() { + return applicationTimeHistogram.createLoadStatisticsChartView(); + } + public AgentResponseTimeViewModelList getAgentTimeHistogram(TimeHistogramFormat timeHistogramFormat) { return new AgentResponseTimeViewModelList(agentTimeHistogram.createViewModel(timeHistogramFormat)); } + public Map> getAgentTimeSeriesView() { + return agentTimeHistogram.createTimeSeriesView(); + } + public void setAgentTimeHistogram(AgentTimeHistogram agentTimeHistogram) { this.agentTimeHistogram = agentTimeHistogram; } @@ -165,7 +178,7 @@ private Histogram createApplicationLevelResponseTime(List response } return applicationHistogram; } - + public Range getRange() { return range; } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/histogram/TimeHistogramFormat.java b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/histogram/TimeHistogramFormat.java index 1d6223f1a225a..2186ac1e78c4c 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/histogram/TimeHistogramFormat.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/histogram/TimeHistogramFormat.java @@ -18,5 +18,6 @@ public enum TimeHistogramFormat { V1, // key is slot("1s", "3s", "5s", "Slow", "Error"), value is {timestamp : count} - V2 // key is timestamp, value is [1s, 3s, 5s, Slow, Error, Avg, Max, Sum, Tot] - LoadHistogram + V2, // key is timestamp, value is [1s, 3s, 5s, Slow, Error, Avg, Max, Sum, Tot] - LoadHistogram + V3 // time series format, fieldName is slot("1s", "3s", "5s", "Slow", "Error") } \ No newline at end of file diff --git a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/link/Link.java b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/link/Link.java index ef311e1b3bfca..84ce0bc42739d 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/link/Link.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/link/Link.java @@ -33,11 +33,13 @@ import com.navercorp.pinpoint.web.view.AgentResponseTimeViewModelList; import com.navercorp.pinpoint.web.view.LinkSerializer; import com.navercorp.pinpoint.web.view.TimeViewModel; +import com.navercorp.pinpoint.web.view.time.TimeHistogramView; import com.navercorp.pinpoint.web.vo.Application; import java.util.Collection; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; @@ -213,6 +215,14 @@ public ApplicationTimeHistogram getTargetApplicationTimeSeriesHistogramData() { return builder.build(targetLinkCallDataMap.getLinkDataList()); } + public ApplicationTimeHistogram getLinkApplicationTimeHistogram() { + if (createType == CreateType.Source) { + return getSourceApplicationTimeSeriesHistogramData(); + } else { + return getTargetApplicationTimeSeriesHistogramData(); + } + } + public void addSource(LinkCallDataMap sourceLinkCallDataMap) { this.sourceLinkCallDataMap.addLinkDataMap(sourceLinkCallDataMap); } @@ -233,6 +243,13 @@ public AgentTimeHistogram getTargetAgentTimeHistogram() { return builder.buildSource(targetLinkCallDataMap); } + public Map> getSourceAgentTimeSeriesView() { + AgentTimeHistogramBuilder builder = new AgentTimeHistogramBuilder(toNode.getApplication(), range); + AgentTimeHistogram sourceAgentTimeHistogram = builder.buildSource(sourceLinkCallDataMap); + + return sourceAgentTimeHistogram.createTimeSeriesView(); + } + public Collection getSourceLinkTargetAgentList() { Set agentList = new HashSet<>(); Collection linkDataList = sourceLinkCallDataMap.getLinkDataList(); diff --git a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/link/LinkHistogramSummary.java b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/link/LinkHistogramSummary.java index d8e17b1d3bd9a..0272f14b8b7e8 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/link/LinkHistogramSummary.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/applicationmap/link/LinkHistogramSummary.java @@ -17,6 +17,7 @@ package com.navercorp.pinpoint.web.applicationmap.link; import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.navercorp.pinpoint.web.applicationmap.histogram.ApplicationTimeHistogram; import com.navercorp.pinpoint.web.applicationmap.histogram.Histogram; import com.navercorp.pinpoint.web.applicationmap.histogram.TimeHistogramFormat; import com.navercorp.pinpoint.web.view.LinkHistogramSummarySerializer; @@ -54,6 +55,10 @@ public List getTimeSeriesHistogram() { return link.getLinkApplicationTimeSeriesHistogram(); } + public ApplicationTimeHistogram getApplicationTimeHistogram() { + return link.getLinkApplicationTimeHistogram(); + } + @Override public String toString() { return "LinkHistogramSummary{" + diff --git a/web/src/main/java/com/navercorp/pinpoint/web/controller/MapController.java b/web/src/main/java/com/navercorp/pinpoint/web/controller/MapController.java index 419527b61cd0b..a636eedc72dea 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/controller/MapController.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/controller/MapController.java @@ -16,11 +16,13 @@ package com.navercorp.pinpoint.web.controller; +import com.navercorp.pinpoint.common.server.util.time.Range; import com.navercorp.pinpoint.web.applicationmap.ApplicationMap; import com.navercorp.pinpoint.web.applicationmap.MapWrap; import com.navercorp.pinpoint.web.applicationmap.histogram.TimeHistogramFormat; import com.navercorp.pinpoint.web.applicationmap.link.LinkHistogramSummary; import com.navercorp.pinpoint.web.applicationmap.link.LinkType; +import com.navercorp.pinpoint.web.applicationmap.nodes.NodeHistogramSummary; import com.navercorp.pinpoint.web.applicationmap.nodes.NodeType; import com.navercorp.pinpoint.web.service.ApplicationFactory; import com.navercorp.pinpoint.web.service.MapService; @@ -29,14 +31,12 @@ import com.navercorp.pinpoint.web.service.ResponseTimeHistogramServiceOption; import com.navercorp.pinpoint.web.util.Limiter; import com.navercorp.pinpoint.web.view.ApplicationTimeHistogramViewModel; -import com.navercorp.pinpoint.web.applicationmap.nodes.NodeHistogramSummary; import com.navercorp.pinpoint.web.vo.Application; import com.navercorp.pinpoint.web.vo.ApplicationPair; import com.navercorp.pinpoint.web.vo.ApplicationPairs; -import com.navercorp.pinpoint.common.server.util.time.Range; import com.navercorp.pinpoint.web.vo.SearchOption; -import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.GetMapping; diff --git a/web/src/main/java/com/navercorp/pinpoint/web/controller/ResponseTimeController.java b/web/src/main/java/com/navercorp/pinpoint/web/controller/ResponseTimeController.java new file mode 100644 index 0000000000000..539f16c887de3 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/controller/ResponseTimeController.java @@ -0,0 +1,241 @@ +/* + * Copyright 2023 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.web.controller; + +import com.navercorp.pinpoint.common.server.util.time.Range; +import com.navercorp.pinpoint.web.applicationmap.histogram.ApplicationTimeHistogram; +import com.navercorp.pinpoint.web.applicationmap.histogram.Histogram; +import com.navercorp.pinpoint.web.applicationmap.histogram.NodeHistogram; +import com.navercorp.pinpoint.web.applicationmap.link.LinkHistogramSummary; +import com.navercorp.pinpoint.web.applicationmap.nodes.NodeHistogramSummary; +import com.navercorp.pinpoint.web.service.ApplicationFactory; +import com.navercorp.pinpoint.web.service.ResponseTimeHistogramService; +import com.navercorp.pinpoint.web.service.ResponseTimeHistogramServiceOption; +import com.navercorp.pinpoint.web.util.Limiter; +import com.navercorp.pinpoint.web.view.time.TimeHistogramView; +import com.navercorp.pinpoint.web.vo.Application; +import com.navercorp.pinpoint.web.vo.ApplicationPair; +import com.navercorp.pinpoint.web.vo.ApplicationPairs; +import com.navercorp.pinpoint.web.vo.ResponseTimeStatics; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +@RestController +public class ResponseTimeController { + private final Logger logger = LogManager.getLogger(this.getClass()); + + private final ResponseTimeHistogramService responseTimeHistogramService; + private final Limiter dateLimit; + private final ApplicationFactory applicationFactory; + + public ResponseTimeController(ResponseTimeHistogramService responseTimeHistogramService, + Limiter dateLimit, ApplicationFactory applicationFactory) { + this.responseTimeHistogramService = Objects.requireNonNull(responseTimeHistogramService, "responseTimeHistogramService"); + this.dateLimit = Objects.requireNonNull(dateLimit, "dateLimit"); + this.applicationFactory = Objects.requireNonNull(applicationFactory, "applicationFactory"); + } + + //node + @PostMapping(value = "/getNodeResponseSummary") + public Histogram postNodeResponseSummary( + @RequestParam("applicationName") String applicationName, + @RequestParam("serviceTypeCode") Short serviceTypeCode, + @RequestParam("from") long from, + @RequestParam("to") long to, + @RequestBody ApplicationPairs applicationPairs, + @RequestParam(value = "useStatisticsAgentState", defaultValue = "false", required = false) boolean useStatisticsAgentState) { + final NodeHistogramSummary nodeHistogramSummary = getNodeHistogramSummary(applicationName, serviceTypeCode, + from, to, applicationPairs, useStatisticsAgentState); + + final NodeHistogram nodeHistogram = nodeHistogramSummary.getNodeHistogram(); + return nodeHistogram.getApplicationHistogram(); + } + + @PostMapping(value = "/getNodeResponseStatistics") + public ResponseTimeStatics postNodeResponseStatistics( + @RequestParam("applicationName") String applicationName, + @RequestParam("serviceTypeCode") Short serviceTypeCode, + @RequestParam("from") long from, + @RequestParam("to") long to, + @RequestBody ApplicationPairs applicationPairs, + @RequestParam(value = "useStatisticsAgentState", defaultValue = "false", required = false) boolean useStatisticsAgentState) { + final NodeHistogramSummary nodeHistogramSummary = getNodeHistogramSummary(applicationName, serviceTypeCode, + from, to, applicationPairs, useStatisticsAgentState); + + final NodeHistogram nodeHistogram = nodeHistogramSummary.getNodeHistogram(); + return ResponseTimeStatics.fromHistogram(nodeHistogram.getApplicationHistogram()); + } + + @PostMapping(value = "/getNodeLoadChart") + public TimeHistogramView postNodeLoadChart( + @RequestParam("applicationName") String applicationName, + @RequestParam("serviceTypeCode") Short serviceTypeCode, + @RequestParam("from") long from, + @RequestParam("to") long to, + @RequestBody ApplicationPairs applicationPairs, + @RequestParam(value = "useStatisticsAgentState", defaultValue = "false", required = false) boolean useStatisticsAgentState) { + final NodeHistogramSummary nodeHistogramSummary = getNodeHistogramSummary(applicationName, serviceTypeCode, + from, to, applicationPairs, useStatisticsAgentState); + + final NodeHistogram nodeHistogram = nodeHistogramSummary.getNodeHistogram(); + return nodeHistogram.getApplicationLoadChartView(); + } + + @PostMapping(value = "/getNodeLoadStatisticsChart") + public TimeHistogramView postNodeLoadStatisticsChart( + @RequestParam("applicationName") String applicationName, + @RequestParam("serviceTypeCode") Short serviceTypeCode, + @RequestParam("from") long from, + @RequestParam("to") long to, + @RequestBody ApplicationPairs applicationPairs, + @RequestParam(value = "useStatisticsAgentState", defaultValue = "false", required = false) boolean useStatisticsAgentState) { + final NodeHistogramSummary nodeHistogramSummary = getNodeHistogramSummary(applicationName, serviceTypeCode, + from, to, applicationPairs, useStatisticsAgentState); + + final NodeHistogram nodeHistogram = nodeHistogramSummary.getNodeHistogram(); + return nodeHistogram.getApplicationLoadStatisticsChartView(); + } + + public NodeHistogramSummary getNodeHistogramSummary(String applicationName, Short serviceTypeCode, + long from, long to, ApplicationPairs applicationPairs, boolean useStatisticsAgentState) { + final Range range = Range.between(from, to); + dateLimit.limit(range); + + Application application = applicationFactory.createApplication(applicationName, serviceTypeCode); + + List fromApplications = mapApplicationPairsToApplications(applicationPairs.getFromApplications()); + List toApplications = mapApplicationPairsToApplications(applicationPairs.getToApplications()); + final ResponseTimeHistogramServiceOption option = new ResponseTimeHistogramServiceOption.Builder(application, range, fromApplications, toApplications) + .setUseStatisticsAgentState(useStatisticsAgentState).build(); + return responseTimeHistogramService.selectNodeHistogramData(option); + } + + //link + @GetMapping(value = "/getLinkResponseSummary") + public Histogram getLinkResponseSummary( + @RequestParam("fromApplicationName") String fromApplicationName, + @RequestParam(value = "fromServiceTypeCode", required = false) Short fromServiceTypeCode, + @RequestParam(value = "fromServiceTypeName", required = false) String fromServiceTypeName, + @RequestParam("toApplicationName") String toApplicationName, + @RequestParam(value = "toServiceTypeCode", required = false) Short toServiceTypeCode, + @RequestParam(value = "toServiceTypeName", required = false) String toServiceTypeName, + @RequestParam("from") long from, + @RequestParam("to") long to) { + final LinkHistogramSummary linkHistogramSummary = getLinkHistogramSummary(fromApplicationName, fromServiceTypeCode, fromServiceTypeName, + toApplicationName, toServiceTypeCode, toServiceTypeName, from, to); + + return linkHistogramSummary.getHistogram(); + } + + @GetMapping(value = "/getLinkResponseStatistics") + public ResponseTimeStatics getLinkResponseStatistics( + @RequestParam("fromApplicationName") String fromApplicationName, + @RequestParam(value = "fromServiceTypeCode", required = false) Short fromServiceTypeCode, + @RequestParam(value = "fromServiceTypeName", required = false) String fromServiceTypeName, + @RequestParam("toApplicationName") String toApplicationName, + @RequestParam(value = "toServiceTypeCode", required = false) Short toServiceTypeCode, + @RequestParam(value = "toServiceTypeName", required = false) String toServiceTypeName, + @RequestParam("from") long from, + @RequestParam("to") long to) { + final LinkHistogramSummary linkHistogramSummary = getLinkHistogramSummary(fromApplicationName, fromServiceTypeCode, fromServiceTypeName, + toApplicationName, toServiceTypeCode, toServiceTypeName, from, to); + + return ResponseTimeStatics.fromHistogram(linkHistogramSummary.getHistogram()); + } + + @GetMapping(value = "/getLinkLoadChart") + public TimeHistogramView getLinkLoadChart( + @RequestParam("fromApplicationName") String fromApplicationName, + @RequestParam(value = "fromServiceTypeCode", required = false) Short fromServiceTypeCode, + @RequestParam(value = "fromServiceTypeName", required = false) String fromServiceTypeName, + @RequestParam("toApplicationName") String toApplicationName, + @RequestParam(value = "toServiceTypeCode", required = false) Short toServiceTypeCode, + @RequestParam(value = "toServiceTypeName", required = false) String toServiceTypeName, + @RequestParam("from") long from, + @RequestParam("to") long to) { + final LinkHistogramSummary linkHistogramSummary = getLinkHistogramSummary(fromApplicationName, fromServiceTypeCode, fromServiceTypeName, + toApplicationName, toServiceTypeCode, toServiceTypeName, from, to); + + final ApplicationTimeHistogram applicationTimeHistogram = linkHistogramSummary.getApplicationTimeHistogram(); + return applicationTimeHistogram.createLoadChartView(); + } + + @GetMapping(value = "/getLinkLoadStatisticsChart") + public TimeHistogramView getLinkLoadStatisticsChart( + @RequestParam("fromApplicationName") String fromApplicationName, + @RequestParam(value = "fromServiceTypeCode", required = false) Short fromServiceTypeCode, + @RequestParam(value = "fromServiceTypeName", required = false) String fromServiceTypeName, + @RequestParam("toApplicationName") String toApplicationName, + @RequestParam(value = "toServiceTypeCode", required = false) Short toServiceTypeCode, + @RequestParam(value = "toServiceTypeName", required = false) String toServiceTypeName, + @RequestParam("from") long from, + @RequestParam("to") long to) { + final LinkHistogramSummary linkHistogramSummary = getLinkHistogramSummary(fromApplicationName, fromServiceTypeCode, fromServiceTypeName, + toApplicationName, toServiceTypeCode, toServiceTypeName, from, to); + + final ApplicationTimeHistogram applicationTimeHistogram = linkHistogramSummary.getApplicationTimeHistogram(); + return applicationTimeHistogram.createLoadStatisticsChartView(); + } + + private LinkHistogramSummary getLinkHistogramSummary(String fromApplicationName, Short fromServiceTypeCode, String fromServiceTypeName, + String toApplicationName, Short toServiceTypeCode, String toServiceTypeName, + long from, long to) { + final Range range = Range.between(from, to); + dateLimit.limit(range); + + Application fromApplication = createApplication(fromApplicationName, fromServiceTypeCode, fromServiceTypeName); + Application toApplication = createApplication(toApplicationName, toServiceTypeCode, toServiceTypeName); + return responseTimeHistogramService.selectLinkHistogramData(fromApplication, toApplication, range); + } + + private List mapApplicationPairsToApplications(List applicationPairs) { + if (CollectionUtils.isEmpty(applicationPairs)) { + return Collections.emptyList(); + } + List applications = new ArrayList<>(applicationPairs.size()); + for (ApplicationPair applicationPair : applicationPairs) { + String applicationName = applicationPair.getApplicationName(); + short serviceTypeCode = applicationPair.getServiceTypeCode(); + Application application = applicationFactory.createApplication(applicationName, serviceTypeCode); + applications.add(application); + } + return applications; + } + + private Application createApplication(String applicationName, Short serviceTypeCode, String serviceTypeName) { + if (StringUtils.hasLength(applicationName)) { + if (serviceTypeCode != null) { + return applicationFactory.createApplication(applicationName, serviceTypeCode); + } else if (serviceTypeName != null) { + return applicationFactory.createApplicationByTypeName(applicationName, serviceTypeName); + } + } + return null; + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/view/LinkSerializer.java b/web/src/main/java/com/navercorp/pinpoint/web/view/LinkSerializer.java index abc77fda18808..a24fe17789edd 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/view/LinkSerializer.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/view/LinkSerializer.java @@ -20,7 +20,9 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; +import com.navercorp.pinpoint.web.applicationmap.histogram.ApplicationTimeHistogram; import com.navercorp.pinpoint.web.applicationmap.histogram.Histogram; +import com.navercorp.pinpoint.web.applicationmap.histogram.TimeHistogramFormat; import com.navercorp.pinpoint.web.applicationmap.link.Link; import com.navercorp.pinpoint.web.applicationmap.link.LinkType; import com.navercorp.pinpoint.web.applicationmap.nodes.Node; @@ -142,9 +144,14 @@ private void writeWasToWasTargetRpcList(Link link, JsonGenerator jgen) throws IO } private void writeTimeSeriesHistogram(Link link, JsonGenerator jgen) throws IOException { - List sourceApplicationTimeSeriesHistogram = link.getLinkApplicationTimeSeriesHistogram(); - jgen.writeFieldName("timeSeriesHistogram"); - jgen.writeObject(sourceApplicationTimeSeriesHistogram); + if (link.getTimeHistogramFormat() == TimeHistogramFormat.V3) { + ApplicationTimeHistogram applicationTimeHistogram = link.getLinkApplicationTimeHistogram(); + jgen.writeObjectField("timeSeriesHistogram", List.of(applicationTimeHistogram.createLoadChartView(), applicationTimeHistogram.createLoadStatisticsChartView())); + } else { + List sourceApplicationTimeSeriesHistogram = link.getLinkApplicationTimeSeriesHistogram(); + jgen.writeFieldName("timeSeriesHistogram"); + jgen.writeObject(sourceApplicationTimeSeriesHistogram); + } } private void writeAgentResponseStatistics(String fieldName, AgentHistogramList agentHistogramList, JsonGenerator jgen) throws IOException { @@ -168,9 +175,13 @@ private void writeAgentHistogram(String fieldName, AgentHistogramList agentHisto } private void writeSourceAgentTimeSeriesHistogram(Link link, JsonGenerator jgen) throws IOException { - AgentResponseTimeViewModelList sourceAgentTimeSeriesHistogram = link.getSourceAgentTimeSeriesHistogram(); - sourceAgentTimeSeriesHistogram.setFieldName("sourceTimeSeriesHistogram"); - jgen.writeObject(sourceAgentTimeSeriesHistogram); + if (link.getTimeHistogramFormat() == TimeHistogramFormat.V3) { + jgen.writeObjectField("sourceTimeSeriesHistogram", link.getSourceAgentTimeSeriesView()); + } else { + AgentResponseTimeViewModelList sourceAgentTimeSeriesHistogram = link.getSourceAgentTimeSeriesHistogram(); + sourceAgentTimeSeriesHistogram.setFieldName("sourceTimeSeriesHistogram"); + jgen.writeObject(sourceAgentTimeSeriesHistogram); + } } private void writeSimpleNode(String fieldName, Node node, JsonGenerator jgen) throws IOException { diff --git a/web/src/main/java/com/navercorp/pinpoint/web/view/NodeHistogramSummarySerializer.java b/web/src/main/java/com/navercorp/pinpoint/web/view/NodeHistogramSummarySerializer.java index 736e0565971c7..cf2d11466611b 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/view/NodeHistogramSummarySerializer.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/view/NodeHistogramSummarySerializer.java @@ -22,6 +22,7 @@ import com.fasterxml.jackson.databind.SerializerProvider; import com.navercorp.pinpoint.web.applicationmap.histogram.Histogram; import com.navercorp.pinpoint.web.applicationmap.histogram.NodeHistogram; +import com.navercorp.pinpoint.web.applicationmap.histogram.TimeHistogramFormat; import com.navercorp.pinpoint.web.applicationmap.nodes.NodeHistogramSummary; import com.navercorp.pinpoint.web.applicationmap.nodes.ServerGroupList; import com.navercorp.pinpoint.web.vo.ResponseTimeStatics; @@ -68,15 +69,19 @@ private void writeHistogram(JsonGenerator jgen, NodeHistogramSummary nodeHistogr jgen.writeObjectField(ResponseTimeStatics.AGENT_RESPONSE_STATISTICS, nodeHistogram.getAgentResponseStatisticsMap()); } - List applicationTimeSeriesHistogram = nodeHistogram.getApplicationTimeHistogram(nodeHistogramSummary.getTimeHistogramFormat()); - if (applicationTimeSeriesHistogram == null) { - writeEmptyArray(jgen, "timeSeriesHistogram"); + if (nodeHistogramSummary.getTimeHistogramFormat() == TimeHistogramFormat.V3) { + jgen.writeObjectField("timeSeriesHistogram", List.of(nodeHistogram.getApplicationLoadChartView(), nodeHistogram.getApplicationLoadStatisticsChartView())); + jgen.writeObjectField("agentTimeSeriesHistogram", nodeHistogram.getAgentTimeSeriesView()); } else { - jgen.writeObjectField("timeSeriesHistogram", applicationTimeSeriesHistogram); + List applicationTimeSeriesHistogram = nodeHistogram.getApplicationTimeHistogram(nodeHistogramSummary.getTimeHistogramFormat()); + if (applicationTimeSeriesHistogram == null) { + writeEmptyArray(jgen, "timeSeriesHistogram"); + } else { + jgen.writeObjectField("timeSeriesHistogram", applicationTimeSeriesHistogram); + } + AgentResponseTimeViewModelList agentTimeSeriesHistogram = nodeHistogram.getAgentTimeHistogram(nodeHistogramSummary.getTimeHistogramFormat()); + jgen.writeObject(agentTimeSeriesHistogram); } - - AgentResponseTimeViewModelList agentTimeSeriesHistogram = nodeHistogram.getAgentTimeHistogram(nodeHistogramSummary.getTimeHistogramFormat()); - jgen.writeObject(agentTimeSeriesHistogram); } private void writeEmptyArray(JsonGenerator jgen, String fieldName) throws IOException { diff --git a/web/src/main/java/com/navercorp/pinpoint/web/view/NodeSerializer.java b/web/src/main/java/com/navercorp/pinpoint/web/view/NodeSerializer.java index 2db6c7e437ea4..98bab3db23ccc 100644 --- a/web/src/main/java/com/navercorp/pinpoint/web/view/NodeSerializer.java +++ b/web/src/main/java/com/navercorp/pinpoint/web/view/NodeSerializer.java @@ -23,6 +23,7 @@ import com.navercorp.pinpoint.common.trace.ServiceType; import com.navercorp.pinpoint.web.applicationmap.histogram.Histogram; import com.navercorp.pinpoint.web.applicationmap.histogram.NodeHistogram; +import com.navercorp.pinpoint.web.applicationmap.histogram.TimeHistogramFormat; import com.navercorp.pinpoint.web.applicationmap.nodes.Node; import com.navercorp.pinpoint.web.applicationmap.nodes.NodeType; import com.navercorp.pinpoint.web.applicationmap.nodes.ServerGroupList; @@ -170,16 +171,24 @@ private void writeHistogram(Node node, JsonGenerator jgen, SerializerProvider pr } // FIXME isn't this all ServiceTypes that can be a node? if (serviceType.isWas() || serviceType.isUser() || serviceType.isTerminal() || serviceType.isUnknown() || serviceType.isQueue() || serviceType.isAlias()) { - List applicationTimeSeriesHistogram = nodeHistogram.getApplicationTimeHistogram(node.getTimeHistogramFormat()); - if (applicationTimeSeriesHistogram == null) { - writeEmptyArray(jgen, "timeSeriesHistogram"); + + if (node.getTimeHistogramFormat() == TimeHistogramFormat.V3) { + jgen.writeObjectField("timeSeriesHistogram", List.of(nodeHistogram.getApplicationLoadChartView(), nodeHistogram.getApplicationLoadStatisticsChartView())); + if (NodeType.DETAILED == node.getNodeType()) { + jgen.writeObjectField("agentTimeSeriesHistogram", nodeHistogram.getAgentTimeSeriesView()); + } } else { - jgen.writeObjectField("timeSeriesHistogram", applicationTimeSeriesHistogram); - } + List applicationTimeSeriesHistogram = nodeHistogram.getApplicationTimeHistogram(node.getTimeHistogramFormat()); + if (applicationTimeSeriesHistogram == null) { + writeEmptyArray(jgen, "timeSeriesHistogram"); + } else { + jgen.writeObjectField("timeSeriesHistogram", applicationTimeSeriesHistogram); + } - if (NodeType.DETAILED == node.getNodeType()) { - AgentResponseTimeViewModelList agentTimeSeriesHistogram = nodeHistogram.getAgentTimeHistogram(node.getTimeHistogramFormat()); - jgen.writeObject(agentTimeSeriesHistogram); + if (NodeType.DETAILED == node.getNodeType()) { + AgentResponseTimeViewModelList agentTimeSeriesHistogram = nodeHistogram.getAgentTimeHistogram(node.getTimeHistogramFormat()); + jgen.writeObject(agentTimeSeriesHistogram); + } } } } diff --git a/web/src/main/java/com/navercorp/pinpoint/web/view/time/LoadChartView.java b/web/src/main/java/com/navercorp/pinpoint/web/view/time/LoadChartView.java new file mode 100644 index 0000000000000..e66c9518675c0 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/view/time/LoadChartView.java @@ -0,0 +1,78 @@ +package com.navercorp.pinpoint.web.view.time; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.navercorp.pinpoint.common.trace.HistogramSchema; +import com.navercorp.pinpoint.web.applicationmap.histogram.Histogram; +import com.navercorp.pinpoint.web.applicationmap.histogram.TimeHistogram; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class LoadChartView implements TimeHistogramView { + private final List timestamp; + private final List metricValues; + + public LoadChartView(HistogramSchema schema, List histogramList) { + Objects.requireNonNull(schema, "schema"); + Objects.requireNonNull(histogramList, "histogramList"); + this.timestamp = TimeHistogramView.getTimeStampList(histogramList); + this.metricValues = createMetricValues(schema, histogramList); + } + + private static List createMetricValues(HistogramSchema schema, List histogramList) { + List metricValueList = new ArrayList<>(5); + metricValueList.add(new LoadChartValue(schema.getFastSlot().getSlotName(), TimeHistogramView.getValueList(histogramList, Histogram::getFastCount))); + metricValueList.add(new LoadChartValue(schema.getNormalSlot().getSlotName(), TimeHistogramView.getValueList(histogramList, Histogram::getNormalCount))); + metricValueList.add(new LoadChartValue(schema.getSlowSlot().getSlotName(), TimeHistogramView.getValueList(histogramList, Histogram::getSlowCount))); + metricValueList.add(new LoadChartValue(schema.getVerySlowSlot().getSlotName(), TimeHistogramView.getValueList(histogramList, Histogram::getVerySlowCount))); + metricValueList.add(new LoadChartValue(schema.getErrorSlot().getSlotName(), TimeHistogramView.getValueList(histogramList, Histogram::getErrorCount))); + return metricValueList; + } + + @Override + public String getTitle() { + return "Load"; + } + + @Override + public String getUnit() { + return "count"; + } + + @Override + public List getTimestamp() { + return timestamp; + } + + @Override + public List getMetricValues() { + return metricValues; + } + + public static class LoadChartValue implements TimeHistogramValueView { + private final String fieldName; + private final List valueList; + + public LoadChartValue(String fieldName, List valueList) { + this.fieldName = Objects.requireNonNull(fieldName, "fieldName"); + this.valueList = Objects.requireNonNull(valueList, "valueList"); + } + + @Override + public String getFieldName() { + return fieldName; + } + + @Override + @JsonInclude(JsonInclude.Include.NON_NULL) + public List getTags() { + return null; + } + + @Override + public List getValues() { + return valueList; + } + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/view/time/LoadStatsticsChartView.java b/web/src/main/java/com/navercorp/pinpoint/web/view/time/LoadStatsticsChartView.java new file mode 100644 index 0000000000000..2d4ae7fc9d5d9 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/view/time/LoadStatsticsChartView.java @@ -0,0 +1,74 @@ +package com.navercorp.pinpoint.web.view.time; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.navercorp.pinpoint.web.applicationmap.histogram.Histogram; +import com.navercorp.pinpoint.web.applicationmap.histogram.TimeHistogram; +import com.navercorp.pinpoint.web.vo.ResponseTimeStatics; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class LoadStatsticsChartView implements TimeHistogramView { + private final List timestamp; + private final List metricValues; + + public LoadStatsticsChartView(List histogramList) { + Objects.requireNonNull(histogramList, "histogramList"); + this.timestamp = TimeHistogramView.getTimeStampList(histogramList); + metricValues = createMetricValues(histogramList); + } + + private static List createMetricValues(List histogramList) { + List metricValues = new ArrayList<>(2); + metricValues.add(new LoadStatisticsChartValue(ResponseTimeStatics.AVG_ELAPSED_TIME, TimeHistogramView.getValueList(histogramList, Histogram::getAvgElapsed))); + metricValues.add(new LoadStatisticsChartValue(ResponseTimeStatics.MAX_ELAPSED_TIME, TimeHistogramView.getValueList(histogramList, Histogram::getMaxElapsed))); + return metricValues; + } + + @Override + public String getTitle() { + return "Load Avg & Max"; + } + + @Override + public String getUnit() { + return "ms"; + } + + @Override + public List getTimestamp() { + return timestamp; + } + + @Override + public List getMetricValues() { + return metricValues; + } + + public static class LoadStatisticsChartValue implements TimeHistogramValueView { + private final String fieldName; + private final List valueList; + + public LoadStatisticsChartValue(String fieldName, List valueList) { + this.fieldName = Objects.requireNonNull(fieldName, "fieldName"); + this.valueList = Objects.requireNonNull(valueList, "valueList"); + } + + @Override + public String getFieldName() { + return fieldName; + } + + @Override + @JsonInclude(JsonInclude.Include.NON_NULL) + public List getTags() { + return null; + } + + @Override + public List getValues() { + return valueList; + } + } +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/view/time/TimeHistogramValueView.java b/web/src/main/java/com/navercorp/pinpoint/web/view/time/TimeHistogramValueView.java new file mode 100644 index 0000000000000..e6df36bcaae67 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/view/time/TimeHistogramValueView.java @@ -0,0 +1,26 @@ +/* + * Copyright 2023 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.web.view.time; + +import java.util.List; + +public interface TimeHistogramValueView { + String getFieldName(); + + List getTags(); + + List getValues(); +} diff --git a/web/src/main/java/com/navercorp/pinpoint/web/view/time/TimeHistogramView.java b/web/src/main/java/com/navercorp/pinpoint/web/view/time/TimeHistogramView.java new file mode 100644 index 0000000000000..f7998d2bec393 --- /dev/null +++ b/web/src/main/java/com/navercorp/pinpoint/web/view/time/TimeHistogramView.java @@ -0,0 +1,45 @@ +/* + * Copyright 2023 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.web.view.time; + +import com.navercorp.pinpoint.web.applicationmap.histogram.TimeHistogram; + +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + +public interface TimeHistogramView { + String getTitle(); + + String getUnit(); + + List getTimestamp(); + + List getMetricValues(); + + static List getTimeStampList(List histogramList) { + return histogramList.stream() + .map(TimeHistogram::getTimeStamp) + .collect(Collectors.toList()); + } + + static List getValueList(List histogramList, Function function) { + return histogramList + .stream() + .map(function) + .collect(Collectors.toList()); + } +} diff --git a/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/histogram/ApplicationTimeHistogramTest.java b/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/histogram/ApplicationTimeHistogramTest.java index 7d95f0546f05c..66e7cda518311 100644 --- a/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/histogram/ApplicationTimeHistogramTest.java +++ b/web/src/test/java/com/navercorp/pinpoint/web/applicationmap/histogram/ApplicationTimeHistogramTest.java @@ -21,10 +21,12 @@ import com.navercorp.pinpoint.common.server.util.time.Range; import com.navercorp.pinpoint.common.trace.ServiceType; import com.navercorp.pinpoint.web.view.TimeViewModel; +import com.navercorp.pinpoint.web.view.time.TimeHistogramView; import com.navercorp.pinpoint.web.vo.Application; import com.navercorp.pinpoint.web.vo.ResponseTime; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import java.io.IOException; @@ -84,4 +86,17 @@ public void testLoadViewModel() { List viewModelList = histogram.createViewModel(TimeHistogramFormat.V2); logger.debug("{}", viewModelList); } + + @Test + public void createTimeSeriesViewTest() { + Application app = new Application("testApplicationName", ServiceType.STAND_ALONE); + ApplicationTimeHistogramBuilder builder = new ApplicationTimeHistogramBuilder(app, Range.between(0, 10 * 6000)); + List responseHistogramList = createResponseTime(app); + ApplicationTimeHistogram histogram = builder.build(responseHistogramList); + + TimeHistogramView timeSeriesView = histogram.createLoadChartView(); + + Assertions.assertEquals("Load", timeSeriesView.getTitle()); + Assertions.assertEquals("count", timeSeriesView.getUnit()); + } }