/**
* 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.
*/
package org.apache.hadoop.hive.ql.exec.errors;
import java.io.BufferedReader;
import java.io.EOFException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import org.apache.hadoop.hive.conf.HiveConf;
import org.apache.hadoop.mapred.JobConf;
import org.junit.After;
import org.junit.Test;
import static org.junit.Assert.*;
public class TestTaskLogProcessor {
private final List<File> toBeDeletedList = new LinkedList<File>();
@After
public void after() {
for (File f: toBeDeletedList) {
f.delete();
}
toBeDeletedList.clear();
}
private File writeTestLog(String id, String content) throws IOException {
// Put the script content in a temp file
File scriptFile = File.createTempFile(getClass().getName() + "-" + id + "-", ".log");
scriptFile.deleteOnExit();
toBeDeletedList.add(scriptFile);
PrintStream os = new PrintStream(new FileOutputStream(scriptFile));
try {
os.print(content);
} finally {
os.close();
}
return scriptFile;
}
private String toString(Throwable t) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw, false);
t.printStackTrace(pw);
pw.close();
return sw.toString();
}
/*
* returns number of lines in the printed throwable stack trace.
*/
private String writeThrowableAsFile(String before, Throwable t, String after,
String fileSuffix, TaskLogProcessor taskLogProcessor) throws IOException {
// compose file text:
StringBuilder sb = new StringBuilder();
if (before != null) {
sb.append(before);
}
final String stackTraceStr = toString(t);
sb.append(stackTraceStr);
if (after != null) {
sb.append(after);
}
// write it to file:
File file = writeTestLog(fileSuffix, sb.toString());
// add it to the log processor:
taskLogProcessor.addTaskAttemptLogUrl(file.toURI().toURL().toString());
return stackTraceStr;
}
@Test
public void testGetStackTraces() throws Exception {
JobConf jobConf = new JobConf();
HiveConf.setQueryString(jobConf, "select * from foo group by moo;");
final TaskLogProcessor taskLogProcessor = new TaskLogProcessor(jobConf);
Throwable oome = new OutOfMemoryError("java heap space");
String oomeStr = writeThrowableAsFile("Some line in the beginning\n", oome, null, "1", taskLogProcessor);
Throwable compositeException = new InvocationTargetException(new IOException(new NullPointerException()));
String compositeStr = writeThrowableAsFile(null, compositeException, "Some line in the end.\n", "2", taskLogProcessor);
Throwable eofe = new EOFException();
String eofeStr = writeThrowableAsFile("line a\nlineb\n", eofe, " line c\nlineD\n", "3", taskLogProcessor);
List<List<String>> stackTraces = taskLogProcessor.getStackTraces();
assertEquals(3, stackTraces.size());
// Assert the actual stack traces are exactly equal to the written ones,
// and are contained in "stackTraces" list in the submission order:
checkException(oomeStr, stackTraces.get(0));
checkException(compositeStr, stackTraces.get(1));
checkException(eofeStr, stackTraces.get(2));
}
private void checkException(String writenText, List<String> actualTrace) throws IOException {
List<String> expectedLines = getLines(writenText);
String expected, actual;
for (int i=0; i<expectedLines.size(); i++) {
expected = expectedLines.get(i);
actual = actualTrace.get(i);
assertEquals(expected, actual);
}
}
private List<String> getLines(String text) throws IOException{
BufferedReader br = new BufferedReader(new StringReader(text));
List<String> list = new ArrayList<String>(48);
String string;
while (true) {
string = br.readLine();
if (string == null) {
break;
} else {
list.add(string);
}
}
br.close();
return list;
}
@Test
public void testScriptErrorHeuristic() throws Exception {
JobConf jobConf = new JobConf();
HiveConf.setQueryString(jobConf, "select * from foo group by moo;");
final TaskLogProcessor taskLogProcessor = new TaskLogProcessor(jobConf);
String errorCode = "7874"; // example code
String content = "line a\nlineb\n" + "Script failed with code " + errorCode + " line c\nlineD\n";
File log3File = writeTestLog("1", content);
taskLogProcessor.addTaskAttemptLogUrl(log3File.toURI().toURL().toString());
List<ErrorAndSolution> errList = taskLogProcessor.getErrors();
assertEquals(1, errList.size());
final ErrorAndSolution eas = errList.get(0);
String error = eas.getError();
assertNotNull(error);
// check that the error code is present in the error description:
assertTrue(error.indexOf(errorCode) >= 0);
String solution = eas.getSolution();
assertNotNull(solution);
assertTrue(solution.length() > 0);
}
@Test
public void testDataCorruptErrorHeuristic() throws Exception {
JobConf jobConf = new JobConf();
HiveConf.setQueryString(jobConf, "select * from foo group by moo;");
final TaskLogProcessor taskLogProcessor = new TaskLogProcessor(jobConf);
String badFile1 = "hdfs://localhost/foo1/moo1/zoo1";
String badFile2 = "hdfs://localhost/foo2/moo2/zoo2";
String content = "line a\nlineb\n"
+ "split: " + badFile1 + " is very bad.\n"
+ " line c\nlineD\n"
+ "split: " + badFile2 + " is also very bad.\n"
+ " java.io.EOFException: null \n"
+ "line E\n";
File log3File = writeTestLog("1", content);
taskLogProcessor.addTaskAttemptLogUrl(log3File.toURI().toURL().toString());
List<ErrorAndSolution> errList = taskLogProcessor.getErrors();
assertEquals(1, errList.size());
final ErrorAndSolution eas = errList.get(0);
String error = eas.getError();
assertNotNull(error);
// check that the error code is present in the error description:
assertTrue(error.contains(badFile1) || error.contains(badFile2));
String solution = eas.getSolution();
assertNotNull(solution);
assertTrue(solution.length() > 0);
}
@Test
public void testMapAggrMemErrorHeuristic() throws Exception {
JobConf jobConf = new JobConf();
HiveConf.setQueryString(jobConf, "select * from foo group by moo;");
final TaskLogProcessor taskLogProcessor = new TaskLogProcessor(jobConf);
Throwable oome = new OutOfMemoryError("java heap space");
File log1File = writeTestLog("1", toString(oome));
taskLogProcessor.addTaskAttemptLogUrl(log1File.toURI().toURL().toString());
List<ErrorAndSolution> errList = taskLogProcessor.getErrors();
assertEquals(1, errList.size());
final ErrorAndSolution eas = errList.get(0);
String error = eas.getError();
assertNotNull(error);
// check that the error code is present in the error description:
assertTrue(error.contains("memory"));
String solution = eas.getSolution();
assertNotNull(solution);
assertTrue(solution.length() > 0);
String confName = HiveConf.ConfVars.HIVEMAPAGGRHASHMEMORY.toString();
assertTrue(solution.contains(confName));
}
}