This is an automated email from the ASF dual-hosted git repository. morningman pushed a commit to branch dev-1.1.2 in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/dev-1.1.2 by this push: new 8e1018d1c8 [improvement](profile) add json profile and add session context (#11279) 8e1018d1c8 is described below commit 8e1018d1c8f0b646d8526f4b525a4078ac32cebc Author: miswujian <38979663+miswuj...@users.noreply.github.com> AuthorDate: Thu Jul 28 15:48:00 2022 +0800 [improvement](profile) add json profile and add session context (#11279) 1. Add a new session varible "session_context" 2. support export profile in json format --- .../org/apache/doris/analysis/SchemaTableType.java | 1 + .../org/apache/doris/catalog/PrimitiveType.java | 3 +- .../doris/common/profile/ProfileTreeNode.java | 1 - .../doris/common/profile/ProfileTreePrinter.java | 8 +- .../apache/doris/common/util/ProfileManager.java | 17 ++- .../apache/doris/common/util/RuntimeProfile.java | 2 +- .../apache/doris/httpv2/rest/MetaInfoAction.java | 15 +-- .../httpv2/rest/manager/QueryProfileAction.java | 148 +++++++++++++-------- .../java/org/apache/doris/mysql/MysqlCommand.java | 1 + .../java/org/apache/doris/qe/SessionVariable.java | 42 +++++- .../java/org/apache/doris/qe/StmtExecutor.java | 1 + .../doris/common/util/RuntimeProfileTest.java | 4 +- 12 files changed, 164 insertions(+), 79 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/SchemaTableType.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/SchemaTableType.java index ff3e29d6f6..32fa75c7a8 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/SchemaTableType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/SchemaTableType.java @@ -68,6 +68,7 @@ public enum SchemaTableType { SCH_INVALID("NULL", "NULL", TSchemaTableType.SCH_INVALID); private static final String dbName = "INFORMATION_SCHEMA"; private static SelectList fullSelectLists; + static { fullSelectLists = new SelectList(); fullSelectLists.addItem(SelectListItem.createStarItem(null)); diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/PrimitiveType.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/PrimitiveType.java index cdc0f56980..b61e573f9e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/PrimitiveType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/PrimitiveType.java @@ -70,6 +70,7 @@ public enum PrimitiveType { private static final int DECIMAL_INDEX_LEN = 12; private static ImmutableSetMultimap<PrimitiveType, PrimitiveType> implicitCastMap; + static { ImmutableSetMultimap.Builder<PrimitiveType, PrimitiveType> builder = ImmutableSetMultimap.builder(); // Nulltype @@ -746,7 +747,7 @@ public enum PrimitiveType { case DATETIME: { if (isTimeType) { return MysqlColType.MYSQL_TYPE_TIME; - } else { + } else { return MysqlColType.MYSQL_TYPE_DATETIME; } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/common/profile/ProfileTreeNode.java b/fe/fe-core/src/main/java/org/apache/doris/common/profile/ProfileTreeNode.java index 10d71a58bc..9d77bca46f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/common/profile/ProfileTreeNode.java +++ b/fe/fe-core/src/main/java/org/apache/doris/common/profile/ProfileTreeNode.java @@ -137,7 +137,6 @@ public class ProfileTreeNode extends TreeNode<ProfileTreeNode> { return sb.toString(); } - public JSONObject debugStringInJson(ProfileTreePrinter.PrintLevel level, String nodeLevel) { JSONObject jsonObject = new JSONObject(); jsonObject.put("id", nodeLevel); diff --git a/fe/fe-core/src/main/java/org/apache/doris/common/profile/ProfileTreePrinter.java b/fe/fe-core/src/main/java/org/apache/doris/common/profile/ProfileTreePrinter.java index 0028d080ed..c09a764d73 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/common/profile/ProfileTreePrinter.java +++ b/fe/fe-core/src/main/java/org/apache/doris/common/profile/ProfileTreePrinter.java @@ -20,16 +20,14 @@ package org.apache.doris.common.profile; import hu.webarticum.treeprinter.BorderTreeNodeDecorator; import hu.webarticum.treeprinter.SimpleTreeNode; import hu.webarticum.treeprinter.TraditionalTreePrinter; - import org.apache.commons.lang3.StringUtils; import org.json.simple.JSONArray; import org.json.simple.JSONObject; public class ProfileTreePrinter { - public static enum PrintLevel { - FRAGMENT, - INSTANCE + public enum PrintLevel { + FRAGMENT, INSTANCE } // Fragment tree only print the entire query plan tree with node name @@ -57,7 +55,6 @@ public class ProfileTreePrinter { return node; } - public static JSONObject printFragmentTreeInJson(ProfileTreeNode root, ProfileTreePrinter.PrintLevel level) { JSONObject object = new JSONObject(); JSONArray jsonNodes = new JSONArray(); @@ -88,5 +85,4 @@ public class ProfileTreePrinter { edges.add(edge); } } - } diff --git a/fe/fe-core/src/main/java/org/apache/doris/common/util/ProfileManager.java b/fe/fe-core/src/main/java/org/apache/doris/common/util/ProfileManager.java index 05103f83ca..ac105e3bc6 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/common/util/ProfileManager.java +++ b/fe/fe-core/src/main/java/org/apache/doris/common/util/ProfileManager.java @@ -67,6 +67,7 @@ public class ProfileManager { public static final String DEFAULT_DB = "Default Db"; public static final String SQL_STATEMENT = "Sql Statement"; public static final String IS_CACHED = "Is Cached"; + public static final String TRACE_ID = "Trace ID"; public enum ProfileType { QUERY, @@ -75,7 +76,7 @@ public class ProfileManager { public static final ArrayList<String> PROFILE_HEADERS = new ArrayList( Arrays.asList(QUERY_ID, USER, DEFAULT_DB, SQL_STATEMENT, QUERY_TYPE, - START_TIME, END_TIME, TOTAL_TIME, QUERY_STATE)); + START_TIME, END_TIME, TOTAL_TIME, QUERY_STATE, TRACE_ID)); private class ProfileElement { public Map<String, String> infoStrings = Maps.newHashMap(); @@ -285,4 +286,18 @@ public class ProfileManager { readLock.unlock(); } } + + public String getQueryIdByTraceId(String traceId) { + readLock.lock(); + try { + for (Map.Entry<String, ProfileElement> entry : queryIdToProfileMap.entrySet()) { + if (entry.getValue().infoStrings.getOrDefault(TRACE_ID, "").equals(traceId)) { + return entry.getKey(); + } + } + return ""; + } finally { + readLock.unlock(); + } + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/common/util/RuntimeProfile.java b/fe/fe-core/src/main/java/org/apache/doris/common/util/RuntimeProfile.java index 9d465020b7..de79ba6ecc 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/common/util/RuntimeProfile.java +++ b/fe/fe-core/src/main/java/org/apache/doris/common/util/RuntimeProfile.java @@ -468,7 +468,7 @@ public class RuntimeProfile { // Returns the value to which the specified key is mapped; // or null if this map contains no mapping for the key. public String getInfoString(String key) { - return infoStrings.get(key); + return infoStrings.getOrDefault(key, ""); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/MetaInfoAction.java b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/MetaInfoAction.java index e00d54ddc3..1c780f9542 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/MetaInfoAction.java +++ b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/MetaInfoAction.java @@ -37,22 +37,21 @@ import org.apache.doris.mysql.privilege.PrivPredicate; import org.apache.doris.qe.ConnectContext; import org.apache.doris.system.SystemInfoService; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; - import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import java.util.Collections; import java.util.List; import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; /** * And meta info like databases, tables and schema @@ -227,7 +226,7 @@ public class MetaInfoAction extends RestBaseController { Table tbl; try { db = Catalog.getCurrentCatalog().getDbOrMetaException(fullDbName); - tbl = db.getTableOrMetaException(tblName, Table.TableType.OLAP); + tbl = db.getTableOrMetaException(tblName); } catch (MetaNotFoundException e) { return ResponseEntityBuilder.okWithCommonError(e.getMessage()); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/manager/QueryProfileAction.java b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/manager/QueryProfileAction.java index f0b02e00d6..e3f83b9e3c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/manager/QueryProfileAction.java +++ b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/manager/QueryProfileAction.java @@ -41,9 +41,9 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.gson.JsonParser; import com.google.gson.reflect.TypeToken; - import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; import org.json.simple.JSONObject; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; @@ -58,7 +58,6 @@ import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; import java.util.stream.Collectors; - import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -221,38 +220,84 @@ public class QueryProfileAction extends RestBaseController { return ResponseEntityBuilder.ok(querySql); } - // Returns the text profile for the specified query id. - @RequestMapping(path = "/profile/text/{query_id}", method = RequestMethod.GET) + /** + * Returns the text profile for the specified query id. + * There are 3 formats: + * 1. Text: return the entire profile of the specified query id + * eg: {"profile": "text_xxx"} + * <p> + * 2. Graph: return the profile in ascii graph. If fragmentId and instanceId are specified, it will + * return the instance profile, otherwise, it will return the fragment profile. + * eg: {"profile" : "graph_xxx"} + * <p> + * 3. Json: return the profile in json. If fragmentId and instanceId are specified, it will + * return the instance profile, otherwise, it will return the fragment profile. + * Json format is mainly used for front-end UI drawing. + * eg: {"profile" : "json_xxx"} + */ + @RequestMapping(path = "/profile/{format}/{query_id}", method = RequestMethod.GET) public Object queryProfileText(HttpServletRequest request, HttpServletResponse response, - @PathVariable("query_id") String queryId, - @RequestParam(value = IS_ALL_NODE_PARA, required = false, defaultValue = "true") - boolean isAllNode) { + @PathVariable("format") String format, @PathVariable("query_id") String queryId, + @RequestParam(value = FRAGMENT_ID, required = false) String fragmentId, + @RequestParam(value = INSTANCE_ID, required = false) String instanceId, + @RequestParam(value = IS_ALL_NODE_PARA, required = false, defaultValue = "true") boolean isAllNode) { + executeCheckPassword(request, response); + checkGlobalAuth(ConnectContext.get().getCurrentUserIdentity(), PrivPredicate.ADMIN); + + if (format.equals("text")) { + return getTextProfile(request, queryId, isAllNode); + } else if (format.equals("graph")) { + return getGraphProfile(request, queryId, fragmentId, instanceId, isAllNode); + } else if (format.equals("json")) { + return getJsonProfile(request, queryId, fragmentId, instanceId, isAllNode); + } else { + return ResponseEntityBuilder.badRequest("Invalid profile format: " + format); + } + } + + /** + * Get query id by trace id + * + * @param request + * @param response + * @param traceId + * @param isAllNode + * @return + */ + @RequestMapping(path = "/trace_id/{trace_id}", method = RequestMethod.GET) + public Object getQueryIdByTraceId(HttpServletRequest request, HttpServletResponse response, + @PathVariable("trace_id") String traceId, + @RequestParam(value = IS_ALL_NODE_PARA, required = false, defaultValue = "true") boolean isAllNode) { executeCheckPassword(request, response); checkGlobalAuth(ConnectContext.get().getCurrentUserIdentity(), PrivPredicate.ADMIN); - Map<String, String> profileMap = Maps.newHashMap(); if (isAllNode) { - String httpPath = "/rest/v2/manager/query/profile/text/" + queryId; + String httpPath = "/rest/v2/manager/query/trace_id/" + traceId; ImmutableMap<String, String> arguments = ImmutableMap.<String, String>builder() .put(IS_ALL_NODE_PARA, "false").build(); - List<String> dataList = requestAllFe(httpPath, arguments, request.getHeader(NodeAction.AUTHORIZATION)); - if (!dataList.isEmpty()) { + List<Pair<String, Integer>> frontends = HttpUtils.getFeList(); + ImmutableMap<String, String> header = ImmutableMap.<String, String>builder() + .put(NodeAction.AUTHORIZATION, request.getHeader(NodeAction.AUTHORIZATION)).build(); + for (Pair<String, Integer> ipPort : frontends) { + String url = HttpUtils.concatUrl(ipPort, httpPath, arguments); try { - String profile = - JsonParser.parseString(dataList.get(0)).getAsJsonObject().get("profile").getAsString(); - profileMap.put("profile", profile); - return ResponseEntityBuilder.ok(profileMap); + String responseJson = HttpUtils.doGet(url, header); + int code = JsonParser.parseString(responseJson).getAsJsonObject().get("code").getAsInt(); + if (code == HttpUtils.REQUEST_SUCCESS_CODE) { + return responseJson; + } } catch (Exception e) { - LOG.warn("parse profile text error: {}", dataList.get(0), e); + LOG.warn(e); } } } else { - String profile = ProfileManager.getInstance().getProfile(queryId); - if (!Strings.isNullOrEmpty(profile)) { - profileMap.put("profile", profile); + String queryId = ProfileManager.getInstance().getQueryIdByTraceId(traceId); + if (Strings.isNullOrEmpty(queryId)) { + return ResponseEntityBuilder.badRequest("Not found"); } + return ResponseEntityBuilder.ok(queryId); } - return ResponseEntityBuilder.ok(profileMap); + return ResponseEntityBuilder.badRequest("not found query id"); } // Returns the fragments and instances for the specified query id. @@ -267,9 +312,8 @@ public class QueryProfileAction extends RestBaseController { // ] @RequestMapping(path = "/profile/fragments/{query_id}", method = RequestMethod.GET) public Object fragments(HttpServletRequest request, HttpServletResponse response, - @PathVariable("query_id") String queryId, - @RequestParam(value = IS_ALL_NODE_PARA, required = false, defaultValue = "true") - boolean isAllNode) { + @PathVariable("query_id") String queryId, + @RequestParam(value = IS_ALL_NODE_PARA, required = false, defaultValue = "true") boolean isAllNode) { executeCheckPassword(request, response); checkGlobalAuth(ConnectContext.get().getCurrentUserIdentity(), PrivPredicate.ADMIN); @@ -302,56 +346,47 @@ public class QueryProfileAction extends RestBaseController { return ResponseEntityBuilder.badRequest("not found query id"); } - // Returns the graph profile for the specified query id. - @RequestMapping(path = "/profile/graph/{query_id}", method = RequestMethod.GET) - public Object queryProfileGraph(HttpServletRequest request, HttpServletResponse response, - @PathVariable("query_id") String queryId, - @RequestParam(value = FRAGMENT_ID, required = false) String fragmentId, - @RequestParam(value = INSTANCE_ID, required = false) String instanceId, - @RequestParam(value = IS_ALL_NODE_PARA, required = false, defaultValue = "true") - boolean isAllNode) { - executeCheckPassword(request, response); - checkGlobalAuth(ConnectContext.get().getCurrentUserIdentity(), PrivPredicate.ADMIN); + @NotNull + private ResponseEntity getTextProfile(HttpServletRequest request, String queryId, boolean isAllNode) { + Map<String, String> profileMap = Maps.newHashMap(); + if (isAllNode) { + return getProfileFromAllFrontends(request, "text", queryId, "", ""); + } else { + String profile = ProfileManager.getInstance().getProfile(queryId); + if (!Strings.isNullOrEmpty(profile)) { + profileMap.put("profile", profile); + } + } + return ResponseEntityBuilder.ok(profileMap); + } + @NotNull + private ResponseEntity getGraphProfile(HttpServletRequest request, String queryId, String fragmentId, + String instanceId, boolean isAllNode) { Map<String, String> graph = Maps.newHashMap(); List<String> results; - if (isAllNode) { - String httpPath = "/rest/v2/manager/query/profile/graph/" + queryId; - Map<String, String> arguments = Maps.newHashMap(); - arguments.put(FRAGMENT_ID, fragmentId); - arguments.put(INSTANCE_ID, instanceId); - arguments.put(IS_ALL_NODE_PARA, "false"); - List<String> dataList = requestAllFe(httpPath, arguments, request.getHeader(NodeAction.AUTHORIZATION)); - if (!dataList.isEmpty()) { - try { - String profileGraph = - JsonParser.parseString(dataList.get(0)).getAsJsonObject().get("graph").getAsString(); - graph.put("graph", profileGraph); - return ResponseEntityBuilder.ok(graph); - } catch (Exception e) { - LOG.warn("parse profile graph error: {}", dataList.get(0), e); - } - } + return getProfileFromAllFrontends(request, "graph", queryId, fragmentId, instanceId); } else { try { if (Strings.isNullOrEmpty(fragmentId) || Strings.isNullOrEmpty(instanceId)) { ProfileTreeNode treeRoot = ProfileManager.getInstance().getFragmentProfileTree(queryId, queryId); results = Lists.newArrayList(ProfileTreePrinter.printFragmentTree(treeRoot)); } else { - ProfileTreeNode treeRoot = ProfileManager.getInstance().getInstanceProfileTree(queryId, queryId, - fragmentId, instanceId); + ProfileTreeNode treeRoot = ProfileManager.getInstance() + .getInstanceProfileTree(queryId, queryId, fragmentId, instanceId); results = Lists.newArrayList(ProfileTreePrinter.printInstanceTree(treeRoot)); } graph.put("graph", results.get(0)); } catch (Exception e) { - LOG.warn("get profile graph error, queryId:{}, fragementId:{}, instanceId:{}", - queryId, fragmentId, instanceId, e); + LOG.warn("get profile graph error, queryId:{}, fragementId:{}, instanceId:{}", queryId, fragmentId, + instanceId, e); } } return ResponseEntityBuilder.ok(graph); } + @NotNull private ResponseEntity getJsonProfile(HttpServletRequest request, String queryId, String fragmentId, String instanceId, boolean isAllNode) { Map<String, String> graph = Maps.newHashMap(); @@ -377,11 +412,12 @@ public class QueryProfileAction extends RestBaseController { return ResponseEntityBuilder.ok(graph); } + @NotNull private ResponseEntity getProfileFromAllFrontends(HttpServletRequest request, String format, String queryId, String fragmentId, String instanceId) { String httpPath = "/rest/v2/manager/query/profile/" + format + "/" + queryId; - ImmutableMap.Builder<String, String> builder = - ImmutableMap.<String, String>builder().put(IS_ALL_NODE_PARA, "false"); + ImmutableMap.Builder<String, String> builder = ImmutableMap.<String, String>builder() + .put(IS_ALL_NODE_PARA, "false"); if (!Strings.isNullOrEmpty(fragmentId)) { builder.put(FRAGMENT_ID, fragmentId); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/MysqlCommand.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/MysqlCommand.java index 69c13f15a2..f8a03029d5 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mysql/MysqlCommand.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/MysqlCommand.java @@ -51,6 +51,7 @@ public enum MysqlCommand { COM_RESET_CONNECTION("COM_RESET_CONNECTION", 31); private static Map<Integer, MysqlCommand> codeMap = Maps.newHashMap(); + static { EnumSet<MysqlCommand> enumSet = EnumSet.allOf(MysqlCommand.class); for (MysqlCommand command : enumSet) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java index 1a8c2c082b..204ce8dbaa 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java @@ -24,6 +24,7 @@ import org.apache.doris.qe.VariableMgr.VarAttr; import org.apache.doris.thrift.TQueryOptions; import org.apache.doris.thrift.TResourceLimit; +import com.google.common.base.Strings; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.json.simple.JSONObject; @@ -183,7 +184,10 @@ public class SessionVariable implements Serializable, Writable { public static final String ENABLE_PROJECTION = "enable_projection"; - public static final String TRIM_TAILING_SPACES_FOR_EXTERNAL_TABLE_QUERY = "trim_tailing_spaces_for_external_table_query"; + public static final String TRIM_TAILING_SPACES_FOR_EXTERNAL_TABLE_QUERY + = "trim_tailing_spaces_for_external_table_query"; + + static final String SESSION_CONTEXT = "session_context"; // session origin value public Map<Field, String> sessionOriginValue = new HashMap<Field, String>(); @@ -444,13 +448,21 @@ public class SessionVariable implements Serializable, Writable { // Default value is 1Gto @VariableMgr.VarAttr(name = AUTO_BROADCAST_JOIN_THRESHOLD) public double autoBroadcastJoinThreshold = 0.8; - + @VariableMgr.VarAttr(name = ENABLE_PROJECTION) private boolean enableProjection = true; @VariableMgr.VarAttr(name = TRIM_TAILING_SPACES_FOR_EXTERNAL_TABLE_QUERY, needForward = true) public boolean trimTailingSpacesForExternalTableQuery = false; + /** + * The client can pass some special information by setting this session variable in the format: "k1:v1;k2:v2". + * For example, trace_id can be passed to trace the query request sent by the user. + * set session_context="trace_id:1234565678"; + */ + @VariableMgr.VarAttr(name = SESSION_CONTEXT, needForward = true) + public String sessionContext = ""; + public String getBlockEncryptionMode() { return blockEncryptionMode; } @@ -458,6 +470,7 @@ public class SessionVariable implements Serializable, Writable { public void setBlockEncryptionMode(String blockEncryptionMode) { this.blockEncryptionMode = blockEncryptionMode; } + public long getMaxExecMemByte() { return maxExecMemByte; } @@ -1130,5 +1143,30 @@ public class SessionVariable implements Serializable, Writable { setLoadMemLimit(queryOptions.getLoadMemLimit()); } } + + /** + * The sessionContext is as follows: + * "k1:v1;k2:v2;..." + * Here we want to get value with key named "trace_id", + * Return empty string is not found. + * + * @return + */ + public String getTraceId() { + if (Strings.isNullOrEmpty(sessionContext)) { + return ""; + } + String[] parts = sessionContext.split(";"); + for (String part : parts) { + String[] innerParts = part.split(":"); + if (innerParts.length != 2) { + continue; + } + if (innerParts[0].equals("trace_id")) { + return innerParts[1]; + } + } + return ""; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java b/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java index 191dd2da89..e874358d08 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java @@ -230,6 +230,7 @@ public class StmtExecutor implements ProfileWriter { summaryProfile.addInfoString(ProfileManager.SQL_STATEMENT, originStmt.originStmt); summaryProfile.addInfoString(ProfileManager.IS_CACHED, isCached ? "Yes" : "No"); + summaryProfile.addInfoString(ProfileManager.TRACE_ID, context.getSessionVariable().getTraceId()); plannerRuntimeProfile = new RuntimeProfile("Execution Summary"); summaryProfile.addChild(plannerRuntimeProfile); profile.addChild(queryProfile); diff --git a/fe/fe-core/src/test/java/org/apache/doris/common/util/RuntimeProfileTest.java b/fe/fe-core/src/test/java/org/apache/doris/common/util/RuntimeProfileTest.java index 6ca409c225..ca35c157be 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/common/util/RuntimeProfileTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/common/util/RuntimeProfileTest.java @@ -25,7 +25,6 @@ import org.apache.doris.thrift.TUnit; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; - import org.junit.Assert; import org.junit.Test; @@ -65,8 +64,7 @@ public class RuntimeProfileTest { public void testInfoStrings() { RuntimeProfile profile = new RuntimeProfile("profileName"); - // not exists key - Assert.assertNull(profile.getInfoString("key")); + Assert.assertEquals("", profile.getInfoString("key")); // normal add and get profile.addInfoString("key", "value"); String value = profile.getInfoString("key"); --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org