[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-13 Thread asfgit
Github user asfgit closed the pull request at:

https://github.com/apache/spark/pull/20474


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-13 Thread squito
Github user squito commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r167917613
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +51,29 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") execId: String): 
Array[ThreadStackTrace] = withUI { ui =>
+if (execId != SparkContext.DRIVER_IDENTIFIER && 
!execId.forall(Character.isDigit)) {
+  throw new BadParameterException(
+s"Invalid executorId: neither '${SparkContext.DRIVER_IDENTIFIER}' 
nor number.")
+}
+
+val safeSparkContext = ui.sc.getOrElse {
+  throw new ServiceUnavailable("Thread dumps not available through the 
history server.")
+}
+
+ui.store.asOption(ui.store.executorSummary(execId)) match {
+  case Some(executorSummary) if executorSummary.isActive =>
+  val safeThreadDump = 
safeSparkContext.getExecutorThreadDump(execId).getOrElse {
+throw new NotFoundException("No thread dump is available.")
+  }
+  return safeThreadDump
--- End diff --

you don't need `return` here


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-13 Thread squito
Github user squito commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r167917733
  
--- Diff: docs/monitoring.md ---
@@ -347,6 +347,10 @@ can be identified by their `[attempt-id]`. In the API 
listed below, when running
 /applications/[app-id]/executors
 A list of all active executors for the given application.
   
+  
+
/applications/[app-id]/executors/[executor-id]/threads
+Stack traces of all the threads running within the given active 
executor.
--- End diff --

Add that this is not available via the history server.


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-06 Thread vanzin
Github user vanzin commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r166465338
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +51,30 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String): 
Array[ThreadStackTrace] =
+withUI { ui =>
+if (executorId != SparkContext.DRIVER_IDENTIFIER && 
!executorId.forall(Character.isDigit)) {
--- End diff --

This whole block now needs to be indented further, and a `{` added in the 
declaration.

(Or, if you call the parameter `execId` instead, everything fits in one 
line...)


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-06 Thread vanzin
Github user vanzin commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r166409901
  
--- Diff: core/src/main/scala/org/apache/spark/ui/SparkUI.scala ---
@@ -17,7 +17,7 @@
 
 package org.apache.spark.ui
 
-import java.util.{Date, List => JList, ServiceLoader}
+import java.util.Date
--- End diff --

No code seems to be really changing in this file, so I'd avoid touching it.


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-06 Thread vanzin
Github user vanzin commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r166409000
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +51,31 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String): Response = 
withUI { ui =>
+def isAllDigits(x: String) = x.forall(Character.isDigit)
--- End diff --

You only call this in one place, so I'd just inline it. The code is just as 
self-explanatory as the method name.


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-06 Thread vanzin
Github user vanzin commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r166409259
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +51,31 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String): Response = 
withUI { ui =>
--- End diff --

You can change the return type to `Array[ThreadStackTrace]` now (and adjust 
the only path that actually returns something).


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-06 Thread vanzin
Github user vanzin commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r166409473
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +51,31 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String): Response = 
withUI { ui =>
+def isAllDigits(x: String) = x.forall(Character.isDigit)
+
+if (executorId != SparkContext.DRIVER_IDENTIFIER && 
!isAllDigits(executorId)) {
+  throw new BadParameterException(
+s"Invalid executorId: neither '${SparkContext.DRIVER_IDENTIFIER}' 
nor number.")
+}
+
+val safeSparkContext = ui.sc.getOrElse {
+  throw new ServiceUnavailable("Thread dumps not available through the 
history server.")
+}
+
+ui.store.asOption(ui.store.executorSummary(executorId)) match {
+  case Some(executorSummary) if executorSummary.isActive =>
+  val safeThreadDump = 
safeSparkContext.getExecutorThreadDump(executorId).getOrElse {
+throw new NotFoundException("No thread dump is available.")
+  }
+  return Response.ok(safeThreadDump).build()
+  case Some(_) => throw new BadParameterException("Executor is already 
dead.")
--- End diff --

nit: "Executor is not active."


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-06 Thread attilapiros
Github user attilapiros commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r166285595
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +51,52 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String): Response = 
withUI { ui =>
--- End diff --

Review comments are applied then retested and test results are updated.
Moreover I have removed the condition with UIUtils.stripXSS as the existing 
check (whether the executorId is  'driver' or number) seams to me enough. 

Some if conditions on options are transformed to a val initialised with a 
getOrElse as the option value is safe to be used elsewhere. 

As I have seen the JAX RS is at 2.0.1, so I did not touch the mapping of 
exceptions to JSON. 


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-05 Thread vanzin
Github user vanzin commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r166089402
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +51,52 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String): Response = 
withUI { ui =>
--- End diff --

If you throw exceptions in the code below instead, you can have a more 
specialized return type here, which I slightly prefer. 

Not all errors currently have exceptions (e.g. 503 is missing), but it's 
easy to add them.

(I also don't remember exactly what version of JAX-RS is being used by 
Spark, but if it's 2.1, that version has all these exceptions already, so some 
cleanup could be done here. 2.0 doesn't have them though.)


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-05 Thread vanzin
Github user vanzin commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r166087219
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +51,52 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String): Response = 
withUI { ui =>
+val safeExecutorId =
+  Option(UIUtils.stripXSS(executorId)).map { executorId =>
+UIUtils.decodeURLParameter(executorId)
+  }.getOrElse {
+throw new IllegalArgumentException(s"Missing executorId parameter")
+  }
+
+def isAllDigits(x: String) = x.forall(Character.isDigit)
+
+if (executorId != SparkContext.DRIVER_IDENTIFIER && 
!isAllDigits(executorId)) {
+  Response.serverError()
+.entity(s"Invalid executorId: neither 
'${SparkContext.DRIVER_IDENTIFIER}' nor number.")
+.status(Response.Status.BAD_REQUEST)
+.build()
+} else {
+  ui.store.asOption(ui.store.executorSummary(executorId)).map { 
executorSummary =>
+if (executorSummary.isActive) {
+  ui.sc match {
+case Some(sc) => sc.getExecutorThreadDump(safeExecutorId)
--- End diff --

nit: move case statement to next line when you have a multi-line statement.


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-05 Thread vanzin
Github user vanzin commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r166088802
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +51,52 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String): Response = 
withUI { ui =>
+val safeExecutorId =
+  Option(UIUtils.stripXSS(executorId)).map { executorId =>
+UIUtils.decodeURLParameter(executorId)
+  }.getOrElse {
+throw new IllegalArgumentException(s"Missing executorId parameter")
+  }
+
+def isAllDigits(x: String) = x.forall(Character.isDigit)
+
+if (executorId != SparkContext.DRIVER_IDENTIFIER && 
!isAllDigits(executorId)) {
+  Response.serverError()
+.entity(s"Invalid executorId: neither 
'${SparkContext.DRIVER_IDENTIFIER}' nor number.")
+.status(Response.Status.BAD_REQUEST)
+.build()
+} else {
+  ui.store.asOption(ui.store.executorSummary(executorId)).map { 
executorSummary =>
+if (executorSummary.isActive) {
+  ui.sc match {
+case Some(sc) => sc.getExecutorThreadDump(safeExecutorId)
+  .map(Response.ok(_).build())
+  .getOrElse(Response.serverError()
--- End diff --

Throw `NotFoundException` instead.


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-05 Thread vanzin
Github user vanzin commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r166088682
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +51,52 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String): Response = 
withUI { ui =>
+val safeExecutorId =
+  Option(UIUtils.stripXSS(executorId)).map { executorId =>
+UIUtils.decodeURLParameter(executorId)
+  }.getOrElse {
+throw new IllegalArgumentException(s"Missing executorId parameter")
+  }
+
+def isAllDigits(x: String) = x.forall(Character.isDigit)
+
+if (executorId != SparkContext.DRIVER_IDENTIFIER && 
!isAllDigits(executorId)) {
+  Response.serverError()
--- End diff --

Throw `BadParameterException` instead.


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-05 Thread vanzin
Github user vanzin commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r166089445
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/ApiRootResource.scala ---
@@ -93,6 +93,7 @@ private[spark] trait UIRoot {
   .status(Response.Status.SERVICE_UNAVAILABLE)
   .build()
   }
+
--- End diff --

No need to change this file.


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-05 Thread vanzin
Github user vanzin commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r166089845
  
--- Diff: core/src/main/scala/org/apache/spark/util/Utils.scala ---
@@ -2168,7 +2169,23 @@ private[spark] object Utils extends Logging {
 // We need to filter out null values here because dumpAllThreads() may 
return null array
 // elements for threads that are dead / don't exist.
 val threadInfos = 
ManagementFactory.getThreadMXBean.dumpAllThreads(true, true).filter(_ != null)
-threadInfos.sortBy(_.getThreadId).map(threadInfoToThreadStackTrace)
+threadInfos.sortWith {
+  case (threadTrace1, threadTrace2) =>
--- End diff --

nit: fits in previous line


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-05 Thread vanzin
Github user vanzin commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r166088600
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +51,52 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String): Response = 
withUI { ui =>
+val safeExecutorId =
+  Option(UIUtils.stripXSS(executorId)).map { executorId =>
+UIUtils.decodeURLParameter(executorId)
+  }.getOrElse {
+throw new IllegalArgumentException(s"Missing executorId parameter")
+  }
+
+def isAllDigits(x: String) = x.forall(Character.isDigit)
+
+if (executorId != SparkContext.DRIVER_IDENTIFIER && 
!isAllDigits(executorId)) {
--- End diff --

So this kind of code is where I prefer the "return early" approach to avoid 
nesting. It makes code easier to follow IMO.

```
if (executorId != SparkContext.DRIVER_IDENTIFIER && 
!isAllDigits(executorId)) {
  return // or throw
}

if (ui.sc.isEmpty) {
  return // or throw
}

ui.store.asOption(...) match {
  case Some(e) if e.isActive => ...
  case Some(e) => ...
  case _ => ...
}
```



---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-02 Thread attilapiros
Github user attilapiros commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r165741532
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +52,43 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String): Response = 
withUI { ui =>
+uiRoot.executorThreadDumpsNotAvailableError().getOrElse {
+  val safeExecutorId =
+Option(UIUtils.stripXSS(executorId)).map { executorId =>
+  UIUtils.decodeURLParameter(executorId)
+}.getOrElse {
+  throw new IllegalArgumentException(s"Missing executorId 
parameter")
+}
+
+  def isAllDigits(x: String) = x.forall(Character.isDigit)
+
+  if (executorId != SparkContext.DRIVER_IDENTIFIER && 
!isAllDigits(executorId)) {
+Response.serverError()
+  .entity(s"Invalid executorId: neither 
'${SparkContext.DRIVER_IDENTIFIER}' nor number.")
+  .status(Response.Status.BAD_REQUEST)
+  .build()
+  } else {
+if 
(ui.store.asOption(ui.store.executorSummary(executorId)).exists(!_.isActive)) {
--- End diff --

Yeah, I see your point. 


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-02 Thread vanzin
Github user vanzin commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r165741132
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +52,43 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String): Response = 
withUI { ui =>
+uiRoot.executorThreadDumpsNotAvailableError().getOrElse {
+  val safeExecutorId =
+Option(UIUtils.stripXSS(executorId)).map { executorId =>
+  UIUtils.decodeURLParameter(executorId)
+}.getOrElse {
+  throw new IllegalArgumentException(s"Missing executorId 
parameter")
+}
+
+  def isAllDigits(x: String) = x.forall(Character.isDigit)
+
+  if (executorId != SparkContext.DRIVER_IDENTIFIER && 
!isAllDigits(executorId)) {
+Response.serverError()
+  .entity(s"Invalid executorId: neither 
'${SparkContext.DRIVER_IDENTIFIER}' nor number.")
+  .status(Response.Status.BAD_REQUEST)
+  .build()
+  } else {
+if 
(ui.store.asOption(ui.store.executorSummary(executorId)).exists(!_.isActive)) {
--- End diff --

Those two error messages say "No stack traces are available", while the 
actual error I'm pointing out is that the executor may not exist at all. The 
HTTP error code is the same, it's just that the message is misleading.

e.g. if you have 5 executors and ask for the stack trace from executor 
1000. Yeah, technically, "No stack traces are available" is correct, it's just 
that we can do better.


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-02 Thread attilapiros
Github user attilapiros commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r165739588
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +52,43 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String): Response = 
withUI { ui =>
+uiRoot.executorThreadDumpsNotAvailableError().getOrElse {
+  val safeExecutorId =
+Option(UIUtils.stripXSS(executorId)).map { executorId =>
+  UIUtils.decodeURLParameter(executorId)
+}.getOrElse {
+  throw new IllegalArgumentException(s"Missing executorId 
parameter")
+}
+
+  def isAllDigits(x: String) = x.forall(Character.isDigit)
+
+  if (executorId != SparkContext.DRIVER_IDENTIFIER && 
!isAllDigits(executorId)) {
+Response.serverError()
+  .entity(s"Invalid executorId: neither 
'${SparkContext.DRIVER_IDENTIFIER}' nor number.")
+  .status(Response.Status.BAD_REQUEST)
+  .build()
+  } else {
+if 
(ui.store.asOption(ui.store.executorSummary(executorId)).exists(!_.isActive)) {
--- End diff --

This is exactly the current behaviour as for false it goes into:

```scala
} else {
  ui.sc.flatMap(_.getExecutorThreadDump(safeExecutorId))
.map(Response.ok(_).build())
.getOrElse(
  Response.serverError()
.entity("No stack traces are available.")
.status(Response.Status.NOT_FOUND)
.build())
}
```

Then further to:

```scala
 .getOrElse(
  Response.serverError()
.entity("No stack traces are available.")
.status(Response.Status.NOT_FOUND)
.build())
```

See the test screenshot for "Not existing (well formatted) executor ID". 

Or did I misunderstood your requirement? 


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-02 Thread vanzin
Github user vanzin commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r165733278
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +52,43 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String): Response = 
withUI { ui =>
+uiRoot.executorThreadDumpsNotAvailableError().getOrElse {
+  val safeExecutorId =
+Option(UIUtils.stripXSS(executorId)).map { executorId =>
+  UIUtils.decodeURLParameter(executorId)
+}.getOrElse {
+  throw new IllegalArgumentException(s"Missing executorId 
parameter")
+}
+
+  def isAllDigits(x: String) = x.forall(Character.isDigit)
+
+  if (executorId != SparkContext.DRIVER_IDENTIFIER && 
!isAllDigits(executorId)) {
+Response.serverError()
+  .entity(s"Invalid executorId: neither 
'${SparkContext.DRIVER_IDENTIFIER}' nor number.")
+  .status(Response.Status.BAD_REQUEST)
+  .build()
+  } else {
+if 
(ui.store.asOption(ui.store.executorSummary(executorId)).exists(!_.isActive)) {
--- End diff --

Since that method doesn't throw an exception, perhaps it's not worth it to 
try to fix this race nor make the log change.

Also I think the logic here is a little off. If the executor doesn't exist 
at all in the store, this condition will not trigger.

```
scala> case class Exec(active: Boolean)
scala> Option[Exec](null).exists(!_.active)
res3: Boolean = false
```

In that situation you should probably return a 404 error (= throw 
NotFoundException).


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-02 Thread vanzin
Github user vanzin commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r165731119
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/ApiRootResource.scala ---
@@ -83,6 +83,8 @@ private[spark] trait UIRoot {
   def getApplicationInfoList: Iterator[ApplicationInfo]
   def getApplicationInfo(appId: String): Option[ApplicationInfo]
 
+  def executorThreadDumpsNotAvailableError(): Option[Response] = None
--- End diff --

In fact, now that you pointed out the method to get the thread dump is in 
`SparkContext`, maybe you don't even need this at all. In the existing resource 
code, you can just return the error if `ui.sc` is not defined (e.g. "Thread 
dumps are only available in live applications.")


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-02 Thread vanzin
Github user vanzin commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r165730556
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/ApiRootResource.scala ---
@@ -83,6 +83,8 @@ private[spark] trait UIRoot {
   def getApplicationInfoList: Iterator[ApplicationInfo]
   def getApplicationInfo(appId: String): Option[ApplicationInfo]
 
+  def executorThreadDumpsNotAvailableError(): Option[Response] = None
--- End diff --

Sure, the method you'd add could have the `SparkUI` as a parameter.


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-02 Thread attilapiros
Github user attilapiros commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r165720298
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +52,43 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String): Response = 
withUI { ui =>
+uiRoot.executorThreadDumpsNotAvailableError().getOrElse {
+  val safeExecutorId =
+Option(UIUtils.stripXSS(executorId)).map { executorId =>
+  UIUtils.decodeURLParameter(executorId)
+}.getOrElse {
+  throw new IllegalArgumentException(s"Missing executorId 
parameter")
+}
+
+  def isAllDigits(x: String) = x.forall(Character.isDigit)
+
+  if (executorId != SparkContext.DRIVER_IDENTIFIER && 
!isAllDigits(executorId)) {
+Response.serverError()
+  .entity(s"Invalid executorId: neither 
'${SparkContext.DRIVER_IDENTIFIER}' nor number.")
+  .status(Response.Status.BAD_REQUEST)
+  .build()
+  } else {
+if 
(ui.store.asOption(ui.store.executorSummary(executorId)).exists(!_.isActive)) {
--- End diff --

In that case I would suggest to consider changing the log level in 
org.apache.spark.SparkContext#getExecutorThreadDump

```  scala
logError(s"Exception getting thread dump from executor 
$executorId", e)
```

Maybe to info. What is your opinion?


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-02 Thread attilapiros
Github user attilapiros commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r165719025
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +52,43 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String): Response = 
withUI { ui =>
+uiRoot.executorThreadDumpsNotAvailableError().getOrElse {
+  val safeExecutorId =
+Option(UIUtils.stripXSS(executorId)).map { executorId =>
+  UIUtils.decodeURLParameter(executorId)
+}.getOrElse {
+  throw new IllegalArgumentException(s"Missing executorId 
parameter")
+}
+
+  def isAllDigits(x: String) = x.forall(Character.isDigit)
+
+  if (executorId != SparkContext.DRIVER_IDENTIFIER && 
!isAllDigits(executorId)) {
+Response.serverError()
+  .entity(s"Invalid executorId: neither 
'${SparkContext.DRIVER_IDENTIFIER}' nor number.")
+  .status(Response.Status.BAD_REQUEST)
+  .build()
+  } else {
+if 
(ui.store.asOption(ui.store.executorSummary(executorId)).exists(!_.isActive)) {
+  Response.serverError()
+.entity("Executor is already dead.")
+.status(Response.Status.BAD_REQUEST)
+.build()
+} else {
+  ui.sc.flatMap(_.getExecutorThreadDump(safeExecutorId))
--- End diff --

Thanks then I will move ThreadStackTrace to api.


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-02 Thread attilapiros
Github user attilapiros commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r165717844
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/ApiRootResource.scala ---
@@ -83,6 +83,8 @@ private[spark] trait UIRoot {
   def getApplicationInfoList: Iterator[ApplicationInfo]
   def getApplicationInfo(appId: String): Option[ApplicationInfo]
 
+  def executorThreadDumpsNotAvailableError(): Option[Response] = None
--- End diff --

UIRoot has no access to AppStatusStore and SparkContext can I pass this 
parameters along with the executorId to the UIRoot?


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-02 Thread vanzin
Github user vanzin commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r165711425
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +52,43 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String): Response = 
withUI { ui =>
+uiRoot.executorThreadDumpsNotAvailableError().getOrElse {
+  val safeExecutorId =
+Option(UIUtils.stripXSS(executorId)).map { executorId =>
+  UIUtils.decodeURLParameter(executorId)
+}.getOrElse {
+  throw new IllegalArgumentException(s"Missing executorId 
parameter")
+}
+
+  def isAllDigits(x: String) = x.forall(Character.isDigit)
+
+  if (executorId != SparkContext.DRIVER_IDENTIFIER && 
!isAllDigits(executorId)) {
+Response.serverError()
+  .entity(s"Invalid executorId: neither 
'${SparkContext.DRIVER_IDENTIFIER}' nor number.")
+  .status(Response.Status.BAD_REQUEST)
+  .build()
+  } else {
+if 
(ui.store.asOption(ui.store.executorSummary(executorId)).exists(!_.isActive)) {
+  Response.serverError()
+.entity("Executor is already dead.")
+.status(Response.Status.BAD_REQUEST)
+.build()
+} else {
+  ui.sc.flatMap(_.getExecutorThreadDump(safeExecutorId))
--- End diff --

This is still exposing an internal type through the public REST API.

You need to create an API type for it and translate between the two, so 
that the type returned here is public and checked by mima. Or you could even 
just move that type into the api package and make it public.


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-02 Thread vanzin
Github user vanzin commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r165711666
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +52,43 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String): Response = 
withUI { ui =>
+uiRoot.executorThreadDumpsNotAvailableError().getOrElse {
+  val safeExecutorId =
+Option(UIUtils.stripXSS(executorId)).map { executorId =>
+  UIUtils.decodeURLParameter(executorId)
+}.getOrElse {
+  throw new IllegalArgumentException(s"Missing executorId 
parameter")
+}
+
+  def isAllDigits(x: String) = x.forall(Character.isDigit)
+
+  if (executorId != SparkContext.DRIVER_IDENTIFIER && 
!isAllDigits(executorId)) {
+Response.serverError()
+  .entity(s"Invalid executorId: neither 
'${SparkContext.DRIVER_IDENTIFIER}' nor number.")
+  .status(Response.Status.BAD_REQUEST)
+  .build()
+  } else {
+if 
(ui.store.asOption(ui.store.executorSummary(executorId)).exists(!_.isActive)) {
--- End diff --

There is a minor race here in which the active state can change in between 
here and when you get the thread dump below. Can you handle it in the call 
below instead (e.g. if it throws an exception when the executor is stopped)?


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-02 Thread vanzin
Github user vanzin commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r165712466
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/ApiRootResource.scala ---
@@ -83,6 +83,8 @@ private[spark] trait UIRoot {
   def getApplicationInfoList: Iterator[ApplicationInfo]
   def getApplicationInfo(appId: String): Option[ApplicationInfo]
 
+  def executorThreadDumpsNotAvailableError(): Option[Response] = None
--- End diff --

This feels a little odd. You could instead have a `def threadDump(...): 
Response` method and have the implementation of it be in each `UIRoot` 
implementation, instead of in the resource class. I think I prefer that a 
little bit more over this.


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-02 Thread attilapiros
Github user attilapiros commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r165604504
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +52,46 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String): Response = 
withUI { ui =>
+uiRoot.executorThreadDumpsNotAvailableError().getOrElse {
+  val safeExecutorId =
+Option(UIUtils.stripXSS(executorId)).map { executorId =>
+  UIUtils.decodeURLParameter(executorId)
+}.getOrElse {
+  throw new IllegalArgumentException(s"Missing executorId 
parameter")
+}
+
+  def isAllDigits(x: String) = x.forall(Character.isDigit)
+
+  if (executorId != SparkContext.DRIVER_IDENTIFIER && 
!isAllDigits(executorId)) {
--- End diff --

I don't think so. As I see the app-id is also not case insensitive at the 
URL api/v1/applications/{app-id}.


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-01 Thread jerryshao
Github user jerryshao commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r165548039
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +52,46 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String): Response = 
withUI { ui =>
+uiRoot.executorThreadDumpsNotAvailableError().getOrElse {
+  val safeExecutorId =
+Option(UIUtils.stripXSS(executorId)).map { executorId =>
+  UIUtils.decodeURLParameter(executorId)
+}.getOrElse {
+  throw new IllegalArgumentException(s"Missing executorId 
parameter")
+}
+
+  def isAllDigits(x: String) = x.forall(Character.isDigit)
+
+  if (executorId != SparkContext.DRIVER_IDENTIFIER && 
!isAllDigits(executorId)) {
+Response.serverError()
+  .entity(s"Invalid executorId: neither 
'${SparkContext.DRIVER_IDENTIFIER}' nor number.")
+  .status(Response.Status.BAD_REQUEST)
+  .build()
+  } else {
+if 
(ui.store.asOption(ui.store.executorSummary(executorId)).exists(!_.isActive)) {
+  Response.serverError()
+.entity("Executor is already dead.")
+.status(Response.Status.BAD_REQUEST)
+.build()
+} else {
+  val maybeStackTraces = ui.sc.flatMap { sc =>
+sc.getExecutorThreadDump(safeExecutorId)
+  }
+  maybeStackTraces match {
+case Some(stackTraces) => Response.ok(stackTraces).build()
+case None => Response.serverError()
+  .entity("No stack traces are available.")
+  .status(Response.Status.NOT_FOUND)
+  .build()
--- End diff --

nit: I think the above code can be simplified as: `ui.sc.flatMap { xxx 
}.map { xxx }.getOrElse(xxx)`.


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-01 Thread jerryshao
Github user jerryshao commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r165547727
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +52,46 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String): Response = 
withUI { ui =>
+uiRoot.executorThreadDumpsNotAvailableError().getOrElse {
+  val safeExecutorId =
+Option(UIUtils.stripXSS(executorId)).map { executorId =>
+  UIUtils.decodeURLParameter(executorId)
+}.getOrElse {
+  throw new IllegalArgumentException(s"Missing executorId 
parameter")
+}
+
+  def isAllDigits(x: String) = x.forall(Character.isDigit)
+
+  if (executorId != SparkContext.DRIVER_IDENTIFIER && 
!isAllDigits(executorId)) {
--- End diff --

Shall we change the "executorId" to low case before doing the comparison?


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-01 Thread attilapiros
Github user attilapiros commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r165510071
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +52,21 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String):
+  Option[Array[ThreadStackTrace]] = withUI { ui =>
+val safeExecutorId =
+  Option(UIUtils.stripXSS(executorId)).map { executorId =>
+UIUtils.decodeURLParameter(executorId)
+  }.getOrElse {
+throw new IllegalArgumentException(s"Missing executorId parameter")
+  }
+ui.sc.flatMap { sc =>
--- End diff --

fixed by:
Response.serverError()
  .entity("Thread dumps not available through the history server.")
  .status(Response.Status.SERVICE_UNAVAILABLE)
  .build()


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-01 Thread attilapiros
Github user attilapiros commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r165509830
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +52,21 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String):
+  Option[Array[ThreadStackTrace]] = withUI { ui =>
--- End diff --

fixed, now it a response which able to store the error message too


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-01 Thread vanzin
Github user vanzin commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r165504748
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +52,21 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String):
+  Option[Array[ThreadStackTrace]] = withUI { ui =>
--- End diff --

Not a big fan of exposing a private class (`ThreadStackTrace`) in a public 
API. (The api here is public even if the scala types aren't.)


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-01 Thread vanzin
Github user vanzin commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r165504275
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +52,21 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String):
+  Option[Array[ThreadStackTrace]] = withUI { ui =>
+val safeExecutorId =
+  Option(UIUtils.stripXSS(executorId)).map { executorId =>
+UIUtils.decodeURLParameter(executorId)
+  }.getOrElse {
+throw new IllegalArgumentException(s"Missing executorId parameter")
+  }
+ui.sc.flatMap { sc =>
--- End diff --

Should an error be thrown if this is called in a replayed app?

GONE/410 sounds like the most appropriate.


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-01 Thread gaborgsomogyi
Github user gaborgsomogyi commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r165411432
  
--- Diff: core/src/main/scala/org/apache/spark/util/Utils.scala ---
@@ -2168,7 +2168,17 @@ private[spark] object Utils extends Logging {
 // We need to filter out null values here because dumpAllThreads() may 
return null array
 // elements for threads that are dead / don't exist.
 val threadInfos = 
ManagementFactory.getThreadMXBean.dumpAllThreads(true, true).filter(_ != null)
-threadInfos.sortBy(_.getThreadId).map(threadInfoToThreadStackTrace)
--- End diff --

Keeping old behaviour is a good idea this case.


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-01 Thread attilapiros
Github user attilapiros commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r165407125
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +52,21 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String):
+  Option[Array[ThreadStackTrace]] = withUI { ui =>
+val safeExecutorId =
+  Option(UIUtils.stripXSS(executorId)).map { executorId =>
+UIUtils.decodeURLParameter(executorId)
+  }.getOrElse {
+throw new IllegalArgumentException(s"Missing executorId parameter")
+  }
+ui.sc.flatMap { sc =>
+  sc.getExecutorThreadDump(safeExecutorId)
--- End diff --

Thanks. Yes, currently it gives back null. You are right an error message 
definitely is needed here. Moreover I can check for totally bogus executorId 
(neither "driver" nor parsable to integer), finally I can access 
ExecutorSummary to decide whether the executor is active. The history server 
check is also easy.


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-01 Thread attilapiros
Github user attilapiros commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r165387234
  
--- Diff: core/src/main/scala/org/apache/spark/util/Utils.scala ---
@@ -2168,7 +2168,17 @@ private[spark] object Utils extends Logging {
 // We need to filter out null values here because dumpAllThreads() may 
return null array
 // elements for threads that are dead / don't exist.
 val threadInfos = 
ManagementFactory.getThreadMXBean.dumpAllThreads(true, true).filter(_ != null)
-threadInfos.sortBy(_.getThreadId).map(threadInfoToThreadStackTrace)
--- End diff --

Yes, it was. There is a new sortWith right after this line. Of course if 
two threads has the same name then earlier the one with the smaller thread ID 
was before (assuming sortWith is stable). I can add this extra conditions if it 
makes sense, @squito what do you think (how often we have threads with the same 
name)?


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-01 Thread squito
Github user squito commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r165379694
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +52,21 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String):
+  Option[Array[ThreadStackTrace]] = withUI { ui =>
+val safeExecutorId =
+  Option(UIUtils.stripXSS(executorId)).map { executorId =>
+UIUtils.decodeURLParameter(executorId)
+  }.getOrElse {
+throw new IllegalArgumentException(s"Missing executorId parameter")
+  }
+ui.sc.flatMap { sc =>
+  sc.getExecutorThreadDump(safeExecutorId)
--- End diff --

what happens if you give a bad executor Id?  Looks like you'll just return 
an empty response, but I think an error might be more appropriate?

In fact would be nice if the error distinguished between a totally bogus 
executorId vs. an executorId which is dead vs. calling this on the history 
server, where its totally unavailable.  Here's an example of that kind of error 
handling for the opposite case, where the endpoint is *only* available on the 
history server:


https://github.com/apache/spark/blob/master/core/src/main/scala/org/apache/spark/status/api/v1/ApiRootResource.scala?utf8=%E2%9C%93#L90-L95


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-01 Thread squito
Github user squito commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r165377861
  
--- Diff: 
core/src/main/scala/org/apache/spark/status/api/v1/OneApplicationResource.scala 
---
@@ -51,6 +52,21 @@ private[v1] class AbstractApplicationResource extends 
BaseAppResource {
   @Path("executors")
   def executorList(): Seq[ExecutorSummary] = 
withUI(_.store.executorList(true))
 
+  @GET
+  @Path("executors/{executorId}/threads")
+  def threadDump(@PathParam("executorId") executorId: String):
+  Option[Array[ThreadStackTrace]] = withUI { ui =>
--- End diff --

if this doesn't fit on oneline, the style is to still put each param on its 
own line

```scala
def threadDump(
@PathParam("executorId") executorId: String): 
Option[Array[ThreadStackTrace]] = ...
```


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-01 Thread gaborgsomogyi
Github user gaborgsomogyi commented on a diff in the pull request:

https://github.com/apache/spark/pull/20474#discussion_r165377643
  
--- Diff: core/src/main/scala/org/apache/spark/util/Utils.scala ---
@@ -2168,7 +2168,17 @@ private[spark] object Utils extends Logging {
 // We need to filter out null values here because dumpAllThreads() may 
return null array
 // elements for threads that are dead / don't exist.
 val threadInfos = 
ManagementFactory.getThreadMXBean.dumpAllThreads(true, true).filter(_ != null)
-threadInfos.sortBy(_.getThreadId).map(threadInfoToThreadStackTrace)
--- End diff --

`sortBy(_.getThreadId)` just disappeared. Is it intentional?


---

-
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org



[GitHub] spark pull request #20474: [SPARK-23235][Core] Add executor Threaddump to ap...

2018-02-01 Thread attilapiros
GitHub user attilapiros opened a pull request:

https://github.com/apache/spark/pull/20474

[SPARK-23235][Core] Add executor Threaddump to api

## What changes were proposed in this pull request?

Extending api with the executor thread dump data.

For this new REST URL is introduced:
- GET 
http://localhost:4040/api/v1/applications/{applicationId}/executors/{executorId}/threads


Example response:

``` javascript
[ {
  "threadId" : 52,
  "threadName" : "context-cleaner-periodic-gc",
  "threadState" : "TIMED_WAITING",
  "stackTrace" : "sun.misc.Unsafe.park(Native 
Method)\njava.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)\njava.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)\njava.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1093)\njava.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)\njava.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)\njava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)\njava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\njava.lang.Thread.run(Thread.java:748)",
  "blockedByLock" : 
"Lock(java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@1385411893})",
  "holdingLocks" : [ ]
}, {
  "threadId" : 48,
  "threadName" : "dag-scheduler-event-loop",
  "threadState" : "WAITING",
  "stackTrace" : "sun.misc.Unsafe.park(Native 
Method)\njava.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\njava.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)\njava.util.concurrent.LinkedBlockingDeque.takeFirst(LinkedBlockingDeque.java:492)\njava.util.concurrent.LinkedBlockingDeque.take(LinkedBlockingDeque.java:680)\norg.apache.spark.util.EventLoop$$anon$1.run(EventLoop.scala:46)",
  "blockedByLock" : 
"Lock(java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@1138053349})",
  "holdingLocks" : [ ]
}, {
  "threadId" : 17,
  "threadName" : "dispatcher-event-loop-0",
  "threadState" : "WAITING",
  "stackTrace" : "sun.misc.Unsafe.park(Native 
Method)\njava.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\njava.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)\njava.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)\norg.apache.spark.rpc.netty.Dispatcher$MessageLoop.run(Dispatcher.scala:215)\njava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\njava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\njava.lang.Thread.run(Thread.java:748)",
  "blockedByLock" : 
"Lock(java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@1764626380})",
  "holdingLocks" : [ 
"Lock(java.util.concurrent.ThreadPoolExecutor$Worker@832743930})" ]
}, {
  "threadId" : 18,
  "threadName" : "dispatcher-event-loop-1",
  "threadState" : "WAITING",
  "stackTrace" : "sun.misc.Unsafe.park(Native 
Method)\njava.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\njava.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)\njava.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)\norg.apache.spark.rpc.netty.Dispatcher$MessageLoop.run(Dispatcher.scala:215)\njava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\njava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\njava.lang.Thread.run(Thread.java:748)",
  "blockedByLock" : 
"Lock(java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@1764626380})",
  "holdingLocks" : [ 
"Lock(java.util.concurrent.ThreadPoolExecutor$Worker@834153999})" ]
}, {
  "threadId" : 19,
  "threadName" : "dispatcher-event-loop-2",
  "threadState" : "WAITING",
  "stackTrace" : "sun.misc.Unsafe.park(Native 
Method)\njava.util.concurrent.locks.LockSupport.park(LockSupport.java:175)\njava.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)\njava.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)\norg.apache.spark.rpc.netty.Dispatcher$MessageLoop.run(Dispatcher.scala:215)\njava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\njava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\njava.lang.Thread.run(Thread.java:748)",
  "blockedByLock" : 
"Lock(java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@1764626380})",
  "holdingLocks" : [ 
"Lock(java.util.concurrent.ThreadPoolExecutor$Worker@664836465})" ]
}, {
  "threadId