You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by mo...@apache.org on 2022/07/28 07:48:08 UTC
[doris] branch master updated: [improvement](profile) add json profile and add session context (#11279)
This is an automated email from the ASF dual-hosted git repository.
morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new 97874dd125 [improvement](profile) add json profile and add session context (#11279)
97874dd125 is described below
commit 97874dd125b34b6229cc529ba1a9b80fc8c6d7be
Author: miswujian <38...@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 +-
.../apache/doris/common/profile/CounterNode.java | 4 +
.../doris/common/profile/ProfileTreeNode.java | 36 ++++
.../doris/common/profile/ProfileTreePrinter.java | 39 +++-
.../apache/doris/common/util/ProfileManager.java | 17 +-
.../apache/doris/common/util/RuntimeProfile.java | 2 +-
.../apache/doris/httpv2/rest/MetaInfoAction.java | 2 +-
.../httpv2/rest/manager/QueryProfileAction.java | 212 ++++++++++++++-------
.../java/org/apache/doris/mysql/MysqlCommand.java | 1 +
.../java/org/apache/doris/qe/SessionVariable.java | 38 ++++
.../java/org/apache/doris/qe/StmtExecutor.java | 1 +
.../doris/common/util/RuntimeProfileTest.java | 2 +-
13 files changed, 284 insertions(+), 74 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 127285bcb5..d4f8e68f54 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 240ecc037a..7dd410410a 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
@@ -92,6 +92,7 @@ public enum PrimitiveType {
}
private static ImmutableSetMultimap<PrimitiveType, PrimitiveType> implicitCastMap;
+
static {
ImmutableSetMultimap.Builder<PrimitiveType, PrimitiveType> builder = ImmutableSetMultimap.builder();
// Nulltype
@@ -1107,7 +1108,7 @@ public enum PrimitiveType {
case DATETIMEV2: {
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/CounterNode.java b/fe/fe-core/src/main/java/org/apache/doris/common/profile/CounterNode.java
index 86f2d1a010..5934f05f05 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/common/profile/CounterNode.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/common/profile/CounterNode.java
@@ -27,6 +27,10 @@ public class CounterNode extends TreeNode<CounterNode> {
counter = Pair.create(key, value);
}
+ public Pair<String, String> getCounter() {
+ return counter;
+ }
+
public String toTree(int indent) {
StringBuilder sb = new StringBuilder();
sb.append(debugString(indent));
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 45cf25d603..c6ef8b5c82 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
@@ -21,6 +21,8 @@ import org.apache.doris.common.TreeNode;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
import java.util.List;
@@ -155,6 +157,40 @@ 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);
+ JSONObject title = new JSONObject();
+ if (!id.equals(ProfileTreeBuilder.UNKNOWN_ID)) {
+ title.put("id", id);
+ }
+ title.put("name", name);
+ jsonObject.put("title", title);
+ if (level == ProfileTreePrinter.PrintLevel.FRAGMENT) {
+ jsonObject.put("fragment", fragmentId);
+ JSONArray labels = new JSONArray();
+ if (!Strings.isNullOrEmpty(maxInstanceActiveTime)) {
+ JSONObject label = new JSONObject();
+ label.put("name", "MaxActiveTime");
+ label.put("value", maxInstanceActiveTime);
+ labels.add(label);
+ }
+ jsonObject.put("labels", labels);
+ }
+ if (level == ProfileTreePrinter.PrintLevel.INSTANCE) {
+ jsonObject.put("active", activeTime);
+ jsonObject.put("non-child", nonChild);
+ JSONArray counters = new JSONArray();
+ for (CounterNode node : counterNode.getChildren()) {
+ JSONObject counter = new JSONObject();
+ counter.put(node.getCounter().first, node.getCounter().second);
+ counters.add(counter);
+ }
+ jsonObject.put("counters", counters);
+ }
+ return jsonObject;
+ }
+
private String printIndent(int indent) {
String res = "";
for (int i = 0; i < indent; i++) {
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 19d2f6a62f..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,12 +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
@@ -52,4 +54,35 @@ public class ProfileTreePrinter {
}
return node;
}
+
+ public static JSONObject printFragmentTreeInJson(ProfileTreeNode root, ProfileTreePrinter.PrintLevel level) {
+ JSONObject object = new JSONObject();
+ JSONArray jsonNodes = new JSONArray();
+ JSONArray edges = new JSONArray();
+ object.put("nodes", jsonNodes);
+ object.put("edges", edges);
+ buildNodeInJson(root, level, "", "", jsonNodes, edges);
+ return object;
+ }
+
+ private static void buildNodeInJson(ProfileTreeNode profileNode, PrintLevel level, String sourceNodeId,
+ String targetNodeId, JSONArray jsonNodes, JSONArray edges) {
+ boolean isFrist = false;
+ if (StringUtils.isBlank(sourceNodeId)) {
+ isFrist = true;
+ targetNodeId = "1";
+ }
+ jsonNodes.add(profileNode.debugStringInJson(level, targetNodeId));
+ int i = 0;
+ for (ProfileTreeNode child : profileNode.getChildren()) {
+ buildNodeInJson(child, level, targetNodeId, targetNodeId + i++, jsonNodes, edges);
+ }
+ if (!isFrist) {
+ JSONObject edge = new JSONObject();
+ edge.put("id", "e" + targetNodeId);
+ edge.put("source", sourceNodeId);
+ edge.put("target", targetNodeId);
+ 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 4f1a705920..7223169122 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
@@ -66,6 +66,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,
@@ -74,7 +75,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();
@@ -287,4 +288,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 b81db22f52..82402c294d 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
@@ -466,7 +466,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, "");
}
public Map<String, String> getInfoStrings() {
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 874c4be42b..9cad674763 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
@@ -227,7 +227,7 @@ public class MetaInfoAction extends RestBaseController {
Table tbl;
try {
db = Env.getCurrentInternalCatalog().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 b5f796159b..3fb21205e2 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
@@ -39,6 +39,9 @@ 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;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@@ -195,8 +198,9 @@ public class QueryProfileAction extends RestBaseController {
}
}
} else {
- List<List<String>> queries = ProfileManager.getInstance().getAllQueries().stream()
- .filter(query -> query.get(0).equals(queryId)).collect(Collectors.toList());
+ List<List<String>> queries =
+ ProfileManager.getInstance().getAllQueries().stream().filter(query -> query.get(0).equals(queryId))
+ .collect(Collectors.toList());
if (!queries.isEmpty()) {
querySql.put("sql", queries.get(0).get(3));
}
@@ -204,62 +208,97 @@ 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;
- 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()) {
+ 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<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.
- // [
- // {
- // "fragment_id":"",
- // "time":"",
- // "instance_id":[
- // ""
- // ]
- // }
- // ]
@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);
if (isAllNode) {
String httpPath = "/rest/v2/manager/query/profile/fragments/" + queryId;
- ImmutableMap<String, String> arguments = ImmutableMap.<String, String>builder()
- .put(IS_ALL_NODE_PARA, "false").build();
+ ImmutableMap<String, String> arguments =
+ ImmutableMap.<String, String>builder().put(IS_ALL_NODE_PARA, "false").build();
List<Pair<String, Integer>> frontends = HttpUtils.getFeList();
ImmutableMap<String, String> header = ImmutableMap.<String, String>builder()
.put(NodeAction.AUTHORIZATION, request.getHeader(NodeAction.AUTHORIZATION)).build();
@@ -285,37 +324,27 @@ 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)) {
@@ -328,10 +357,61 @@ public class QueryProfileAction extends RestBaseController {
}
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();
+ if (isAllNode) {
+ return getProfileFromAllFrontends(request, "json", queryId, fragmentId, instanceId);
+ } else {
+ try {
+ JSONObject json;
+ if (Strings.isNullOrEmpty(fragmentId) || Strings.isNullOrEmpty(instanceId)) {
+ ProfileTreeNode treeRoot = ProfileManager.getInstance().getFragmentProfileTree(queryId, queryId);
+ json = ProfileTreePrinter.printFragmentTreeInJson(treeRoot, ProfileTreePrinter.PrintLevel.FRAGMENT);
+ } else {
+ ProfileTreeNode treeRoot = ProfileManager.getInstance()
+ .getInstanceProfileTree(queryId, queryId, fragmentId, instanceId);
+ json = ProfileTreePrinter.printFragmentTreeInJson(treeRoot, ProfileTreePrinter.PrintLevel.INSTANCE);
+ }
+ graph.put("profile", json.toJSONString());
+ } catch (Exception e) {
+ LOG.warn("get profile graph error, queryId:{}, fragementId:{}, instanceId:{}", queryId, fragmentId,
+ instanceId, e);
}
}
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");
+ if (!Strings.isNullOrEmpty(fragmentId)) {
+ builder.put(FRAGMENT_ID, fragmentId);
+ }
+ if (!Strings.isNullOrEmpty(instanceId)) {
+ builder.put(INSTANCE_ID, instanceId);
+ }
+ List<String> dataList = requestAllFe(httpPath, builder.build(), request.getHeader(NodeAction.AUTHORIZATION));
+ Map<String, String> result = Maps.newHashMap();
+ if (!dataList.isEmpty()) {
+ try {
+ String profile = JsonParser.parseString(dataList.get(0)).getAsJsonObject().get("profile").getAsString();
+ result.put("profile", profile);
+ } catch (Exception e) {
+ return ResponseEntityBuilder.badRequest(e.getMessage());
+ }
+ }
+ return ResponseEntityBuilder.ok(result);
+ }
}
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 bccfed14b9..6ceb826332 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;
@@ -177,6 +178,8 @@ public class SessionVariable implements Serializable, Writable {
public static final String ENABLE_PARALLEL_OUTFILE = "enable_parallel_outfile";
+ public static final String ENABLE_LATERAL_VIEW = "enable_lateral_view";
+
public static final String SQL_QUOTE_SHOW_CREATE = "sql_quote_show_create";
public static final String RETURN_OBJECT_DATA_AS_BINARY = "return_object_data_as_binary";
@@ -200,6 +203,8 @@ public class SessionVariable implements Serializable, Writable {
public static final String ENABLE_REMOVE_NO_CONJUNCTS_RUNTIME_FILTER =
"enable_remove_no_conjuncts_runtime_filter_policy";
+ static final String SESSION_CONTEXT = "session_context";
+
// session origin value
public Map<Field, String> sessionOriginValue = new HashMap<Field, String>();
// check stmt is or not [select /*+ SET_VAR(...)*/ ...]
@@ -476,6 +481,7 @@ public class SessionVariable implements Serializable, Writable {
@VariableMgr.VarAttr(name = BLOCK_ENCRYPTION_MODE)
private String blockEncryptionMode = "";
+
@VariableMgr.VarAttr(name = ENABLE_PROJECTION)
private boolean enableProjection = true;
@@ -497,6 +503,14 @@ public class SessionVariable implements Serializable, Writable {
@VariableMgr.VarAttr(name = ENABLE_REMOVE_NO_CONJUNCTS_RUNTIME_FILTER)
public boolean enableRemoveNoConjunctsRuntimeFilterPolicy = 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;
}
@@ -1263,4 +1277,28 @@ public class SessionVariable implements Serializable, Writable {
return queryOptions;
}
+ /**
+ * 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 45f9ff3529..5bfa5fa45c 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
@@ -238,6 +238,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 12ad3d5124..5e1c396f57 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
@@ -64,7 +64,7 @@ public class RuntimeProfileTest {
public void testInfoStrings() {
RuntimeProfile profile = new RuntimeProfile("profileName");
- 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-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org