diff --git a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/controller/ExceptionTraceController.java b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/controller/ExceptionTraceController.java index e48a35b1989a..2b4fdf0a8dd9 100644 --- a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/controller/ExceptionTraceController.java +++ b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/controller/ExceptionTraceController.java @@ -18,6 +18,8 @@ import com.navercorp.pinpoint.common.server.util.time.Range; import com.navercorp.pinpoint.common.server.util.time.RangeValidator; +import com.navercorp.pinpoint.exceptiontrace.web.mapper.ExceptionEntityMapper; +import com.navercorp.pinpoint.exceptiontrace.web.mapper.ExceptionModelMapper; import com.navercorp.pinpoint.exceptiontrace.web.model.ExceptionGroupSummary; import com.navercorp.pinpoint.exceptiontrace.web.view.ExceptionChartValueView; import com.navercorp.pinpoint.exceptiontrace.web.service.ExceptionTraceService; @@ -29,6 +31,7 @@ import com.navercorp.pinpoint.common.server.util.timewindow.TimeWindow; import com.navercorp.pinpoint.common.server.util.timewindow.TimeWindowSampler; import com.navercorp.pinpoint.common.server.util.timewindow.TimeWindowSlotCentricSampler; +import com.navercorp.pinpoint.exceptiontrace.web.view.ExceptionGroupSummaryView; import com.navercorp.pinpoint.metric.web.util.TimePrecision; import com.navercorp.pinpoint.pinot.tenant.TenantProvider; import jakarta.validation.constraints.NotBlank; @@ -70,14 +73,19 @@ public class ExceptionTraceController { @Value("${pinpoint.modules.web.exceptiontrace.table:exceptionTrace}") private String tableName; + private final ExceptionModelMapper mapper; + + public ExceptionTraceController( ExceptionTraceService exceptionTraceService, TenantProvider tenantProvider, - @Qualifier("rangeValidator7d") RangeValidator rangeValidator + @Qualifier("rangeValidator7d") RangeValidator rangeValidator, + ExceptionModelMapper mapper ) { this.exceptionTraceService = Objects.requireNonNull(exceptionTraceService, "exceptionTraceService"); this.tenantProvider = Objects.requireNonNull(tenantProvider, "tenantProvider"); this.rangeValidator = Objects.requireNonNull(rangeValidator, "rangeValidator"); + this.mapper = Objects.requireNonNull(mapper, "mapper"); } @GetMapping("/transactionInfo") @@ -135,7 +143,7 @@ public List getListOfExceptionMetaDataByGivenRange( } @GetMapping("/errorList/groupBy") - public List getListOfExceptionMetaDataWithDynamicGroupBy( + public List getListOfExceptionMetaDataWithDynamicGroupBy( @RequestParam("applicationName") @NotBlank String applicationName, @RequestParam(value = "agentId", required = false) String agentId, @RequestParam("from") @PositiveOrZero long from, @@ -159,7 +167,9 @@ public List getListOfExceptionMetaDataWithDynamicGroupBy( .build(); return exceptionTraceService.getGroupSummaries( queryParameter - ); + ).stream().map( + (ExceptionGroupSummary e) -> mapper.toSummaryView(e, timeWindow) + ).toList(); } @GetMapping("/chart") diff --git a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/mapper/ExceptionEntityMapper.java b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/mapper/ExceptionEntityMapper.java index f43a2d9e773f..5859fa6748e3 100644 --- a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/mapper/ExceptionEntityMapper.java +++ b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/mapper/ExceptionEntityMapper.java @@ -16,6 +16,7 @@ package com.navercorp.pinpoint.exceptiontrace.web.mapper; import com.navercorp.pinpoint.common.server.mapper.MapStructUtils; +import com.navercorp.pinpoint.common.server.util.timewindow.TimeWindow; import com.navercorp.pinpoint.common.util.StringUtils; import com.navercorp.pinpoint.exceptiontrace.common.model.ExceptionMetaData; import com.navercorp.pinpoint.exceptiontrace.web.entity.ExceptionChartValueViewEntity; @@ -27,8 +28,11 @@ import com.navercorp.pinpoint.exceptiontrace.web.model.GroupedFieldName; import com.navercorp.pinpoint.exceptiontrace.web.model.params.GroupFilterParams; import com.navercorp.pinpoint.exceptiontrace.web.util.GroupByAttributes; +import com.navercorp.pinpoint.exceptiontrace.web.util.TimeSeriesUtils; import com.navercorp.pinpoint.exceptiontrace.web.view.ExceptionChartValueView; +import com.navercorp.pinpoint.exceptiontrace.web.view.ExceptionChartView; import com.navercorp.pinpoint.exceptiontrace.web.view.ExceptionDetailView; +import com.navercorp.pinpoint.exceptiontrace.web.view.ExceptionGroupSummaryView; import org.mapstruct.AfterMapping; import org.mapstruct.CollectionMappingStrategy; import org.mapstruct.InjectionStrategy; @@ -68,6 +72,8 @@ public interface ExceptionEntityMapper { ExceptionDetailView toDetailView(ExceptionMetaDataEntity entity); @Mappings({ + @Mapping(target = "groupedFieldName", ignore = true), + @Mapping(target = "groupFilterParams", ignore = true), @Mapping(source = "entity.values", target = "values", qualifiedBy = MapStructUtils.JsonStrToList.class), @Mapping(target = "tags", ignore = true), }) diff --git a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/mapper/ExceptionModelMapper.java b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/mapper/ExceptionModelMapper.java new file mode 100644 index 000000000000..6a816716b46e --- /dev/null +++ b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/mapper/ExceptionModelMapper.java @@ -0,0 +1,71 @@ +/* + * Copyright 2024 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.exceptiontrace.web.mapper; + +import com.navercorp.pinpoint.common.server.mapper.MapStructUtils; +import com.navercorp.pinpoint.common.server.util.timewindow.TimeWindow; +import com.navercorp.pinpoint.exceptiontrace.web.model.ExceptionGroupSummary; +import com.navercorp.pinpoint.exceptiontrace.web.model.GroupedFieldName; +import com.navercorp.pinpoint.exceptiontrace.web.model.params.GroupFilterParams; +import com.navercorp.pinpoint.exceptiontrace.web.util.TimeSeriesUtils; +import com.navercorp.pinpoint.exceptiontrace.web.view.ExceptionChartValueView; +import com.navercorp.pinpoint.exceptiontrace.web.view.ExceptionChartView; +import com.navercorp.pinpoint.exceptiontrace.web.view.ExceptionGroupSummaryView; +import org.mapstruct.AfterMapping; +import org.mapstruct.CollectionMappingStrategy; +import org.mapstruct.InjectionStrategy; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.MappingTarget; +import org.mapstruct.Mappings; +import org.mapstruct.Named; + +import java.util.List; + +/** + * @author intr3p1d + */ +@Mapper( + componentModel = "spring", + injectionStrategy = InjectionStrategy.CONSTRUCTOR, + uses = { + } +) +public interface ExceptionModelMapper { + + @Mappings({ + @Mapping(target = "chart", ignore = true), + }) + ExceptionGroupSummaryView toSummaryView ( + ExceptionGroupSummary summary, + TimeWindow timeWindow + ); + + @AfterMapping + default void addChartView( + ExceptionGroupSummary summary, + TimeWindow timeWindow, + @MappingTarget ExceptionGroupSummaryView summaryView + ) { + ExceptionChartValueView exceptionChartValueView = new ExceptionChartValueView(summary.getValues()); + exceptionChartValueView.setGroupedFieldName(summary.getGroupedFieldName()); + + summaryView.setChart(TimeSeriesUtils.newChartView( + "summary", timeWindow, + List.of(exceptionChartValueView) + )); + } +} diff --git a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/model/ExceptionGroupSummary.java b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/model/ExceptionGroupSummary.java index 91e5f644ed40..f06c40cc52e8 100644 --- a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/model/ExceptionGroupSummary.java +++ b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/model/ExceptionGroupSummary.java @@ -62,10 +62,12 @@ public void setCount(long count) { } @JsonProperty("fieldName") + @Override public GroupedFieldName getGroupedFieldName() { return groupedFieldName; } + @Override public void setGroupedFieldName(GroupedFieldName groupedFieldName) { this.groupedFieldName = groupedFieldName; } @@ -145,6 +147,8 @@ public String toString() { ", groupFilterParams=" + groupFilterParams + ", mostRecentErrorClass='" + mostRecentErrorClass + '\'' + ", mostRecentErrorMessage='" + mostRecentErrorMessage + '\'' + + ", firstLineOfClassName='" + firstLineOfClassName + '\'' + + ", firstLineOfMethodName='" + firstLineOfMethodName + '\'' + ", firstOccurred=" + firstOccurred + ", lastOccurred=" + lastOccurred + ", lastTransactionSearchParams=" + lastTransactionSearchParams + diff --git a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/view/ExceptionGroupSummaryView.java b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/view/ExceptionGroupSummaryView.java new file mode 100644 index 000000000000..f7f50767fa3e --- /dev/null +++ b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/view/ExceptionGroupSummaryView.java @@ -0,0 +1,134 @@ +/* + * Copyright 2024 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.exceptiontrace.web.view; + +import com.navercorp.pinpoint.exceptiontrace.web.model.GroupedFieldName; +import com.navercorp.pinpoint.exceptiontrace.web.model.params.GroupFilterParams; +import com.navercorp.pinpoint.exceptiontrace.web.model.params.TransactionSearchParams; + + +/** + * @author intr3p1d + */ +public class ExceptionGroupSummaryView { + + private ExceptionChartView chart; + private long count; + + private GroupedFieldName groupedFieldName; + private GroupFilterParams groupFilterParams; + + private String mostRecentErrorClass; + private String mostRecentErrorMessage; + private String firstLineOfClassName; + private String firstLineOfMethodName; + private long firstOccurred; + private long lastOccurred; + + private TransactionSearchParams lastTransactionSearchParams; + + + public ExceptionGroupSummaryView() { + } + + public ExceptionChartView getChart() { + return chart; + } + + public void setChart(ExceptionChartView chart) { + this.chart = chart; + } + + public long getCount() { + return count; + } + + public void setCount(long count) { + this.count = count; + } + + public GroupedFieldName getGroupedFieldName() { + return groupedFieldName; + } + + public void setGroupedFieldName(GroupedFieldName groupedFieldName) { + this.groupedFieldName = groupedFieldName; + } + + public GroupFilterParams getGroupFilterParams() { + return groupFilterParams; + } + + public void setGroupFilterParams(GroupFilterParams groupFilterParams) { + this.groupFilterParams = groupFilterParams; + } + + public String getMostRecentErrorClass() { + return mostRecentErrorClass; + } + + public void setMostRecentErrorClass(String mostRecentErrorClass) { + this.mostRecentErrorClass = mostRecentErrorClass; + } + + public String getMostRecentErrorMessage() { + return mostRecentErrorMessage; + } + + public void setMostRecentErrorMessage(String mostRecentErrorMessage) { + this.mostRecentErrorMessage = mostRecentErrorMessage; + } + + public String getFirstLineOfClassName() { + return firstLineOfClassName; + } + + public void setFirstLineOfClassName(String firstLineOfClassName) { + this.firstLineOfClassName = firstLineOfClassName; + } + + public String getFirstLineOfMethodName() { + return firstLineOfMethodName; + } + + public void setFirstLineOfMethodName(String firstLineOfMethodName) { + this.firstLineOfMethodName = firstLineOfMethodName; + } + + public long getFirstOccurred() { + return firstOccurred; + } + + public void setFirstOccurred(long firstOccurred) { + this.firstOccurred = firstOccurred; + } + + public long getLastOccurred() { + return lastOccurred; + } + + public void setLastOccurred(long lastOccurred) { + this.lastOccurred = lastOccurred; + } + + public TransactionSearchParams getLastTransactionSearchParams() { + return lastTransactionSearchParams; + } + + public void setLastTransactionSearchParams(TransactionSearchParams lastTransactionSearchParams) { + this.lastTransactionSearchParams = lastTransactionSearchParams; + } +}