-
Notifications
You must be signed in to change notification settings - Fork 29k
[SPARK-44863][UI] Add a button to download thread dump as a txt in Spark UI #42575
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
c980cbe
a30a324
06a201c
89f0af5
59813b0
3411da8
43ccfa6
4935a6d
c485f0a
fe5d067
3eaa7af
1bb4692
3c52f4a
fc2f472
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -533,7 +533,47 @@ case class ThreadStackTrace( | |
| val stackTrace: StackTrace, | ||
| val blockedByThreadId: Option[Long], | ||
| val blockedByLock: String, | ||
| val holdingLocks: Seq[String]) | ||
| @deprecated("using synchronizers and monitors instead", "4.0.0") | ||
| val holdingLocks: Seq[String], | ||
| val synchronizers: Seq[String], | ||
| val monitors: Seq[String], | ||
| val lockName: Option[String], | ||
| val lockOwnerName: Option[String], | ||
| val suspended: Boolean, | ||
| val inNative: Boolean) { | ||
|
|
||
| /** | ||
| * Returns a string representation of this thread stack trace | ||
| * w.r.t java.lang.management.ThreadInfo(JDK 8)'s toString. | ||
| * | ||
| * TODO(Kent Yao): Considering 'daemon', 'priority' from higher JDKs | ||
| * | ||
| * TODO(Kent Yao): Also considering adding information os_prio, cpu, elapsed, tid, nid, etc., | ||
| * from the jstack tool | ||
| */ | ||
| override def toString: String = { | ||
| val sb = new StringBuilder() | ||
| val basic = "\"" + threadName + "\" Id=" + threadId + " " + threadState | ||
|
||
| sb.append(basic) | ||
| lockName.foreach(lock => sb.append(s" on $lock")) | ||
| lockOwnerName.foreach { | ||
| owner => sb.append(s"""owned by "$owner"""") | ||
| } | ||
| blockedByThreadId.foreach(id => s" Id=$id") | ||
| if (suspended) sb.append(" (suspended)") | ||
| if (inNative) sb.append(" (in native)") | ||
| sb.append('\n') | ||
|
|
||
| sb.append(stackTrace.elems.map(e => s"\tat $e").mkString) | ||
|
|
||
| if (synchronizers.nonEmpty) { | ||
| sb.append(s"\n\tNumber of locked synchronizers = ${synchronizers.length}\n") | ||
| synchronizers.foreach(sync => sb.append(s"\t- $sync\n")) | ||
| } | ||
| sb.append('\n') | ||
| sb.toString | ||
| } | ||
| } | ||
|
|
||
| class ProcessSummary private[spark]( | ||
| val id: String, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -48,7 +48,9 @@ private[ui] class ExecutorThreadDumpPage( | |
| </div> | ||
| case None => Text("") | ||
| } | ||
| val heldLocks = thread.holdingLocks.mkString(", ") | ||
| val synchronizers = thread.synchronizers.map(l => s"Lock($l)") | ||
| val monitors = thread.monitors.map(m => s"Monitor($m)") | ||
| val heldLocks = (synchronizers ++ monitors).mkString(", ") | ||
|
|
||
| <tr id={s"thread_${threadId}_tr"} class="accordion-heading" | ||
| onclick={s"toggleThreadStackTrace($threadId, false)"} | ||
|
|
@@ -67,18 +69,17 @@ private[ui] class ExecutorThreadDumpPage( | |
| <p>Updated at {UIUtils.formatDate(time)}</p> | ||
| { | ||
| // scalastyle:off | ||
| <p><a class="expandbutton" onClick="expandAllThreadStackTrace(true)"> | ||
| Expand All | ||
| </a></p> | ||
| <p><a class="expandbutton d-none" onClick="collapseAllThreadStackTrace(true)"> | ||
| Collapse All | ||
| </a></p> | ||
| <div class="form-inline"> | ||
| <div class="bs-example" data-example-id="simple-form-inline"> | ||
| <div class="form-group"> | ||
| <div class="input-group"> | ||
| <label class="mr-2" for="search">Search:</label> | ||
| <input type="text" class="form-control" id="search" oninput="onSearchStringChange()"></input> | ||
| <div style="display: flex; align-items: center;"> | ||
| <a class="expandbutton" onClick="expandAllThreadStackTrace(true)">Expand All</a> | ||
| <a class="expandbutton d-none" onClick="collapseAllThreadStackTrace(true)">Collapse All</a> | ||
| <a class="downloadbutton" href={"data:text/plain;charset=utf-8," + threadDump.map(_.toString).mkString} download={"threaddump_" + executorId + ".txt"}>Download</a> | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how about adding "application id" as part of the file name?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When it comes to distinguishing files, there are several options such as using app id, attempt id, timestamps, executor details, and more to name the files. However, I prefer to keep it simple to allow for easy renaming when users click the button. |
||
| <div class="form-inline"> | ||
| <div class="bs-example" data-example-id="simple-form-inline"> | ||
| <div class="form-group"> | ||
| <div class="input-group"> | ||
| <label class="mr-2" for="search">Search:</label> | ||
| <input type="text" class="form-control" id="search" oninput="onSearchStringChange()"></input> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.