瀏覽代碼

HADOOP-2947. HOD redirects stdout and stderr of daemons to assist debugging. Contributed by Vinod Kumar Vavilapalli.

git-svn-id: https://svn.apache.org/repos/asf/hadoop/core/trunk@643745 13f79535-47bb-0310-9956-ffa450edef68
Hemanth Yamijala 17 年之前
父節點
當前提交
c098f4d484

+ 3 - 0
src/contrib/hod/CHANGES.txt

@@ -17,6 +17,9 @@ Trunk (unreleased changes)
     HADOOP-2796. Enables distinguishing exit codes from user code vis-a-vis
     HOD's exit code. (Hemanth Yamijala via ddas)
 
+    HADOOP-2947. HOD redirects stdout and stderr of daemons to assist
+    getting stack traces. (Vinod Kumar Vavilapalli via yhemanth)
+
   BUG FIXES
 
     HADOOP-2924. Fixes an address problem to do with TaskTracker binding

+ 12 - 2
src/contrib/hod/hodlib/HodRing/hodRing.py

@@ -224,6 +224,9 @@ class HadoopCommand:
                                 "confdir")
     self.logdir = os.path.join(self.hadoopdir, '%d-%s' % (id, self.name), 
                                "logdir")
+    self.out = os.path.join(self.logdir, '%s.out' % self.name)
+    self.err = os.path.join(self.logdir, '%s.err' % self.name)
+
     self.child = None
     self.restart = restart
     self.filledInKeyVals = []
@@ -395,9 +398,14 @@ class HadoopCommand:
     hadoopCommand = ''
     for item in args:
         hadoopCommand = "%s%s " % (hadoopCommand, item)
+
+    # Redirecting output and error to self.out and self.err
+    hadoopCommand = hadoopCommand + ' 1>%s 2>%s ' % (self.out, self.err)
         
     self.log.debug('running command: %s' % (hadoopCommand)) 
     self.log.debug('hadoop env: %s' % fenvs)
+    self.log.debug('Command stdout will be redirected to %s ' % self.out + \
+                   'and command stderr to %s' % self.err)
 
     self.__hadoopThread = simpleCommand('hadoop', hadoopCommand, env=fenvs)
     self.__hadoopThread.start()
@@ -433,10 +441,12 @@ class HadoopCommand:
     self.log.debug("hadoop run status: %s" % status)    
     
     if status == False:
-      for item in self.__hadoopThread.output():
-        self.log.error(item)
       self.log.error('hadoop error: %s' % (
                        self.__hadoopThread.exit_status_string()))
+      self.log.error('See %s.out and/or %s.err for details. They are ' % \
+                     (self.name, self.name) + \
+                     'located at subdirectories under either ' + \
+                     'hodring.work-dirs or hodring.log-destination-uri.')
    
     if (status == True) or (not desc.isIgnoreFailures()):
       return status

+ 33 - 0
src/contrib/hod/testing/helper.py

@@ -0,0 +1,33 @@
+#Licensed to the Apache Software Foundation (ASF) under one
+#or more contributor license agreements.  See the NOTICE file
+#distributed with this work for additional information
+#regarding copyright ownership.  The ASF licenses this file
+#to you under the Apache License, Version 2.0 (the
+#"License"); you may not use this file except in compliance
+#with the License.  You may obtain a copy of the License at
+
+#     http://www.apache.org/licenses/LICENSE-2.0
+
+#Unless required by applicable law or agreed to in writing, software
+#distributed under the License is distributed on an "AS IS" BASIS,
+#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#See the License for the specific language governing permissions and
+#limitations under the License.
+
+import sys
+
+sampleText = "Hello World!"
+
+if __name__=="__main__":
+  args = sys.argv[1:]
+  if args[0] == "1":
+    # print sample text to stderr
+    sys.stdout.write(sampleText)
+
+  elif args[0] == "2":
+    # print sample text to stderr 
+    sys.stderr.write(sampleText)
+
+  # Add any other helper programs here, with different values for args[0]
+  pass
+

+ 99 - 0
src/contrib/hod/testing/testThreads.py

@@ -0,0 +1,99 @@
+#Licensed to the Apache Software Foundation (ASF) under one
+#or more contributor license agreements.  See the NOTICE file
+#distributed with this work for additional information
+#regarding copyright ownership.  The ASF licenses this file
+#to you under the Apache License, Version 2.0 (the
+#"License"); you may not use this file except in compliance
+#with the License.  You may obtain a copy of the License at
+
+#     http://www.apache.org/licenses/LICENSE-2.0
+
+#Unless required by applicable law or agreed to in writing, software
+#distributed under the License is distributed on an "AS IS" BASIS,
+#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#See the License for the specific language governing permissions and
+#limitations under the License.
+import unittest, os, sys, re, threading, time
+
+myDirectory = os.path.realpath(sys.argv[0])
+rootDirectory   = re.sub("/testing/.*", "", myDirectory)
+
+sys.path.append(rootDirectory)
+
+from testing.lib import BaseTestSuite
+
+# module specific imports
+import os, tempfile, random
+
+excludes = []
+
+import getpass
+from hodlib.Common.threads import simpleCommand
+from testing.helper import sampleText
+
+# All test-case classes should have the naming convention test_.*
+class test_SimpleCommand(unittest.TestCase):
+  def setUp(self):
+    self.rootDir = '/tmp/hod-%s' % getpass.getuser()
+    if not os.path.exists(self.rootDir):
+      os.mkdir(self.rootDir)
+    self.prefix= 'ThreadsTestSuite.test_SimpleCommand'
+    self.testFile = None
+    pass
+
+  def testRedirectedStdout(self):
+    self.testFile= tempfile.NamedTemporaryFile(dir=self.rootDir, \
+                                               prefix=self.prefix)
+    cmd=simpleCommand('helper','%s %s 1 1>%s' % \
+                      (sys.executable, \
+                      os.path.join(rootDirectory, "testing", "helper.py"), \
+                      self.testFile.name))
+
+    cmd.start()
+    cmd.join()
+    
+    self.testFile.seek(0)
+    stdout = self.testFile.read()
+    # print stdout, sampleText
+    assert(stdout == sampleText)
+    pass
+
+  def testRedirectedStderr(self):
+    self.testFile= tempfile.NamedTemporaryFile(dir=self.rootDir, \
+                                                prefix=self.prefix)
+    cmd=simpleCommand('helper','%s %s 2 2>%s' % \
+                      (sys.executable, \
+                      os.path.join(rootDirectory, "testing", "helper.py"), \
+                      self.testFile.name))
+    cmd.start()
+    cmd.join()
+     
+    self.testFile.seek(0)
+    stderror = self.testFile.read()
+    # print stderror, sampleText
+    assert(stderror == sampleText)
+    pass
+
+  def tearDown(self):
+    if self.testFile: self.testFile.close()
+    pass
+
+class ThreadsTestSuite(BaseTestSuite):
+  def __init__(self):
+    # suite setup
+    BaseTestSuite.__init__(self, __name__, excludes)
+    pass
+  
+  def cleanUp(self):
+    # suite tearDown
+    pass
+
+def RunThreadsTests():
+  # modulename_suite
+  suite = ThreadsTestSuite()
+  testResult = suite.runTests()
+  suite.cleanUp()
+  return testResult
+
+if __name__ == "__main__":
+  RunThreadsTests()