This is an automated email from the ASF dual-hosted git repository.
wzhou pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/impala.git
The following commit(s) were added to refs/heads/master by this push:
new 0d215da8d IMPALA-13038: Support profile tab for imported query profiles
0d215da8d is described below
commit 0d215da8d4e3f93ad3c1cd72aa801fbcb9464fb0
Author: Surya Hebbar <[email protected]>
AuthorDate: Mon May 6 15:47:08 2024 +0530
IMPALA-13038: Support profile tab for imported query profiles
For query profile imports currently the following tabs are supported.
- Query Statement
- Query Timeline
- Query Text Plan
With the current patch "Query Profile" tab will also be supported.
In the "QueryProfileHandler", "query_id" is now added before verifying
its existence in the query log as in "QuerySummaryHandler" and others.
"getQueryID" function has been added to "util.js", as it is helpful
across multiple query pages for retrieving the query ID into JS scripts,
before the page loads up.
On loading the imported "Query Profile" page, query profile download
section and server's non-existing query ID alerts are removed.
All unsupported navbar tabs are removed and current tab is set to active.
The query profile is retrieved from the indexedDB's "imported_queries"
database. Then query profile is passed onto "profileToString" function,
which converts the profile into indented text for displaying on the
profile page.
Each profile and its child profiles are printed in the following order
with the right indentation(fields are skipped, if they do not exist).
Profile name:
- Info strings:
- Event sequences:
- Offset:
- Events:
- Child profile(recursive):
- Counters:
Change-Id: Iddcf2e285abbf42f97bde19014be076ccd6374bc
Reviewed-on: http://gerrit.cloudera.org:8080/21400
Reviewed-by: Impala Public Jenkins <[email protected]>
Tested-by: Impala Public Jenkins <[email protected]>
---
be/src/service/impala-http-handler.cc | 6 +--
www/query_plan_text.tmpl | 14 +++----
www/query_profile.tmpl | 74 ++++++++++++++++++++++++++++++++++-
www/query_stmt.tmpl | 12 ++----
www/query_timeline.tmpl | 12 ++----
www/scripts/util.js | 12 ++++++
6 files changed, 100 insertions(+), 30 deletions(-)
diff --git a/be/src/service/impala-http-handler.cc
b/be/src/service/impala-http-handler.cc
index 6d11efced..1299285a4 100644
--- a/be/src/service/impala-http-handler.cc
+++ b/be/src/service/impala-http-handler.cc
@@ -310,6 +310,9 @@ void ImpalaHttpHandler::QueryProfileHandler(const
Webserver::WebRequest& req,
return;
}
+ Value query_id_val(PrintId(unique_id).c_str(), document->GetAllocator());
+ document->AddMember("query_id", query_id_val, document->GetAllocator());
+
ImpalaServer::RuntimeProfileOutput runtime_profile;
stringstream ss;
runtime_profile.string_output = &ss;
@@ -323,9 +326,6 @@ void ImpalaHttpHandler::QueryProfileHandler(const
Webserver::WebRequest& req,
Value profile(ss.str().c_str(), document->GetAllocator());
document->AddMember("profile", profile, document->GetAllocator());
- const auto& args = req.parsed_args;
- Value query_id(args.find("query_id")->second.c_str(),
document->GetAllocator());
- document->AddMember("query_id", query_id, document->GetAllocator());
}
void ImpalaHttpHandler::QueryProfileHelper(const Webserver::WebRequest& req,
diff --git a/www/query_plan_text.tmpl b/www/query_plan_text.tmpl
index add1e4448..728cdf4ce 100644
--- a/www/query_plan_text.tmpl
+++ b/www/query_plan_text.tmpl
@@ -30,7 +30,7 @@ $("#plan-text-tab").addClass("active");
var dbOpenReq = indexedDB.open("imported_queries");
var db;
-var supported_tabs = ["Query", "Timeline", "Text plan"];
+var supported_tabs = ["Query", "Timeline", "Text plan", "Profile"];
if (window.location.search.includes("imported")) {
var alertMessage = document.getElementsByClassName("alert alert-danger")[0];
@@ -41,7 +41,7 @@ if (window.location.search.includes("imported")) {
nav_links = nav_links.getElementsByClassName("nav-link");
for (var i = 0; i < nav_links.length;) {
if (supported_tabs.includes(nav_links[i].textContent)) {
- nav_links[i].href = `${nav_links[i].href}&imported=true`;
+ nav_links[i].href = `${nav_links[i].href}&imported=true`;
i++;
} else {
nav_links[i].parentElement.remove();
@@ -55,13 +55,9 @@ if (window.location.search.includes("imported")) {
console.log(e);
}
var profileStore = db.transaction("profiles",
"readonly").objectStore("profiles");
- var query = {};
- query.id = window.location.search;
- query.id = query.id.substring(10, query.id.indexOf("&"));
- profileStore.get(query.id).onsuccess = (e) => {
- query = e.target.result;
- query_plan.textContent = query.profile.child_profiles[0].info_strings
- .find(({key}) => key === "Plan").value;
+ profileStore.get(getQueryID()).onsuccess = (e) => {
+ query_plan.textContent = e.target.result.profile.child_profiles[0]
+ .info_strings.find(({key}) => key === "Plan").value;
};
};
}
diff --git a/www/query_profile.tmpl b/www/query_profile.tmpl
index 2f1f194c6..ed490cfb6 100644
--- a/www/query_profile.tmpl
+++ b/www/query_profile.tmpl
@@ -25,7 +25,7 @@ under the License.
{{> www/query_detail_tabs.tmpl }}
<br/>
-<div>
+<div id="profile_download_section">
<h4>Download Profile (Available Formats):
<a style="font-size:16px;" class="btn btn-primary profile-download"
href="{{ __common__.host-url
}}/query_profile_encoded?query_id={{query_id}}"
@@ -39,13 +39,83 @@ under the License.
</h4>
</div>
-<pre>{{profile}}</pre>
+<pre id="plain_text_profile_field">{{profile}}</pre>
<script>
$("#profile-tab").addClass("active");
+
+var dbOpenReq = indexedDB.open("imported_queries");
+var db;
+
+var supported_tabs = ["Query", "Timeline", "Text plan", "Profile"];
+
+function profileToString(profile, indent="") {
+ let info_strings = "";
+ if (profile.info_strings) {
+ profile.info_strings.forEach(info => {
+ info_strings = `${info_strings}${indent} ${info.key}: ${info.value}\n`;
+ });
+ }
+ let event_sequences = "";
+ if (profile.event_sequences && profile.event_sequences.length > 0) {
+ event_sequences = `${event_sequences}${indent} Event Sequences:\n`;
+ profile.event_sequences.forEach(eventSeq => {
+ event_sequences = `${event_sequences}${indent} Offset:
${eventSeq.offset}\n`;
+ event_sequences = `${event_sequences}${indent} Events:\n`;
+ eventSeq.events.forEach(event => {
+ event_sequences = `${event_sequences}${indent} ${event.label}:
${new Date(event.timestamp).toISOString()}\n`;
+ });
+ });
+ }
+ let child_profiles = "";
+ if (profile.child_profiles) {
+ profile.child_profiles.forEach(childProfile => {
+ child_profiles = `${child_profiles}${profileToString(childProfile,
indent + " ")}`;
+ });
+ }
+ let counters = "";
+ if (profile.counters && profile.counters.length > 0) {
+ counters = `${counters}${indent} Counters:\n`;
+ profile.counters.forEach(counter => {
+ counters = `${counters}${indent} ${counter.counter_name}:
${counter.value} ${counter.unit}\n`;
+ });
+ }
+ return
`${indent}${profile.profile_name}:\n${info_strings}${event_sequences}${child_profiles}${counters}`;
+}
+
document.querySelectorAll('.profile-download').forEach(function (profile_link)
{
profile_link.download = profile_link.download.replace(/\W/g,'_');
});
+
+if (window.location.search.includes("imported")) {
+ profile_download_section.remove();
+ var alertMessage = document.getElementsByClassName("alert alert-danger")[0];
+ if (alertMessage) {
+ alertMessage.remove();
+ }
+ var nav_links = document.getElementsByClassName("nav nav-tabs")[0];
+ nav_links = nav_links.getElementsByClassName("nav-link");
+ for (var i = 0; i < nav_links.length;) {
+ if (supported_tabs.includes(nav_links[i].textContent)) {
+ nav_links[i].href = `${nav_links[i].href}&imported=true`;
+ i++;
+ } else {
+ nav_links[i].parentElement.remove();
+ }
+ }
+
+ dbOpenReq.onsuccess = (e) => {
+ db = e.target.result;
+ db.onerror = (e) => {
+ console.log("IndexedDB error");
+ console.log(e);
+ }
+ var profileStore = db.transaction("profiles",
"readonly").objectStore("profiles");
+ profileStore.get(getQueryID()).onsuccess = (e) => {
+ plain_text_profile_field.textContent =
profileToString(e.target.result.profile);
+ };
+ };
+}
</script>
{{> www/common-footer.tmpl }}
diff --git a/www/query_stmt.tmpl b/www/query_stmt.tmpl
index 188b40c89..dfd39dc80 100644
--- a/www/query_stmt.tmpl
+++ b/www/query_stmt.tmpl
@@ -38,7 +38,7 @@ $("#stmt-tab").addClass("active");
var dbOpenReq = indexedDB.open("imported_queries");
var db;
-var supported_tabs = ["Query", "Timeline", "Text plan"];
+var supported_tabs = ["Query", "Timeline", "Text plan", "Profile"];
if (window.location.search.includes("imported")) {
var alertMessage = document.getElementsByClassName("alert alert-danger")[0];
@@ -49,7 +49,7 @@ if (window.location.search.includes("imported")) {
nav_links = nav_links.getElementsByClassName("nav-link");
for (var i = 0; i < nav_links.length;) {
if (supported_tabs.includes(nav_links[i].textContent)) {
- nav_links[i].href = `${nav_links[i].href}&imported=true`;
+ nav_links[i].href = `${nav_links[i].href}&imported=true`;
i++;
} else {
nav_links[i].parentElement.remove();
@@ -63,12 +63,8 @@ if (window.location.search.includes("imported")) {
console.log(e);
}
var profileStore = db.transaction("profiles",
"readonly").objectStore("profiles");
- var query = {};
- query.id = window.location.search;
- query.id = query.id.substring(10, query.id.indexOf("&"));
- profileStore.get(query.id).onsuccess = (e) => {
- query = e.target.result;
- var sql_query = query.profile.child_profiles[0].info_strings
+ profileStore.get(getQueryID()).onsuccess = (e) => {
+ var sql_query = e.target.result.profile.child_profiles[0].info_strings
.find(({key}) => key === "Sql Statement").value;
var sql_stmt_body = document.createElement("pre");
sql_stmt_body.className = "code";
diff --git a/www/query_timeline.tmpl b/www/query_timeline.tmpl
index 900631a38..06942e4cb 100644
--- a/www/query_timeline.tmpl
+++ b/www/query_timeline.tmpl
@@ -179,7 +179,7 @@ var last_maxts;
var dbOpenReq = indexedDB.open("imported_queries");
var db;
-var supported_tabs = ["Query", "Timeline", "Text plan"];
+var supported_tabs = ["Query", "Timeline", "Text plan", "Profile"];
function refreshView() {
collectFragmentEventsFromProfile();
@@ -202,7 +202,7 @@ if (window.location.search.includes("imported")) {
nav_links = nav_links.getElementsByClassName("nav-link");
for (var i = 0; i < nav_links.length;) {
if (supported_tabs.includes(nav_links[i].textContent)) {
- nav_links[i].href = `${nav_links[i].href}&imported=true`;
+ nav_links[i].href = `${nav_links[i].href}&imported=true`;
i++;
} else {
nav_links[i].parentElement.remove();
@@ -216,12 +216,8 @@ if (window.location.search.includes("imported")) {
console.log(e);
}
var profileStore = db.transaction("profiles",
"readonly").objectStore("profiles");
- var query = {};
- query.id = window.location.search;
- query.id = query.id.substring(10, query.id.indexOf("&"));
- profileStore.get(query.id).onsuccess = (e) => {
- query = e.target.result;
- set_profile(query.profile);
+ profileStore.get(getQueryID()).onsuccess = (e) => {
+ set_profile(e.target.result.profile);
refreshView();
};
};
diff --git a/www/scripts/util.js b/www/scripts/util.js
index ea470132a..ff123d5d9 100644
--- a/www/scripts/util.js
+++ b/www/scripts/util.js
@@ -95,3 +95,15 @@ function renderTime(data, type, row) {
}
return data;
}
+
+/*
+ * Useful to retrieve "query_id" from location string
+ * The search string format is
"?query_id=<query_id>&imported=true&other_params"
+ * Query ID always starts from index 10 in above format
+*/
+function getQueryID() {
+ let query_id = window.location.search.split("query_id=")[1];
+ if (query_id) {
+ return query_id.substring(0, query_id.indexOf("&"));
+ }
+}
\ No newline at end of file