@@ -24,8 +24,10 @@ import scala.xml.Node
2424
2525import org .apache .spark .ui .{WebUIPage , UIUtils }
2626import org .apache .spark .util .Utils
27+ import org .apache .spark .Logging
28+ import org .apache .spark .util .logging .{FileAppender , RollingFileAppender }
2729
28- private [spark] class LogPage (parent : WorkerWebUI ) extends WebUIPage (" logPage" ) {
30+ private [spark] class LogPage (parent : WorkerWebUI ) extends WebUIPage (" logPage" ) with Logging {
2931 private val worker = parent.worker
3032 private val workDir = parent.workDir
3133
@@ -39,21 +41,18 @@ private[spark] class LogPage(parent: WorkerWebUI) extends WebUIPage("logPage") {
3941 val offset = Option (request.getParameter(" offset" )).map(_.toLong)
4042 val byteLength = Option (request.getParameter(" byteLength" )).map(_.toInt).getOrElse(defaultBytes)
4143
42- val path = (appId, executorId, driverId) match {
44+ val logDir = (appId, executorId, driverId) match {
4345 case (Some (a), Some (e), None ) =>
44- s " ${workDir.getPath}/ $appId/ $executorId/ $logType "
46+ s " ${workDir.getPath}/ $appId/ $executorId/ "
4547 case (None , None , Some (d)) =>
46- s " ${workDir.getPath}/ $driverId/ $logType "
48+ s " ${workDir.getPath}/ $driverId/ "
4749 case _ =>
4850 throw new Exception (" Request must specify either application or driver identifiers" )
4951 }
5052
51- val (startByte, endByte) = getByteRange(path, offset, byteLength)
52- val file = new File (path)
53- val logLength = file.length
54-
55- val pre = s " ==== Bytes $startByte- $endByte of $logLength of $path ==== \n "
56- pre + Utils .offsetBytes(path, startByte, endByte)
53+ val (logText, startByte, endByte, logLength) = getLog(logDir, logType, offset, byteLength)
54+ val pre = s " ==== Bytes $startByte- $endByte of $logLength of $logDir$logType ==== \n "
55+ pre + logText
5756 }
5857
5958 def render (request : HttpServletRequest ): Seq [Node ] = {
@@ -65,19 +64,16 @@ private[spark] class LogPage(parent: WorkerWebUI) extends WebUIPage("logPage") {
6564 val offset = Option (request.getParameter(" offset" )).map(_.toLong)
6665 val byteLength = Option (request.getParameter(" byteLength" )).map(_.toInt).getOrElse(defaultBytes)
6766
68- val (path , params) = (appId, executorId, driverId) match {
67+ val (logDir , params) = (appId, executorId, driverId) match {
6968 case (Some (a), Some (e), None ) =>
70- (s " ${workDir.getPath}/ $a/ $e/ $logType " , s " appId= $a&executorId= $e" )
69+ (s " ${workDir.getPath}/ $a/ $e/ " , s " appId= $a&executorId= $e" )
7170 case (None , None , Some (d)) =>
72- (s " ${workDir.getPath}/ $d/ $logType " , s " driverId= $d" )
71+ (s " ${workDir.getPath}/ $d/ " , s " driverId= $d" )
7372 case _ =>
7473 throw new Exception (" Request must specify either application or driver identifiers" )
7574 }
7675
77- val (startByte, endByte) = getByteRange(path, offset, byteLength)
78- val file = new File (path)
79- val logLength = file.length
80- val logText = <node >{Utils .offsetBytes(path, startByte, endByte)}</node >
76+ val (logText, startByte, endByte, logLength) = getLog(logDir, logType, offset, byteLength)
8177 val linkToMaster = <p ><a href ={worker.activeMasterWebUiUrl}>Back to Master </a ></p >
8278 val range = <span >Bytes {startByte.toString} - {endByte.toString} of {logLength}</span >
8379
@@ -127,23 +123,37 @@ private[spark] class LogPage(parent: WorkerWebUI) extends WebUIPage("logPage") {
127123 UIUtils .basicSparkPage(content, logType + " log page for " + appId)
128124 }
129125
130- /** Determine the byte range for a log or log page. */
131- private def getByteRange (path : String , offset : Option [Long ], byteLength : Int ): (Long , Long ) = {
132- val defaultBytes = 100 * 1024
133- val maxBytes = 1024 * 1024
134- val file = new File (path)
135- val logLength = file.length()
136- val getOffset = offset.getOrElse(logLength - defaultBytes)
137- val startByte =
138- if (getOffset < 0 ) {
139- 0L
140- } else if (getOffset > logLength) {
141- logLength
142- } else {
143- getOffset
126+ /** Get the part of the log files given the offset and desired length of bytes */
127+ private def getLog (
128+ logDirectory : String ,
129+ logType : String ,
130+ offsetOption : Option [Long ],
131+ byteLength : Int
132+ ): (String , Long , Long , Long ) = {
133+ try {
134+ val files = RollingFileAppender .getSortedRolledOverFiles(logDirectory, logType)
135+ logDebug(s " Sorted log files of type $logType in $logDirectory: \n ${files.mkString(" \n " )}" )
136+
137+ val totalLength = files.map { _.length }.sum
138+ val offset = offsetOption.getOrElse(totalLength - byteLength)
139+ val startIndex = {
140+ if (offset < 0 ) {
141+ 0L
142+ } else if (offset > totalLength) {
143+ totalLength
144+ } else {
145+ offset
146+ }
144147 }
145- val logPageLength = math.min(byteLength, maxBytes)
146- val endByte = math.min(startByte + logPageLength, logLength)
147- (startByte, endByte)
148+ val endIndex = math.min(startIndex + totalLength, totalLength)
149+ logDebug(s " Getting log from $startIndex to $endIndex" )
150+ val logText = Utils .offsetBytes(files, startIndex, endIndex)
151+ logDebug(s " Got log of length ${logText.length} bytes " )
152+ (logText, startIndex, endIndex, totalLength)
153+ } catch {
154+ case e : Exception =>
155+ logError(s " Error getting $logType logs from directory $logDirectory" , e)
156+ (" Error getting logs due to exception: " + e.getMessage, 0 , 0 , 0 )
157+ }
148158 }
149159}
0 commit comments