From 237e613fa23b8c3e35e64537def3508cc7322468 Mon Sep 17 00:00:00 2001 From: Seoyoung Park Date: Fri, 7 Jun 2024 14:46:38 +0900 Subject: [PATCH] [#9631] Add API to retrieve CLP replaced tokens with count and ordering --- .../common/pinot/PinotFunctions.java | 34 +++++ exceptiontrace/exceptiontrace-web/pom.xml | 9 ++ .../config/ExceptionTraceRegistryHandler.java | 6 +- .../controller/ExceptionTraceController.java | 35 +++++- .../web/dao/ExceptionTraceDao.java | 5 +- .../web/dao/PinotExceptionTraceDao.java | 15 ++- .../web/entity/ClpConvertedEntity.java | 44 +++++++ .../exceptiontrace/web/mapper/CLPMapper.java | 81 ++++++++++-- .../mapper/ExceptionMetaDataEntityMapper.java | 54 ++++++-- .../web/model/ClpConverted.java | 47 +++++++ .../web/query/ClpQueryParameter.java | 117 ++++++++++++++++++ .../ExceptionTraceQueryParameter.java | 8 +- .../web/service/ExceptionTraceService.java | 6 +- .../service/ExceptionTraceServiceImpl.java | 13 +- .../web/util/ClpReplacedColumns.java | 57 +++++++++ .../mapper/ExceptionTraceMapper.xml | 64 +++++++--- .../web/mapper/CLPMapperTest.java | 12 +- 17 files changed, 555 insertions(+), 52 deletions(-) create mode 100644 exceptiontrace/exceptiontrace-common/src/main/java/com/navercorp/pinpoint/exceptiontrace/common/pinot/PinotFunctions.java create mode 100644 exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/entity/ClpConvertedEntity.java create mode 100644 exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/model/ClpConverted.java create mode 100644 exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/query/ClpQueryParameter.java rename exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/{util => query}/ExceptionTraceQueryParameter.java (96%) create mode 100644 exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/util/ClpReplacedColumns.java diff --git a/exceptiontrace/exceptiontrace-common/src/main/java/com/navercorp/pinpoint/exceptiontrace/common/pinot/PinotFunctions.java b/exceptiontrace/exceptiontrace-common/src/main/java/com/navercorp/pinpoint/exceptiontrace/common/pinot/PinotFunctions.java new file mode 100644 index 0000000000000..d2d35af12f17b --- /dev/null +++ b/exceptiontrace/exceptiontrace-common/src/main/java/com/navercorp/pinpoint/exceptiontrace/common/pinot/PinotFunctions.java @@ -0,0 +1,34 @@ +/* + * 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.common.pinot; + +/** + * @author intr3p1d + */ +public enum PinotFunctions { + ARRAY_SLICE_INT("arraySliceInt"), + ARRAY_SLICE_STRING("arraySliceString"); + + private final String name; + + PinotFunctions(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/exceptiontrace/exceptiontrace-web/pom.xml b/exceptiontrace/exceptiontrace-web/pom.xml index 7b279ecd67c29..095155f79ab28 100644 --- a/exceptiontrace/exceptiontrace-web/pom.xml +++ b/exceptiontrace/exceptiontrace-web/pom.xml @@ -29,6 +29,15 @@ com.navercorp.pinpoint pinpoint-exceptiontrace-common + + org.apache.commons + commons-text + 1.10.0 + + + org.apache.commons + commons-lang3 + org.mapstruct mapstruct diff --git a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/config/ExceptionTraceRegistryHandler.java b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/config/ExceptionTraceRegistryHandler.java index 480543c5e0d47..a50cb83519abd 100644 --- a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/config/ExceptionTraceRegistryHandler.java +++ b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/config/ExceptionTraceRegistryHandler.java @@ -15,11 +15,13 @@ */ package com.navercorp.pinpoint.exceptiontrace.web.config; +import com.navercorp.pinpoint.exceptiontrace.web.entity.ClpConvertedEntity; import com.navercorp.pinpoint.exceptiontrace.web.entity.ExceptionMetaDataEntity; import com.navercorp.pinpoint.exceptiontrace.web.entity.ExceptionTraceSummaryEntity; import com.navercorp.pinpoint.exceptiontrace.web.entity.ExceptionTraceValueViewEntity; import com.navercorp.pinpoint.exceptiontrace.web.entity.GroupedFieldNameEntity; -import com.navercorp.pinpoint.exceptiontrace.web.util.ExceptionTraceQueryParameter; +import com.navercorp.pinpoint.exceptiontrace.web.query.ClpQueryParameter; +import com.navercorp.pinpoint.exceptiontrace.web.query.ExceptionTraceQueryParameter; import com.navercorp.pinpoint.mybatis.MyBatisRegistryHandler; import org.apache.ibatis.type.TypeAliasRegistry; import org.apache.ibatis.type.TypeHandlerRegistry; @@ -34,7 +36,9 @@ public void registerTypeAlias(TypeAliasRegistry typeAliasRegistry) { typeAliasRegistry.registerAlias(GroupedFieldNameEntity.class); typeAliasRegistry.registerAlias(ExceptionTraceSummaryEntity.class); typeAliasRegistry.registerAlias(ExceptionTraceValueViewEntity.class); + typeAliasRegistry.registerAlias(ClpConvertedEntity.class); typeAliasRegistry.registerAlias(ExceptionTraceQueryParameter.class); + typeAliasRegistry.registerAlias(ClpQueryParameter.class); } @Override 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 667820af3a038..95c1a891f97cc 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,10 +18,12 @@ import com.navercorp.pinpoint.common.server.util.time.Range; import com.navercorp.pinpoint.common.server.util.time.RangeValidator; +import com.navercorp.pinpoint.exceptiontrace.web.model.ClpConverted; import com.navercorp.pinpoint.exceptiontrace.web.model.ExceptionTraceSummary; import com.navercorp.pinpoint.exceptiontrace.web.model.ExceptionTraceValueView; +import com.navercorp.pinpoint.exceptiontrace.web.query.ClpQueryParameter; import com.navercorp.pinpoint.exceptiontrace.web.service.ExceptionTraceService; -import com.navercorp.pinpoint.exceptiontrace.web.util.ExceptionTraceQueryParameter; +import com.navercorp.pinpoint.exceptiontrace.web.query.ExceptionTraceQueryParameter; import com.navercorp.pinpoint.exceptiontrace.web.util.GroupByAttributes; import com.navercorp.pinpoint.exceptiontrace.web.view.ExceptionMetaDataView; import com.navercorp.pinpoint.exceptiontrace.web.view.ExceptionTraceView; @@ -159,6 +161,37 @@ public List getListOfExceptionMetaDataWithDynamicGroupBy( ); } + @GetMapping("/replacedTokens") + public List getReplacedVariables( + @RequestParam("applicationName") @NotBlank String applicationName, + @RequestParam(value = "agentId", required = false) String agentId, + @RequestParam("from") @PositiveOrZero long from, + @RequestParam("to") @PositiveOrZero long to, + + @RequestParam("logType") String logType, + @RequestParam("targetColumn") String targetColumn, + @RequestParam("targetIndex") int targetIndex + ) { + Range range = Range.between(from, to); + rangeValidator.validate(range); + + ClpQueryParameter queryParameter = new ClpQueryParameter.Builder() + .setTableName(tableName) + .setTenantId(tenantProvider.getTenantId()) + .setApplicationName(applicationName) + .setAgentId(agentId) + .setRange(Range.between(from, to)) + .setTimePrecision(DETAILED_TIME_PRECISION) + .setLogType(logType) + .setTargetColumn(targetColumn) + .setTargetIndex(targetIndex) + .build(); + + return exceptionTraceService.getReplacedVariables( + queryParameter + ); + } + @GetMapping("/chart") public ExceptionTraceView getCollectedExceptionMetaDataByGivenRange( @RequestParam("applicationName") @NotBlank String applicationName, diff --git a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/dao/ExceptionTraceDao.java b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/dao/ExceptionTraceDao.java index 0ad00a05645dc..04b3d04103a62 100644 --- a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/dao/ExceptionTraceDao.java +++ b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/dao/ExceptionTraceDao.java @@ -18,9 +18,11 @@ import com.navercorp.pinpoint.exceptiontrace.common.model.ExceptionMetaData; +import com.navercorp.pinpoint.exceptiontrace.web.model.ClpConverted; import com.navercorp.pinpoint.exceptiontrace.web.model.ExceptionTraceSummary; import com.navercorp.pinpoint.exceptiontrace.web.model.ExceptionTraceValueView; -import com.navercorp.pinpoint.exceptiontrace.web.util.ExceptionTraceQueryParameter; +import com.navercorp.pinpoint.exceptiontrace.web.query.ClpQueryParameter; +import com.navercorp.pinpoint.exceptiontrace.web.query.ExceptionTraceQueryParameter; import com.navercorp.pinpoint.exceptiontrace.web.view.ExceptionMetaDataView; import java.util.List; @@ -34,4 +36,5 @@ public interface ExceptionTraceDao { ExceptionMetaData getException(ExceptionTraceQueryParameter exceptionTraceQueryParameter); List getSummaries(ExceptionTraceQueryParameter exceptionTraceQueryParameter); List getValueViews(ExceptionTraceQueryParameter exceptionTraceQueryParameter); + List getReplacedVariables(ClpQueryParameter queryParameter); } diff --git a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/dao/PinotExceptionTraceDao.java b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/dao/PinotExceptionTraceDao.java index e8ecc8ec642bc..2d89dc04ad1cf 100644 --- a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/dao/PinotExceptionTraceDao.java +++ b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/dao/PinotExceptionTraceDao.java @@ -17,13 +17,16 @@ package com.navercorp.pinpoint.exceptiontrace.web.dao; import com.navercorp.pinpoint.exceptiontrace.common.model.ExceptionMetaData; +import com.navercorp.pinpoint.exceptiontrace.web.entity.ClpConvertedEntity; import com.navercorp.pinpoint.exceptiontrace.web.entity.ExceptionMetaDataEntity; import com.navercorp.pinpoint.exceptiontrace.web.entity.ExceptionTraceSummaryEntity; import com.navercorp.pinpoint.exceptiontrace.web.entity.ExceptionTraceValueViewEntity; import com.navercorp.pinpoint.exceptiontrace.web.mapper.ExceptionMetaDataEntityMapper; +import com.navercorp.pinpoint.exceptiontrace.web.model.ClpConverted; import com.navercorp.pinpoint.exceptiontrace.web.model.ExceptionTraceSummary; import com.navercorp.pinpoint.exceptiontrace.web.model.ExceptionTraceValueView; -import com.navercorp.pinpoint.exceptiontrace.web.util.ExceptionTraceQueryParameter; +import com.navercorp.pinpoint.exceptiontrace.web.query.ClpQueryParameter; +import com.navercorp.pinpoint.exceptiontrace.web.query.ExceptionTraceQueryParameter; import com.navercorp.pinpoint.exceptiontrace.web.view.ExceptionMetaDataView; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -49,6 +52,7 @@ public class PinotExceptionTraceDao implements ExceptionTraceDao { private static final String SELECT_EXACT_QUERY = "selectExactException"; private static final String SELECT_SUMMARIES_QUERY = "selectSummaries"; private static final String SELECT_VALUEVIEWS_QUERY = "selectValueViews"; + private static final String SELECT_CLP_VARIABLES_QUERY = "selectClpVariables"; private final SqlSessionTemplate sqlPinotSessionTemplate; @@ -105,4 +109,13 @@ public List getValueViews(ExceptionTraceQueryParameter ) ).collect(Collectors.toList()); } + + @Override + public List getReplacedVariables(ClpQueryParameter queryParameter) { + List clpConvertedEntities = this.sqlPinotSessionTemplate.selectList(NAMESPACE + SELECT_CLP_VARIABLES_QUERY, queryParameter); + + return clpConvertedEntities.stream() + .map(mapper::toClpConverted) + .collect(Collectors.toList()); + } } diff --git a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/entity/ClpConvertedEntity.java b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/entity/ClpConvertedEntity.java new file mode 100644 index 0000000000000..a7917d4bda26e --- /dev/null +++ b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/entity/ClpConvertedEntity.java @@ -0,0 +1,44 @@ +/* + * 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.entity; + +/** + * @author intr3p1d + */ +public class ClpConvertedEntity { + + private String replacedToken; + private int count; + + public ClpConvertedEntity() { + } + + public String getReplacedToken() { + return replacedToken; + } + + public void setReplacedToken(String replacedToken) { + this.replacedToken = replacedToken; + } + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + } +} diff --git a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/mapper/CLPMapper.java b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/mapper/CLPMapper.java index 54ab0da7578ca..21f9e22f34d89 100644 --- a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/mapper/CLPMapper.java +++ b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/mapper/CLPMapper.java @@ -15,7 +15,13 @@ */ package com.navercorp.pinpoint.exceptiontrace.web.mapper; + +import org.apache.commons.text.StringEscapeUtils; + import java.nio.charset.StandardCharsets; +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * @author intr3p1d @@ -26,17 +32,76 @@ public class CLPMapper { public final static char DICTIONARY_VARIABLE_VALUE = '\u0011'; public final static char NON_DICTIONARY_VALUE = '\u0012'; - public final static String DICTIONARY_REPLACEMENT = "▨▨▨"; - public final static String NON_DICTIONARY_REPLACEMENT = "▧▧▧"; + public final static String DICTIONARY_REPLACEMENT = ""; + public final static String NON_DICTIONARY_REPLACEMENT = ""; + + public final static String SIMPLE_REPLACEMENT = "▨▨▨"; + + static String fixAndEscapeLogType(String encodedLogType) { + return replaceDictPlaceHolder(replaceNonDictPlaceHolder( + escapeXml(correctEncoding( + encodedLogType + )) + )); + } + + static String processEncodedLogType(String encodedLogType) { + return replaceSimple(correctEncoding( + encodedLogType + )); + } - static String makeReadableString(String encodedLogType) { - byte[] encodedLogTypeBytes = encodedLogType.getBytes(StandardCharsets.ISO_8859_1); + static String correctEncoding(String isoString) { + byte[] encodedLogTypeBytes = isoString.getBytes(StandardCharsets.ISO_8859_1); return new String(encodedLogTypeBytes, StandardCharsets.UTF_8); } - static String replacePlaceHolders(String encodedLogType) { - return encodedLogType - .replaceAll(String.valueOf(DICTIONARY_VARIABLE_VALUE), DICTIONARY_REPLACEMENT) - .replaceAll(String.valueOf(NON_DICTIONARY_VALUE), NON_DICTIONARY_REPLACEMENT); + static String escapeXml(String rawString) { + return StringEscapeUtils.escapeHtml4(rawString); + } + + static String replaceNonDictPlaceHolder(String encodedLogType) { + return replaceHolder( + encodedLogType, + String.valueOf(NON_DICTIONARY_VALUE), + x -> stringFunction(NON_DICTIONARY_REPLACEMENT, x) + ); + } + + static String replaceDictPlaceHolder(String encodedLogType) { + return replaceHolder( + encodedLogType, + String.valueOf(DICTIONARY_VARIABLE_VALUE), + x -> stringFunction(DICTIONARY_REPLACEMENT, x) + ); + } + + static String replaceSimple(String encodedLogType) { + return replaceHolder(replaceHolder( + encodedLogType, + String.valueOf((DICTIONARY_VARIABLE_VALUE)), + x -> stringFunction(SIMPLE_REPLACEMENT, x) + ), + String.valueOf(NON_DICTIONARY_VALUE), + x -> stringFunction(SIMPLE_REPLACEMENT, x) + ); + } + + static String stringFunction(String format, int index) { + return String.format(format, index); + } + + static String replaceHolder(String encodedLogType, String replacedCharacter, Function replacement) { + Pattern pattern = Pattern.compile(replacedCharacter); + Matcher matcher = pattern.matcher(encodedLogType); + StringBuilder result = new StringBuilder(); + int wordCount = 0; + + while (matcher.find()) { + matcher.appendReplacement(result, replacement.apply(wordCount++)); + } + matcher.appendTail(result); + + return result.toString(); } } diff --git a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/mapper/ExceptionMetaDataEntityMapper.java b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/mapper/ExceptionMetaDataEntityMapper.java index 37180f934a953..826d410757cce 100644 --- a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/mapper/ExceptionMetaDataEntityMapper.java +++ b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/mapper/ExceptionMetaDataEntityMapper.java @@ -18,10 +18,12 @@ import com.navercorp.pinpoint.common.server.mapper.MapStructUtils; import com.navercorp.pinpoint.common.util.StringUtils; import com.navercorp.pinpoint.exceptiontrace.common.model.ExceptionMetaData; +import com.navercorp.pinpoint.exceptiontrace.web.entity.ClpConvertedEntity; import com.navercorp.pinpoint.exceptiontrace.web.entity.ExceptionMetaDataEntity; import com.navercorp.pinpoint.exceptiontrace.web.entity.ExceptionTraceSummaryEntity; import com.navercorp.pinpoint.exceptiontrace.web.entity.ExceptionTraceValueViewEntity; import com.navercorp.pinpoint.exceptiontrace.web.entity.GroupedFieldNameEntity; +import com.navercorp.pinpoint.exceptiontrace.web.model.ClpConverted; import com.navercorp.pinpoint.exceptiontrace.web.model.ExceptionTraceSummary; import com.navercorp.pinpoint.exceptiontrace.web.model.ExceptionTraceValueView; import com.navercorp.pinpoint.exceptiontrace.web.model.Grouped; @@ -38,10 +40,12 @@ import org.mapstruct.Mappings; import org.mapstruct.Named; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.List; +import java.util.function.Function; -import static com.navercorp.pinpoint.exceptiontrace.web.mapper.CLPMapper.makeReadableString; -import static com.navercorp.pinpoint.exceptiontrace.web.mapper.CLPMapper.replacePlaceHolders; +import static com.navercorp.pinpoint.exceptiontrace.web.mapper.CLPMapper.fixAndEscapeLogType; /** * @author intr3p1d @@ -58,7 +62,8 @@ public interface ExceptionMetaDataEntityMapper { @Mappings({ - @Mapping(source = ".", target = "stackTrace", qualifiedBy = StackTraceMapper.StringsToStackTrace.class), + @Mapping(source = ".", target = "stackTrac" + + "e", qualifiedBy = StackTraceMapper.StringsToStackTrace.class), }) ExceptionMetaData toModel(ExceptionMetaDataEntity entity); @@ -86,6 +91,11 @@ ExceptionTraceSummary toSummary( List attributesList ); + @Mappings({ + }) + ClpConverted toClpConverted(ClpConvertedEntity entity); + + @AfterMapping default void addRawGroupedFieldName( ExceptionTraceSummaryEntity entity, @@ -98,18 +108,42 @@ default void addRawGroupedFieldName( case STACK_TRACE -> groupedFieldName.setStackTraceHash(checkIfNull(entity.getStackTraceHash())); case URI_TEMPLATE -> groupedFieldName.setUriTemplate(checkIfNull(entity.getUriTemplate())); case ERROR_CLASS_NAME -> groupedFieldName.setErrorClassName(checkIfNull(entity.getErrorClassName())); - case ERROR_MESSAGE_LOG_TYPE -> - groupedFieldName.setErrorMessage_logtype(checkIfNull(entity.getErrorMessage_logtype())); + case ERROR_MESSAGE_LOG_TYPE -> groupedFieldName.setErrorMessage_logtype(checkIfNull( + encode(entity.getErrorMessage_logtype()))); } } summary.setRawFieldName(groupedFieldName); } + @Named("encode") + default String encode(String string) { + return URLEncoder.encode(string, StandardCharsets.UTF_8); + } + @AfterMapping + default void addGroupedFieldNameToSummary( + GroupedFieldNameEntity entity, + List attributesList, + @MappingTarget ExceptionTraceSummary exceptionTraceSummary + ) { + addGroupedFieldName(entity, attributesList, exceptionTraceSummary, CLPMapper::fixAndEscapeLogType); + } + + @AfterMapping + default void addGroupedFieldNameToValueView( + GroupedFieldNameEntity entity, + List attributesList, + @MappingTarget ExceptionTraceValueView exceptionTraceValueView + ) { + addGroupedFieldName(entity, attributesList, exceptionTraceValueView, CLPMapper::processEncodedLogType); + } + + @Named("addGroupedFieldName") default void addGroupedFieldName( GroupedFieldNameEntity entity, List attributesList, - @MappingTarget Grouped grouped + @MappingTarget Grouped grouped, + Function function ) { GroupedFieldName groupedFieldName = new GroupedFieldName(); for (GroupByAttributes attributes : attributesList) { @@ -118,7 +152,9 @@ default void addGroupedFieldName( case URI_TEMPLATE -> groupedFieldName.setUriTemplate(checkIfNull(entity.getUriTemplate())); case ERROR_CLASS_NAME -> groupedFieldName.setErrorClassName(checkIfNull(entity.getErrorClassName())); case ERROR_MESSAGE_LOG_TYPE -> - groupedFieldName.setErrorMessage(checkIfNull(selectErrorMessage(entity))); + groupedFieldName.setErrorMessage(checkIfNull( + function.apply(entity.getErrorMessage_logtype()) + )); } } grouped.setGroupedFieldName(groupedFieldName); @@ -127,9 +163,7 @@ default void addGroupedFieldName( @Named("selectErrorMessage") default String selectErrorMessage(GroupedFieldNameEntity entity) { if (entity.getErrorMessage_logtype() != null) { - return replacePlaceHolders( - makeReadableString(entity.getErrorMessage_logtype()) - ); + return fixAndEscapeLogType(entity.getErrorMessage_logtype()); } return entity.getErrorMessage(); } diff --git a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/model/ClpConverted.java b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/model/ClpConverted.java new file mode 100644 index 0000000000000..478f6e5e95444 --- /dev/null +++ b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/model/ClpConverted.java @@ -0,0 +1,47 @@ +/* + * 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.model; + +import java.util.List; + +/** + * @author intr3p1d + */ +public class ClpConverted { + + private String replacedToken; + private int count; + + + public ClpConverted() { + } + + public String getReplacedToken() { + return replacedToken; + } + + public void setReplacedToken(String replacedToken) { + this.replacedToken = replacedToken; + } + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + } +} diff --git a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/query/ClpQueryParameter.java b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/query/ClpQueryParameter.java new file mode 100644 index 0000000000000..d33aecf7f3c26 --- /dev/null +++ b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/query/ClpQueryParameter.java @@ -0,0 +1,117 @@ +/* + * 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.query; + +import com.navercorp.pinpoint.exceptiontrace.web.util.ClpReplacedColumns; +import com.navercorp.pinpoint.metric.web.util.QueryParameter; + +/** + * @author intr3p1d + */ +public class ClpQueryParameter extends QueryParameter { + + private final String tableName; + private final String tenantId; + private final String applicationName; + private final String agentId; + + private final ClpReplacedColumns targetColumn; + private final int targetIndex; + private final String logType; + + protected ClpQueryParameter(Builder builder) { + super(builder.getRange(), builder.getTimePrecision(), builder.getLimit()); + this.tableName = builder.tableName; + this.tenantId = builder.tenantId; + this.applicationName = builder.applicationName; + this.agentId = builder.agentId; + this.targetColumn = builder.targetColumn; + this.targetIndex = builder.targetIndex; + this.logType = builder.logType; + } + + public static class Builder extends QueryParameter.Builder { + + private String tableName; + private String tenantId; + private String applicationName; + private String agentId; + + private ClpReplacedColumns targetColumn; + private int targetIndex; + private String logType; + + @Override + protected Builder self() { + return this; + } + + + public Builder setTableName(String tableName) { + this.tableName = tableName; + return self(); + } + + public Builder setTenantId(String tenantId) { + this.tenantId = tenantId; + return self(); + } + + public Builder setApplicationName(String applicationName) { + this.applicationName = applicationName; + return self(); + } + + public Builder setAgentId(String agentId) { + this.agentId = agentId; + return self(); + } + + public Builder setTargetColumn(String targetColumn) { + this.targetColumn = ClpReplacedColumns.fromValue(targetColumn); + return self(); + } + + public Builder setTargetIndex(int targetIndex) { + this.targetIndex = targetIndex; + return self(); + } + + public Builder setLogType(String logType) { + this.logType = logType; + return self(); + } + + @Override + public ClpQueryParameter build() { + return new ClpQueryParameter(this); + } + } + + + @Override + public String toString() { + return "ClpQueryParameter{" + + "tableName='" + tableName + '\'' + + ", tenantId='" + tenantId + '\'' + + ", applicationName='" + applicationName + '\'' + + ", agentId='" + agentId + '\'' + + ", targetColumn=" + targetColumn + + ", targetIndex=" + targetIndex + + ", logType='" + logType + '\'' + + '}'; + } +} diff --git a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/util/ExceptionTraceQueryParameter.java b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/query/ExceptionTraceQueryParameter.java similarity index 96% rename from exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/util/ExceptionTraceQueryParameter.java rename to exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/query/ExceptionTraceQueryParameter.java index 24bcb2406ae7c..ebee58631e941 100644 --- a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/util/ExceptionTraceQueryParameter.java +++ b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/query/ExceptionTraceQueryParameter.java @@ -14,13 +14,14 @@ * limitations under the License. */ -package com.navercorp.pinpoint.exceptiontrace.web.util; +package com.navercorp.pinpoint.exceptiontrace.web.query; import com.navercorp.pinpoint.common.util.StringUtils; -import com.navercorp.pinpoint.exceptiontrace.web.ExceptionTraceWebConfig; +import com.navercorp.pinpoint.exceptiontrace.web.util.FilterByAttributes; +import com.navercorp.pinpoint.exceptiontrace.web.util.GroupByAttributes; +import com.navercorp.pinpoint.exceptiontrace.web.util.OrderByAttributes; import com.navercorp.pinpoint.metric.web.util.QueryParameter; import com.navercorp.pinpoint.metric.web.util.TimePrecision; -import org.springframework.beans.factory.annotation.Value; import java.security.InvalidParameterException; import java.util.ArrayList; @@ -28,7 +29,6 @@ import java.util.List; import java.util.Objects; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; /** * @author intr3p1d diff --git a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/service/ExceptionTraceService.java b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/service/ExceptionTraceService.java index c25217898bc4e..ecc7fce80ac25 100644 --- a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/service/ExceptionTraceService.java +++ b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/service/ExceptionTraceService.java @@ -16,9 +16,11 @@ package com.navercorp.pinpoint.exceptiontrace.web.service; +import com.navercorp.pinpoint.exceptiontrace.web.model.ClpConverted; import com.navercorp.pinpoint.exceptiontrace.web.model.ExceptionTraceSummary; import com.navercorp.pinpoint.exceptiontrace.web.model.ExceptionTraceValueView; -import com.navercorp.pinpoint.exceptiontrace.web.util.ExceptionTraceQueryParameter; +import com.navercorp.pinpoint.exceptiontrace.web.query.ClpQueryParameter; +import com.navercorp.pinpoint.exceptiontrace.web.query.ExceptionTraceQueryParameter; import com.navercorp.pinpoint.exceptiontrace.web.view.ExceptionMetaDataView; import java.util.List; @@ -35,4 +37,6 @@ public interface ExceptionTraceService { List getSummaries(ExceptionTraceQueryParameter queryParameter); List getValueViews(ExceptionTraceQueryParameter queryParameter); + + List getReplacedVariables(ClpQueryParameter queryParameter); } diff --git a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/service/ExceptionTraceServiceImpl.java b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/service/ExceptionTraceServiceImpl.java index 05710625d9f5e..0d160e072127d 100644 --- a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/service/ExceptionTraceServiceImpl.java +++ b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/service/ExceptionTraceServiceImpl.java @@ -17,9 +17,11 @@ package com.navercorp.pinpoint.exceptiontrace.web.service; import com.navercorp.pinpoint.exceptiontrace.web.dao.ExceptionTraceDao; +import com.navercorp.pinpoint.exceptiontrace.web.model.ClpConverted; import com.navercorp.pinpoint.exceptiontrace.web.model.ExceptionTraceSummary; import com.navercorp.pinpoint.exceptiontrace.web.model.ExceptionTraceValueView; -import com.navercorp.pinpoint.exceptiontrace.web.util.ExceptionTraceQueryParameter; +import com.navercorp.pinpoint.exceptiontrace.web.query.ClpQueryParameter; +import com.navercorp.pinpoint.exceptiontrace.web.query.ExceptionTraceQueryParameter; import com.navercorp.pinpoint.exceptiontrace.web.view.ExceptionMetaDataView; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -99,4 +101,13 @@ private List getExceptionTraceSummaries(ExceptionTraceQue private List getExceptionTraceValueViews(ExceptionTraceQueryParameter queryParameter) { return exceptionTraceDao.getValueViews(queryParameter); } + + + @Override + public List getReplacedVariables(ClpQueryParameter queryParameter) { + return exceptionTraceDao.getReplacedVariables(queryParameter); + } + + + } diff --git a/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/util/ClpReplacedColumns.java b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/util/ClpReplacedColumns.java new file mode 100644 index 0000000000000..e6781887cfa0b --- /dev/null +++ b/exceptiontrace/exceptiontrace-web/src/main/java/com/navercorp/pinpoint/exceptiontrace/web/util/ClpReplacedColumns.java @@ -0,0 +1,57 @@ +/* + * 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.util; + +import com.navercorp.pinpoint.common.server.util.EnumGetter; +import com.navercorp.pinpoint.exceptiontrace.common.pinot.PinotColumns; +import com.navercorp.pinpoint.exceptiontrace.common.pinot.PinotFunctions; + +/** + * @author intr3p1d + */ +public enum ClpReplacedColumns { + + ERROR_MESSAGE_ENCODED_VARS("non-dict", PinotColumns.ERROR_MESSAGE_ENCODED_VARS, PinotFunctions.ARRAY_SLICE_INT), + ERROR_MESSAGE_DICTIONARY_VARS("dict", PinotColumns.ERROR_MESSAGE_DICTIONARY_VARS, PinotFunctions.ARRAY_SLICE_STRING); + + private static final EnumGetter GETTER = new EnumGetter<>(ClpReplacedColumns.class); + + private final String name; + private final PinotColumns columns; + private final PinotFunctions sliceFunction; + + ClpReplacedColumns(String name, PinotColumns columns, PinotFunctions sliceFunction) { + this.name = name; + this.columns = columns; + this.sliceFunction = sliceFunction; + } + + public String getName() { + return name; + } + + public PinotColumns getColumns() { + return columns; + } + + public PinotFunctions getSliceFunction() { + return sliceFunction; + } + + public static ClpReplacedColumns fromValue(String name) { + return GETTER.fromValue(ClpReplacedColumns::getName, name); + } +} diff --git a/exceptiontrace/exceptiontrace-web/src/main/resources/exceptiontrace/mapper/ExceptionTraceMapper.xml b/exceptiontrace/exceptiontrace-web/src/main/resources/exceptiontrace/mapper/ExceptionTraceMapper.xml index a9826c4e0b5b6..0f451269d3cdd 100644 --- a/exceptiontrace/exceptiontrace-web/src/main/resources/exceptiontrace/mapper/ExceptionTraceMapper.xml +++ b/exceptiontrace/exceptiontrace-web/src/main/resources/exceptiontrace/mapper/ExceptionTraceMapper.xml @@ -10,6 +10,9 @@ + + + ${tableName} @@ -21,7 +24,7 @@ - + AND ${key.column.name}=#{value} @@ -42,7 +45,8 @@ - , + , + @@ -66,7 +70,8 @@ agentId, uriTemplate, errorClassName, - as "errorMessage", + + as "errorMessage", exceptionDepth, stackTraceClassName, stackTraceFileName, @@ -87,7 +92,8 @@ agentId, uriTemplate, errorClassName, - as "errorMessage", + + as "errorMessage", exceptionDepth, stackTraceHash @@ -95,9 +101,9 @@ SELECT - + FROM - + WHERE tenantId = #{tenantId} AND applicationName = #{applicationName} @@ -131,7 +137,7 @@ AND agentId = #{agentId} - + ORDER BY ${orderBy.getAttributeName} ${isDesc} LIMIT ${limit} @@ -139,9 +145,9 @@ SELECT - + LASTWITHTIME(errorClassName, "timestamp", 'STRING') as "mostRecentErrorClass", LASTWITHTIME( - , + , "timestamp", 'STRING') as "mostRecentErrorMessage", count(*) as "count", FIRSTWITHTIME("timestamp", "timestamp", 'LONG') as "firstOccurred", LASTWITHTIME("timestamp", "timestamp", 'LONG') as "lastOccurred" FROM - + WHERE tenantId = #{tenantId} @@ -181,7 +187,7 @@ AND agentId = #{agentId} GROUP BY applicationName - + ORDER BY count(*) desc LIMIT 10 @@ -189,13 +195,13 @@ + + \ No newline at end of file diff --git a/exceptiontrace/exceptiontrace-web/src/test/java/com/navercorp/pinpoint/exceptiontrace/web/mapper/CLPMapperTest.java b/exceptiontrace/exceptiontrace-web/src/test/java/com/navercorp/pinpoint/exceptiontrace/web/mapper/CLPMapperTest.java index e8088dc99bd98..f214c47777e9a 100644 --- a/exceptiontrace/exceptiontrace-web/src/test/java/com/navercorp/pinpoint/exceptiontrace/web/mapper/CLPMapperTest.java +++ b/exceptiontrace/exceptiontrace-web/src/test/java/com/navercorp/pinpoint/exceptiontrace/web/mapper/CLPMapperTest.java @@ -6,8 +6,8 @@ import java.io.IOException; -import static com.navercorp.pinpoint.exceptiontrace.web.mapper.CLPMapper.makeReadableString; -import static com.navercorp.pinpoint.exceptiontrace.web.mapper.CLPMapper.replacePlaceHolders; +import static com.navercorp.pinpoint.exceptiontrace.web.mapper.CLPMapper.correctEncoding; +import static com.navercorp.pinpoint.exceptiontrace.web.mapper.CLPMapper.replaceSimple; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; @@ -23,7 +23,7 @@ public void testEncodedLogtype() { String example = "INFO Task \u0011\u0000 assigned to container: [NodeAddress:\u0011\u0001, ...\n" + "ContainerID:\u0011\u0002], operation took \u0012\u0013 seconds"; - String replaced = replacePlaceHolders(example); + String replaced = replaceSimple(example); logger.info(example); logger.info(replaced); assertNotEquals(example, replaced); @@ -36,7 +36,7 @@ public void testMakeReadable1() throws IOException { String rawExample = "getAgentsList.from: \u0011 ì\u009D´ì\u0083\u0081ì\u009D´ì\u0096´ì\u0095¼ í\u0095©ë\u008B\u0088ë\u008B¤"; String example = "getAgentsList.from: \u0011 이상이어야 합니다"; - assertEquals(example, makeReadableString(rawExample)); + assertEquals(example, correctEncoding(rawExample)); } @Test @@ -44,7 +44,7 @@ public void testMakeReadable2() { String rawExample = "\\n not found: limit=\u0011 content=â\u0080¦"; String example = "\\n not found: limit=\u0011 content=…"; - assertEquals(example, makeReadableString(rawExample)); + assertEquals(example, correctEncoding(rawExample)); } @Test @@ -52,6 +52,6 @@ public void testMakeReadable3() { String rawExample = "Request processing failed: jakarta.validation.ConstraintViolationException"; String example = "Request processing failed: jakarta.validation.ConstraintViolationException"; - assertEquals(example, makeReadableString(rawExample)); + assertEquals(example, correctEncoding(rawExample)); } } \ No newline at end of file