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

Reply via email to