You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@oozie.apache.org by pu...@apache.org on 2015/01/27 02:27:18 UTC
oozie git commit: OOZIE-1894 Better error reporting to user
Repository: oozie
Updated Branches:
refs/heads/master 31dbb1bff -> 95d17f26b
OOZIE-1894 Better error reporting to user
Project: http://git-wip-us.apache.org/repos/asf/oozie/repo
Commit: http://git-wip-us.apache.org/repos/asf/oozie/commit/95d17f26
Tree: http://git-wip-us.apache.org/repos/asf/oozie/tree/95d17f26
Diff: http://git-wip-us.apache.org/repos/asf/oozie/diff/95d17f26
Branch: refs/heads/master
Commit: 95d17f26b0f36c9c82e110fba8fe432f25925092
Parents: 31dbb1b
Author: Purshotam Shah <pu...@yahoo-inc.com>
Authored: Mon Jan 26 17:26:40 2015 -0800
Committer: Purshotam Shah <pu...@yahoo-inc.com>
Committed: Mon Jan 26 17:26:40 2015 -0800
----------------------------------------------------------------------
.../java/org/apache/oozie/cli/OozieCLI.java | 15 ++
.../org/apache/oozie/client/OozieClient.java | 23 +++
.../apache/oozie/client/rest/RestConstants.java | 2 +
core/src/main/conf/oozie-log4j.properties | 27 ++-
.../main/java/org/apache/oozie/BaseEngine.java | 13 ++
.../java/org/apache/oozie/BundleEngine.java | 25 ++-
.../org/apache/oozie/CoordinatorEngine.java | 27 ++-
.../main/java/org/apache/oozie/DagEngine.java | 31 +++-
.../org/apache/oozie/service/XLogService.java | 119 ++++--------
.../oozie/service/XLogStreamingService.java | 23 +++
.../java/org/apache/oozie/service/XLogUtil.java | 144 +++++++++++++++
.../oozie/service/ZKXLogStreamingService.java | 59 ++++--
.../apache/oozie/servlet/BaseJobServlet.java | 19 +-
.../org/apache/oozie/servlet/V0JobServlet.java | 7 +
.../org/apache/oozie/servlet/V1JobServlet.java | 6 +
.../org/apache/oozie/servlet/V2JobServlet.java | 41 ++++
.../apache/oozie/util/XLogUserFilterParam.java | 2 +-
.../oozie/service/TestXLogStreamingService.java | 185 ++++++++++++++++++-
.../service/TestZKXLogStreamingService.java | 126 ++++++++++++-
.../resources/test-no-dash-log4j.properties | 22 ++-
docs/src/site/twiki/DG_CommandLineTool.twiki | 26 +++
docs/src/site/twiki/WebServicesAPI.twiki | 23 +++
release-log.txt | 1 +
webapp/src/main/webapp/oozie-console.js | 130 +++++++++++--
24 files changed, 965 insertions(+), 131 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/oozie/blob/95d17f26/client/src/main/java/org/apache/oozie/cli/OozieCLI.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/oozie/cli/OozieCLI.java b/client/src/main/java/org/apache/oozie/cli/OozieCLI.java
index bc8fa50..0c28732 100644
--- a/client/src/main/java/org/apache/oozie/cli/OozieCLI.java
+++ b/client/src/main/java/org/apache/oozie/cli/OozieCLI.java
@@ -111,6 +111,8 @@ public class OozieCLI {
public static final String RERUN_OPTION = "rerun";
public static final String INFO_OPTION = "info";
public static final String LOG_OPTION = "log";
+ public static final String ERROR_LOG_OPTION = "errorlog";
+
public static final String ACTION_OPTION = "action";
public static final String DEFINITION_OPTION = "definition";
public static final String CONFIG_CONTENT_OPTION = "configcontent";
@@ -312,6 +314,8 @@ public class OozieCLI {
Option timezone = new Option(TIME_ZONE_OPTION, true,
"use time zone with the specified ID (default GMT).\nSee 'oozie info -timezones' for a list");
Option log = new Option(LOG_OPTION, true, "job log");
+ Option errorlog = new Option(ERROR_LOG_OPTION, true, "job error log");
+
Option logFilter = new Option(
RestConstants.LOG_FILTER_OPTION, true,
"job log search parameter. Can be specified as -logfilter opt1=val1;opt2=val1;opt3=val1. "
@@ -359,6 +363,7 @@ public class OozieCLI {
actions.addOption(info);
actions.addOption(rerun);
actions.addOption(log);
+ actions.addOption(errorlog);
actions.addOption(definition);
actions.addOption(config_content);
actions.addOption(ignore);
@@ -1159,6 +1164,16 @@ public class OozieCLI {
}
}
}
+ else if (options.contains(ERROR_LOG_OPTION)) {
+ PrintStream ps = System.out;
+ try {
+ wc.getJobErrorLog(commandLine.getOptionValue(ERROR_LOG_OPTION), ps);
+ }
+ finally {
+ ps.close();
+ }
+ }
+
else if (options.contains(DEFINITION_OPTION)) {
System.out.println(wc.getJobDefinition(commandLine.getOptionValue(DEFINITION_OPTION)));
}
http://git-wip-us.apache.org/repos/asf/oozie/blob/95d17f26/client/src/main/java/org/apache/oozie/client/OozieClient.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/oozie/client/OozieClient.java b/client/src/main/java/org/apache/oozie/client/OozieClient.java
index 800e871..29b1131 100644
--- a/client/src/main/java/org/apache/oozie/client/OozieClient.java
+++ b/client/src/main/java/org/apache/oozie/client/OozieClient.java
@@ -990,6 +990,17 @@ public class OozieClient {
}
/**
+ * Get the error log of a job.
+ *
+ * @param jobId
+ * @param ps
+ * @throws OozieClientException
+ */
+ public void getJobErrorLog(String jobId, PrintStream ps) throws OozieClientException {
+ new JobErrorLog(jobId, ps).call();
+ }
+
+ /**
* Get the log of a job.
*
* @param jobId job Id.
@@ -1012,6 +1023,12 @@ public class OozieClient {
}
}
+ private class JobErrorLog extends JobMetadata {
+ JobErrorLog(String jobId, PrintStream ps) {
+ super(jobId, RestConstants.JOB_SHOW_ERROR_LOG, ps);
+ }
+ }
+
/**
* Gets the JMS topic name for a particular job
* @param jobId given jobId
@@ -1068,6 +1085,12 @@ public class OozieClient {
metaType));
}
+ JobMetadata(String jobId, String metaType, PrintStream ps) {
+ this(jobId, metaType);
+ printStream = ps;
+
+ }
+
JobMetadata(String jobId, String logRetrievalType, String logRetrievalScope, String metaType, String logFilter,
PrintStream ps) {
super("GET", RestConstants.JOB, notEmpty(jobId, "jobId"), prepareParams(RestConstants.JOB_SHOW_PARAM,
http://git-wip-us.apache.org/repos/asf/oozie/blob/95d17f26/client/src/main/java/org/apache/oozie/client/rest/RestConstants.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/oozie/client/rest/RestConstants.java b/client/src/main/java/org/apache/oozie/client/rest/RestConstants.java
index 85efecf..3c2afc3 100644
--- a/client/src/main/java/org/apache/oozie/client/rest/RestConstants.java
+++ b/client/src/main/java/org/apache/oozie/client/rest/RestConstants.java
@@ -87,6 +87,8 @@ public interface RestConstants {
public static final String JOB_SHOW_LOG = "log";
+ public static final String JOB_SHOW_ERROR_LOG = "errorlog";
+
public static final String JOB_SHOW_DEFINITION = "definition";
public static final String JOB_SHOW_GRAPH = "graph";
http://git-wip-us.apache.org/repos/asf/oozie/blob/95d17f26/core/src/main/conf/oozie-log4j.properties
----------------------------------------------------------------------
diff --git a/core/src/main/conf/oozie-log4j.properties b/core/src/main/conf/oozie-log4j.properties
index b91bfa4..dd3e53c 100644
--- a/core/src/main/conf/oozie-log4j.properties
+++ b/core/src/main/conf/oozie-log4j.properties
@@ -44,6 +44,29 @@ log4j.appender.oozie.RollingPolicy.FileNamePattern=${log4j.appender.oozie.File}-
# The MaxHistory controls how many log files will be retained (720 hours / 24 hours per day = 30 days); -1 to disable
log4j.appender.oozie.RollingPolicy.MaxHistory=720
+
+
+log4j.appender.oozieError=org.apache.log4j.rolling.RollingFileAppender
+log4j.appender.oozieError.RollingPolicy=org.apache.oozie.util.OozieRollingPolicy
+log4j.appender.oozieError.File=${oozie.log.dir}/oozie-error.log
+log4j.appender.oozieError.Append=true
+log4j.appender.oozieError.layout=org.apache.log4j.PatternLayout
+log4j.appender.oozieError.layout.ConversionPattern=%d{ISO8601} %5p %c{1}:%L - SERVER[${oozie.instance.id}] %m%n
+# The FileNamePattern must end with "-%d{yyyy-MM-dd-HH}.gz" or "-%d{yyyy-MM-dd-HH}" and also start with the
+# value of log4j.appender.oozieError.File
+log4j.appender.oozieError.RollingPolicy.FileNamePattern=${log4j.appender.oozieError.File}-%d{yyyy-MM-dd-HH}
+# The MaxHistory controls how many log files will be retained (720 hours / 24 hours per day = 30 days); -1 to disable
+log4j.appender.oozieError.RollingPolicy.MaxHistory=720
+log4j.appender.oozieError.filter.1 = org.apache.log4j.varia.LevelMatchFilter
+log4j.appender.oozieError.filter.1.levelToMatch = WARN
+log4j.appender.oozieError.filter.2 = org.apache.log4j.varia.LevelMatchFilter
+log4j.appender.oozieError.filter.2.levelToMatch = ERROR
+log4j.appender.oozieError.filter.3 = org.apache.log4j.varia.LevelMatchFilter
+log4j.appender.oozieError.filter.3.levelToMatch = FATAL
+log4j.appender.oozieError.filter.4 = org.apache.log4j.varia.DenyAllFilter
+
+
+
# Uncomment the below two lines to use the DailyRollingFileAppender instead
# The DatePattern must end with either "dd" or "HH"
#log4j.appender.oozie=org.apache.log4j.DailyRollingFileAppender
@@ -81,8 +104,8 @@ log4j.logger.openjpa=INFO, openjpa
log4j.logger.oozieops=INFO, oozieops
log4j.logger.oozieinstrumentation=ALL, oozieinstrumentation
log4j.logger.oozieaudit=ALL, oozieaudit
-log4j.logger.org.apache.oozie=INFO, oozie
+log4j.logger.org.apache.oozie=ALL, oozie, oozieError
log4j.logger.org.apache.hadoop=WARN, oozie
log4j.logger.org.mortbay=WARN, oozie
log4j.logger.org.hsqldb=WARN, oozie
-log4j.logger.org.apache.hadoop.security.authentication.server=WARN, oozie
+log4j.logger.org.apache.hadoop.security.authentication.server=WARN, oozie
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/oozie/blob/95d17f26/core/src/main/java/org/apache/oozie/BaseEngine.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/BaseEngine.java b/core/src/main/java/org/apache/oozie/BaseEngine.java
index a982ad4..bf38a0c 100644
--- a/core/src/main/java/org/apache/oozie/BaseEngine.java
+++ b/core/src/main/java/org/apache/oozie/BaseEngine.java
@@ -171,6 +171,19 @@ public abstract class BaseEngine {
throws IOException, BaseEngineException;
/**
+ * Stream error log of a job.
+ *
+ * @param jobId job Id.
+ * @param writer writer to stream the log to.
+ * @param params additional parameters from the request
+ * @throws IOException thrown if the log cannot be streamed.
+ * @throws BaseEngineException thrown if there is error in getting the Workflow/Coordinator Job Information for
+ * jobId.
+ */
+ public abstract void streamErrorLog(String jobId, Writer writer, Map<String, String[]> params) throws IOException,
+ BaseEngineException;
+
+ /**
* Return the workflow Job ID for an external ID.
* <p/>
* This is reverse lookup for recovery purposes.
http://git-wip-us.apache.org/repos/asf/oozie/blob/95d17f26/core/src/main/java/org/apache/oozie/BundleEngine.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/BundleEngine.java b/core/src/main/java/org/apache/oozie/BundleEngine.java
index 27afe73..9818acc 100644
--- a/core/src/main/java/org/apache/oozie/BundleEngine.java
+++ b/core/src/main/java/org/apache/oozie/BundleEngine.java
@@ -242,12 +242,19 @@ public class BundleEngine extends BaseEngine {
}
}
- /* (non-Javadoc)
- * @see org.apache.oozie.BaseEngine#streamLog(java.lang.String, java.io.Writer)
- */
- @Override
+
public void streamLog(String jobId, Writer writer, Map<String, String[]> params) throws IOException,
BundleEngineException {
+ streamJobLog(jobId, writer, params, false);
+ }
+
+ public void streamErrorLog(String jobId, Writer writer, Map<String, String[]> params) throws IOException,
+ BundleEngineException {
+ streamJobLog(jobId, writer, params, true);
+ }
+
+ private void streamJobLog(String jobId, Writer writer, Map<String, String[]> params, boolean isErrorLog) throws IOException,
+ BundleEngineException {
BundleJobBean job;
try {
@@ -261,7 +268,15 @@ public class BundleEngine extends BaseEngine {
if (lastTime == null) {
lastTime = new Date();
}
- Services.get().get(XLogStreamingService.class).streamLog(filter, job.getCreatedTime(), lastTime, writer, params);
+ if (isErrorLog) {
+ Services.get().get(XLogStreamingService.class)
+ .streamErrorLog(filter, job.getCreatedTime(), lastTime, writer, params);
+ }
+ else {
+ Services.get().get(XLogStreamingService.class)
+ .streamLog(filter, job.getCreatedTime(), lastTime, writer, params);
+
+ }
}
catch (Exception ex) {
throw new IOException(ex);
http://git-wip-us.apache.org/repos/asf/oozie/blob/95d17f26/core/src/main/java/org/apache/oozie/CoordinatorEngine.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/CoordinatorEngine.java b/core/src/main/java/org/apache/oozie/CoordinatorEngine.java
index 3406c6f..136c097 100644
--- a/core/src/main/java/org/apache/oozie/CoordinatorEngine.java
+++ b/core/src/main/java/org/apache/oozie/CoordinatorEngine.java
@@ -293,15 +293,20 @@ public class CoordinatorEngine extends BaseEngine {
throw new BaseEngineException(new XException(ErrorCode.E0301, "invalid use of start"));
}
- /*
- * (non-Javadoc)
- *
- * @see org.apache.oozie.BaseEngine#streamLog(java.lang.String,
- * java.io.Writer)
- */
@Override
public void streamLog(String jobId, Writer writer, Map<String, String[]> params) throws IOException,
BaseEngineException {
+ streamJobLog(jobId, writer, params, false);
+ }
+
+ @Override
+ public void streamErrorLog(String jobId, Writer writer, Map<String, String[]> params) throws IOException,
+ BaseEngineException {
+ streamJobLog(jobId, writer, params, true);
+ }
+
+ private void streamJobLog(String jobId, Writer writer, Map<String, String[]> params, boolean isErrorLog)
+ throws IOException, BaseEngineException {
try {
XLogFilter filter = new XLogFilter(new XLogUserFilterParam(params));
@@ -314,8 +319,14 @@ public class CoordinatorEngine extends BaseEngine {
if (lastTime == null) {
lastTime = new Date();
}
- Services.get().get(XLogStreamingService.class)
- .streamLog(filter, job.getCreatedTime(), lastTime, writer, params);
+ if (isErrorLog) {
+ Services.get().get(XLogStreamingService.class)
+ .streamErrorLog(filter, job.getCreatedTime(), lastTime, writer, params);
+ }
+ else {
+ Services.get().get(XLogStreamingService.class)
+ .streamLog(filter, job.getCreatedTime(), lastTime, writer, params);
+ }
}
catch (Exception e) {
throw new IOException(e);
http://git-wip-us.apache.org/repos/asf/oozie/blob/95d17f26/core/src/main/java/org/apache/oozie/DagEngine.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/DagEngine.java b/core/src/main/java/org/apache/oozie/DagEngine.java
index 70ddd44..cd90390 100644
--- a/core/src/main/java/org/apache/oozie/DagEngine.java
+++ b/core/src/main/java/org/apache/oozie/DagEngine.java
@@ -379,7 +379,7 @@ public class DagEngine extends BaseEngine {
@Override
public String getDefinition(String jobId) throws DagEngineException {
try {
- return new DefinitionXCommand(jobId).call();
+ return new DefinitionXCommand(jobId).call();
}
catch (CommandException ex) {
throw new DagEngineException(ex);
@@ -398,6 +398,25 @@ public class DagEngine extends BaseEngine {
@Override
public void streamLog(String jobId, Writer writer, Map<String, String[]> params) throws IOException,
DagEngineException {
+ streamJobLog(jobId, writer, params, false);
+ }
+
+ /**
+ * Stream the error log of a job.
+ *
+ * @param jobId job Id.
+ * @param writer writer to stream the log to.
+ * @param params additional parameters from the request
+ * @throws IOException thrown if the log cannot be streamed.
+ * @throws DagEngineException thrown if there is error in getting the Workflow Information for jobId.
+ */
+ public void streamErrorLog(String jobId, Writer writer, Map<String, String[]> params) throws IOException,
+ DagEngineException {
+ streamJobLog(jobId, writer, params, true);
+ }
+
+ public void streamJobLog(String jobId, Writer writer, Map<String, String[]> params, boolean isErrorLog)
+ throws IOException, DagEngineException {
try {
XLogFilter filter = new XLogFilter(new XLogUserFilterParam(params));
filter.setParameter(DagXLogInfoService.JOB, jobId);
@@ -406,7 +425,15 @@ public class DagEngine extends BaseEngine {
if (lastTime == null) {
lastTime = job.getLastModifiedTime();
}
- Services.get().get(XLogStreamingService.class).streamLog(filter, job.getCreatedTime(), lastTime, writer, params);
+ if (isErrorLog) {
+ Services.get().get(XLogStreamingService.class)
+ .streamErrorLog(filter, job.getCreatedTime(), lastTime, writer, params);
+ }
+ else {
+ Services.get().get(XLogStreamingService.class)
+ .streamLog(filter, job.getCreatedTime(), lastTime, writer, params);
+ }
+
}
catch (Exception e) {
throw new IOException(e);
http://git-wip-us.apache.org/repos/asf/oozie/blob/95d17f26/core/src/main/java/org/apache/oozie/service/XLogService.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/service/XLogService.java b/core/src/main/java/org/apache/oozie/service/XLogService.java
index e97c38a..c291fa8 100644
--- a/core/src/main/java/org/apache/oozie/service/XLogService.java
+++ b/core/src/main/java/org/apache/oozie/service/XLogService.java
@@ -15,7 +15,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.apache.oozie.service;
import org.apache.commons.logging.LogFactory;
@@ -37,7 +36,6 @@ import java.io.InputStream;
import java.net.URL;
import java.util.Properties;
import java.util.Map;
-import java.util.regex.Pattern;
/**
* Built-in service that initializes and manages Logging via Log4j.
@@ -94,6 +92,7 @@ public class XLogService implements Service, Instrumentable {
private boolean fromClasspath;
private String log4jFileName;
private boolean logOverWS = true;
+ private boolean errorLogEnable = true;
private static final String STARTUP_MESSAGE = "{E}"
+ " ******************************************************************************* {E}"
@@ -103,19 +102,32 @@ public class XLogService implements Service, Instrumentable {
private String oozieLogPath;
private String oozieLogName;
+ private String oozieErrorLogPath;
+ private String oozieErrorLogName;
private int oozieLogRotation = -1;
+ private int oozieErrorLogRotation = -1;
+
public XLogService() {
}
-
+
public String getOozieLogPath() {
return oozieLogPath;
}
-
+
+ public String getOozieErrorLogPath() {
+ return oozieErrorLogPath;
+ }
+
public String getOozieLogName() {
return oozieLogName;
}
+ public String getOozieErrorLogName() {
+ return oozieErrorLogName;
+ }
+
+
/**
* Initialize the log service.
*
@@ -190,7 +202,6 @@ public class XLogService implements Service, Instrumentable {
}
private void extractInfoForLogWebService(InputStream is) throws IOException {
- logOverWS = true;
Properties props = new Properties();
props.load(is);
@@ -198,83 +209,18 @@ public class XLogService implements Service, Instrumentable {
for (Map.Entry entry : props.entrySet()) {
conf.set((String) entry.getKey(), (String) entry.getValue());
}
- String logFile = conf.get("log4j.appender.oozie.File");
- if (logFile == null) {
- log.warn("Oozie WS log will be disabled, missing property 'log4j.appender.oozie.File' for 'oozie' "
- + "appender");
- logOverWS = false;
- }
- else {
- logFile = logFile.trim();
- int i = logFile.lastIndexOf("/");
- if (i == -1) {
- log.warn("Oozie WS log will be disabled, log file is not an absolute path [{0}] for 'oozie' appender",
- logFile);
- logOverWS = false;
- }
- else {
- String appenderClass = conf.get("log4j.appender.oozie");
- if (appenderClass == null) {
- log.warn("Oozie WS log will be disabled, missing property [log4j.appender.oozie]");
- logOverWS = false;
- }
- else if (appenderClass.equals("org.apache.log4j.DailyRollingFileAppender")) {
- String pattern = conf.get("log4j.appender.oozie.DatePattern");
- if (pattern == null) {
- log.warn("Oozie WS log will be disabled, missing property [log4j.appender.oozie.DatePattern]");
- logOverWS = false;
- }
- else {
- pattern = pattern.trim();
- if (pattern.endsWith("HH")) {
- oozieLogRotation = 60 * 60;
- }
- else if (pattern.endsWith("dd")) {
- oozieLogRotation = 60 * 60 * 24;
- }
- else {
- log.warn("Oozie WS log will be disabled, DatePattern [{0}] should end with 'HH' or 'dd'",
- pattern);
- logOverWS = false;
- }
- if (oozieLogRotation > 0) {
- oozieLogPath = logFile.substring(0, i);
- oozieLogName = logFile.substring(i + 1);
- }
- }
- }
- else if (appenderClass.equals("org.apache.log4j.rolling.RollingFileAppender")) {
- String pattern = conf.get("log4j.appender.oozie.RollingPolicy.FileNamePattern");
- if (pattern == null) {
- log.warn("Oozie WS log will be disabled, missing property "
- + "[log4j.appender.oozie.RollingPolicy.FileNamePattern]");
- logOverWS = false;
- }
- else {
- pattern = pattern.trim();
- if (pattern.matches(Pattern.quote(logFile) + ".*-%d\\{yyyy-MM-dd-HH\\}(\\.gz)?")) {
- oozieLogRotation = 60 * 60;
- }
- else {
- log.warn("Oozie WS log will be disabled, RollingPolicy.FileNamePattern [{0}] should end with "
- + "'-%d{yyyy-MM-dd-HH}' or '-%d{yyyy-MM-dd-HH}.gz' and also start with the value of "
- + "log4j.appender.oozie.File [{1}]", pattern, logFile);
- logOverWS = false;
- }
- if (oozieLogRotation > 0) {
- oozieLogPath = logFile.substring(0, i);
- oozieLogName = logFile.substring(i + 1);
- }
- }
- }
- else {
- log.warn("Oozie WS log will be disabled, log4j.appender.oozie [" + appenderClass + "] should be "
- + "either org.apache.log4j.DailyRollingFileAppender or org.apache.log4j.rolling.RollingFileAppender "
- + "to enable it");
- logOverWS = false;
- }
- }
- }
+
+ XLogUtil logUtil = new XLogUtil(conf, "oozie");
+ logOverWS = logUtil.isLogOverEnable();
+ oozieLogRotation = logUtil.getLogRotation() == 0 ? oozieLogRotation : logUtil.getLogRotation();
+ oozieLogPath = logUtil.getLogPath() == null ? oozieLogPath : logUtil.getLogPath();
+ oozieLogName = logUtil.getLogFileName() == null ? oozieLogName : logUtil.getLogFileName();
+
+ logUtil = new XLogUtil(conf, "oozieError");
+ errorLogEnable = logUtil.isLogOverEnable();
+ oozieErrorLogRotation = logUtil.getLogRotation() == 0 ? oozieErrorLogRotation : logUtil.getLogRotation();
+ oozieErrorLogPath = logUtil.getLogPath() == null ? oozieErrorLogPath : logUtil.getLogPath();
+ oozieErrorLogName = logUtil.getLogFileName() == null ? oozieErrorLogName : logUtil.getLogFileName();
}
/**
@@ -313,6 +259,7 @@ public class XLogService implements Service, Instrumentable {
* @param instr instrumentation to use.
*/
public void instrument(Instrumentation instr) {
+
instr.addVariable(INSTRUMENTATION_GROUP, "config.file", new Instrumentation.Variable<String>() {
public String getValue() {
return log4jFileName;
@@ -339,9 +286,17 @@ public class XLogService implements Service, Instrumentable {
return logOverWS;
}
+ boolean isErrorLogEnable(){
+ return errorLogEnable;
+ }
+
int getOozieLogRotation() {
return oozieLogRotation;
}
+ int getOozieErrorLogRotation() {
+ return oozieErrorLogRotation;
+ }
+
String getLog4jProperties() {
return log4jFileName;
http://git-wip-us.apache.org/repos/asf/oozie/blob/95d17f26/core/src/main/java/org/apache/oozie/service/XLogStreamingService.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/service/XLogStreamingService.java b/core/src/main/java/org/apache/oozie/service/XLogStreamingService.java
index 9a42f2f..9066c7a 100644
--- a/core/src/main/java/org/apache/oozie/service/XLogStreamingService.java
+++ b/core/src/main/java/org/apache/oozie/service/XLogStreamingService.java
@@ -93,6 +93,29 @@ public class XLogStreamingService implements Service, Instrumentable {
}
}
+ /**
+ * Stream the error log of a job.
+ *
+ * @param filter log streamer filter.
+ * @param startTime start time for log events to filter.
+ * @param endTime end time for log events to filter.
+ * @param writer writer to stream the log to.
+ * @param params additional parameters from the request
+ * @throws IOException thrown if the log cannot be streamed.
+ */
+ public void streamErrorLog(XLogFilter filter, Date startTime, Date endTime, Writer writer, Map<String, String[]> params)
+ throws IOException {
+ XLogService xLogService = Services.get().get(XLogService.class);
+ if (xLogService.isErrorLogEnable()) {
+ new XLogStreamer(filter, xLogService.getOozieErrorLogPath(), xLogService.getOozieErrorLogName(),
+ xLogService.getOozieErrorLogRotation()).streamLog(writer, startTime, endTime, bufferLen);
+ }
+ else {
+ writer.write("Error Log is disabled!!");
+ }
+ }
+
+
public int getBufferLen() {
return bufferLen;
}
http://git-wip-us.apache.org/repos/asf/oozie/blob/95d17f26/core/src/main/java/org/apache/oozie/service/XLogUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/service/XLogUtil.java b/core/src/main/java/org/apache/oozie/service/XLogUtil.java
new file mode 100644
index 0000000..59a4d22
--- /dev/null
+++ b/core/src/main/java/org/apache/oozie/service/XLogUtil.java
@@ -0,0 +1,144 @@
+/**
+ * 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.oozie.service;
+
+import java.util.regex.Pattern;
+
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.oozie.util.XLog;
+
+public class XLogUtil {
+
+ private String logPath;
+ private String logFileName;
+ private boolean isLogOverEnable = true;
+ private int logRotation;
+
+ public static XLog log = new XLog(LogFactory.getLog(XLogUtil.class));
+
+ public XLogUtil(Configuration conf, String logType) {
+ extractInfoForLogWebService(conf, logType);
+ }
+
+ private void extractInfoForLogWebService(Configuration conf, String logType) {
+ String logFile = conf.get("log4j.appender." + logType + ".File");
+ if (logFile == null) {
+ log.warn("Oozie WS " + logType
+ + " log will be disabled, missing property 'log4j.appender.oozie.File' for 'oozie' " + "appender");
+ isLogOverEnable = false;
+ }
+ else {
+ logFile = logFile.trim();
+ int i = logFile.lastIndexOf("/");
+ if (i == -1) {
+ log.warn("Oozie WS " + logType
+ + " log will be disabled, log file is not an absolute path [{0}] for 'oozie' appender", logFile);
+ isLogOverEnable = false;
+ }
+ else {
+ String appenderClass = conf.get("log4j.appender." + logType);
+ if (appenderClass == null) {
+ log.warn("Oozie WS " + logType + " log will be disabled, missing property [log4j.appender.oozie]");
+ isLogOverEnable = false;
+ }
+ else if (appenderClass.equals("org.apache.log4j.DailyRollingFileAppender")) {
+ String pattern = conf.get("log4j.appender." + logType + ".DatePattern");
+ if (pattern == null) {
+ log.warn("Oozie WS " + logType
+ + " log will be disabled, missing property [log4j.appender." + logType + ".DatePattern]");
+ isLogOverEnable = false;
+ }
+ else {
+ pattern = pattern.trim();
+ if (pattern.endsWith("HH")) {
+ logRotation = 60 * 60;
+ }
+ else if (pattern.endsWith("dd")) {
+ logRotation = 60 * 60 * 24;
+ }
+ else {
+ log.warn("Oozie WS " + logType
+ + " log will be disabled, DatePattern [{0}] should end with 'HH' or 'dd'", pattern);
+ isLogOverEnable = false;
+ }
+ if (logRotation > 0) {
+ logPath = logFile.substring(0, i);
+ logFileName = logFile.substring(i + 1);
+ }
+ }
+ }
+ else if (appenderClass.equals("org.apache.log4j.rolling.RollingFileAppender")) {
+ String pattern = conf.get("log4j.appender." + logType + ".RollingPolicy.FileNamePattern");
+ if (pattern == null) {
+ log.warn("Oozie WS " + logType + " log will be disabled, missing property "
+ + "[log4j.appender." + logType + ".RollingPolicy.FileNamePattern]");
+ isLogOverEnable = false;
+ }
+ else {
+ pattern = pattern.trim();
+ if (pattern.matches(Pattern.quote(logFile) + ".*-%d\\{yyyy-MM-dd-HH\\}(\\.gz)?")) {
+ logRotation = 60 * 60;
+ }
+ else {
+ log.warn(
+ "Oozie WS "
+ + logType
+ + " log will be disabled, RollingPolicy.FileNamePattern [{0}] should end with "
+ + "'-%d{yyyy-MM-dd-HH}' or '-%d{yyyy-MM-dd-HH}.gz' and also start with the value of "
+ + "log4j.appender." + logType + ".File [{1}]", pattern, logFile);
+ isLogOverEnable = false;
+ }
+ if (logRotation > 0) {
+ logPath = logFile.substring(0, i);
+ logFileName = logFile.substring(i + 1);
+ }
+ }
+ }
+ else {
+ log.warn("Oozie WS "
+ + logType
+ + " log will be disabled, log4j.appender.oozie ["
+ + appenderClass
+ + "] should be "
+ + "either org.apache.log4j.DailyRollingFileAppender or org.apache.log4j.rolling.RollingFileAppender "
+ + "to enable it");
+ isLogOverEnable = false;
+ }
+ }
+ }
+ }
+
+ public String getLogPath() {
+ return logPath;
+ }
+
+ public String getLogFileName() {
+ return logFileName;
+ }
+
+ public boolean isLogOverEnable() {
+ return isLogOverEnable;
+ }
+
+ public int getLogRotation() {
+ return logRotation;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/oozie/blob/95d17f26/core/src/main/java/org/apache/oozie/service/ZKXLogStreamingService.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/service/ZKXLogStreamingService.java b/core/src/main/java/org/apache/oozie/service/ZKXLogStreamingService.java
index 94d8cb3..b28a591 100644
--- a/core/src/main/java/org/apache/oozie/service/ZKXLogStreamingService.java
+++ b/core/src/main/java/org/apache/oozie/service/ZKXLogStreamingService.java
@@ -15,7 +15,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.apache.oozie.service;
import java.io.BufferedReader;
@@ -114,7 +113,8 @@ public class ZKXLogStreamingService extends XLogStreamingService implements Serv
}
// Otherwise, we have to go collate relevant logs from the other Oozie servers
else {
- collateLogs(filter, startTime, endTime, writer, params);
+ collateLogs(filter, startTime, endTime, writer, params, xLogService.getOozieLogPath(),
+ xLogService.getOozieLogName(), xLogService.getOozieLogRotation(), RestConstants.JOB_SHOW_LOG);
}
}
else {
@@ -123,19 +123,56 @@ public class ZKXLogStreamingService extends XLogStreamingService implements Serv
}
/**
+ * Stream the error log of a job. It contacts any other running Oozie servers to collate relevant error logs while streaming.
+ *
+ * @param filter log streamer filter.
+ * @param startTime start time for log events to filter.
+ * @param endTime end time for log events to filter.
+ * @param writer writer to stream the log to.
+ * @param params additional parameters from the request
+ * @throws IOException thrown if the log cannot be streamed.
+ */
+ public void streamErrorLog(XLogFilter filter, Date startTime, Date endTime, Writer writer, Map<String, String[]> params)
+ throws IOException {
+ XLogService xLogService = Services.get().get(XLogService.class);
+ if (xLogService.isErrorLogEnable()) {
+ // If ALL_SERVERS_PARAM is set to false, then only stream our log
+ if (!Services.get().get(JobsConcurrencyService.class).isAllServerRequest(params)) {
+ new XLogStreamer(filter, xLogService.getOozieErrorLogPath(), xLogService.getOozieErrorLogName(),
+ xLogService.getOozieErrorLogRotation()).streamLog(writer, startTime, endTime, bufferLen);
+ }
+ // Otherwise, we have to go collate relevant logs from the other Oozie servers
+ else {
+ collateLogs(filter, startTime, endTime, writer, params, xLogService.getOozieLogPath(),
+ xLogService.getOozieErrorLogName(), xLogService.getOozieErrorLogRotation(),
+ RestConstants.JOB_SHOW_ERROR_LOG);
+ }
+ }
+ else {
+ writer.write("Error Log streaming disabled!!");
+ }
+ }
+
+
+ /**
* Contacts each of the other Oozie servers, gets their logs for the job, collates them, and sends them to the user via the
* Writer. It will make sure to not read all of the log messages into memory at the same time to not use up the heap. If there
* is a problem talking to one of the other servers, it will ignore that server and prepend a message to the Writer about it.
* For getting the logs from this server, it won't use the REST API and instead get them directly to be more efficient.
*
- * @param filter
- * @param startTime
- * @param endTime
- * @param writer
- * @throws IOException
+ * @param filter the job filter
+ * @param startTime the job start time
+ * @param endTime the job end time
+ * @param writer the writer
+ * @param params the params
+ * @param logPath the log path
+ * @param logName the log name
+ * @param rotation the rotation
+ * @param logType the log type
+ * @throws IOException Signals that an I/O exception has occurred.
*/
private void collateLogs(XLogFilter filter, Date startTime, Date endTime, Writer writer,
- Map<String, String[]> params) throws IOException {
+ Map<String, String[]> params, String logPath, String logName, int rotation, final String logType) throws IOException {
XLogService xLogService = Services.get().get(XLogService.class);
List<String> badOozies = new ArrayList<String>();
List<ServiceInstance<Map>> oozies = null;
@@ -153,8 +190,8 @@ public class ZKXLogStreamingService extends XLogStreamingService implements Serv
String otherId = oozieMeta.get(ZKUtils.ZKMetadataKeys.OOZIE_ID);
// If it's this server, we can just get them directly
if (otherId.equals(zk.getZKId())) {
- BufferedReader reader = new XLogStreamer(filter, xLogService.getOozieLogPath(), xLogService.getOozieLogName(),
- xLogService.getOozieLogRotation()).makeReader(startTime, endTime);
+ BufferedReader reader = new XLogStreamer(filter, logPath, logName, rotation).makeReader(startTime,
+ endTime);
parsers.add(new TimestampedMessageParser(reader, filter));
}
// If it's another server, we'll have to use the REST API
@@ -165,7 +202,7 @@ public class ZKXLogStreamingService extends XLogStreamingService implements Serv
// It's important that we specify ALL_SERVERS_PARAM=false in the GET request to prevent the other Oozie
// Server from trying aggregate logs from the other Oozie servers (and creating an infinite recursion)
final String url = otherUrl + "/v" + OozieClient.WS_PROTOCOL_VERSION + "/" + RestConstants.JOB
- + "/" + jobId + "?" + RestConstants.JOB_SHOW_PARAM + "=" + RestConstants.JOB_SHOW_LOG
+ + "/" + jobId + "?" + RestConstants.JOB_SHOW_PARAM + "=" + logType
+ "&" + RestConstants.ALL_SERVER_REQUEST + "=false" + AuthUrlClient.getQueryParamString(params);
BufferedReader reader = AuthUrlClient.callServer(url);
http://git-wip-us.apache.org/repos/asf/oozie/blob/95d17f26/core/src/main/java/org/apache/oozie/servlet/BaseJobServlet.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/servlet/BaseJobServlet.java b/core/src/main/java/org/apache/oozie/servlet/BaseJobServlet.java
index c94d1e2..5690787 100644
--- a/core/src/main/java/org/apache/oozie/servlet/BaseJobServlet.java
+++ b/core/src/main/java/org/apache/oozie/servlet/BaseJobServlet.java
@@ -295,6 +295,10 @@ public abstract class BaseJobServlet extends JsonRestServlet {
response.setContentType(TEXT_UTF8);
streamJobLog(request, response);
}
+ else if (show.equals(RestConstants.JOB_SHOW_ERROR_LOG)) {
+ response.setContentType(TEXT_UTF8);
+ streamJobErrorLog(request, response);
+ }
else if (show.equals(RestConstants.JOB_SHOW_DEFINITION)) {
stopCron();
response.setContentType(XML_UTF8);
@@ -426,6 +430,18 @@ public abstract class BaseJobServlet extends JsonRestServlet {
IOException;
/**
+ * abstract method to get and stream error log information of job, either workflow, coordinator or bundle
+ *
+ * @param request
+ * @param response
+ * @throws XServletException
+ * @throws IOException
+ */
+ abstract void streamJobErrorLog(HttpServletRequest request, HttpServletResponse response) throws XServletException,
+ IOException;
+
+
+ /**
* abstract method to create and stream image for runtime DAG -- workflow only
*
* @param request
@@ -482,5 +498,4 @@ public abstract class BaseJobServlet extends JsonRestServlet {
*/
abstract String getJobStatus(HttpServletRequest request, HttpServletResponse response)
throws XServletException, IOException;
-}
-
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/oozie/blob/95d17f26/core/src/main/java/org/apache/oozie/servlet/V0JobServlet.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/servlet/V0JobServlet.java b/core/src/main/java/org/apache/oozie/servlet/V0JobServlet.java
index b160b46..3e186f9 100644
--- a/core/src/main/java/org/apache/oozie/servlet/V0JobServlet.java
+++ b/core/src/main/java/org/apache/oozie/servlet/V0JobServlet.java
@@ -194,6 +194,13 @@ public class V0JobServlet extends BaseJobServlet {
}
}
+ @Override
+ protected void streamJobErrorLog(HttpServletRequest request, HttpServletResponse response) throws XServletException,
+ IOException {
+ throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0306);
+ }
+
+
/*
* Not implemented in v0
*/
http://git-wip-us.apache.org/repos/asf/oozie/blob/95d17f26/core/src/main/java/org/apache/oozie/servlet/V1JobServlet.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/servlet/V1JobServlet.java b/core/src/main/java/org/apache/oozie/servlet/V1JobServlet.java
index eed7ca1..64b97c2 100644
--- a/core/src/main/java/org/apache/oozie/servlet/V1JobServlet.java
+++ b/core/src/main/java/org/apache/oozie/servlet/V1JobServlet.java
@@ -1097,4 +1097,10 @@ public class V1JobServlet extends BaseJobServlet {
IOException {
throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0302, "Not supported in v1");
}
+
+ @Override
+ protected void streamJobErrorLog(HttpServletRequest request, HttpServletResponse response) throws XServletException,
+ IOException {
+ throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0302, "Not supported in v1");
+ }
}
http://git-wip-us.apache.org/repos/asf/oozie/blob/95d17f26/core/src/main/java/org/apache/oozie/servlet/V2JobServlet.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/servlet/V2JobServlet.java b/core/src/main/java/org/apache/oozie/servlet/V2JobServlet.java
index da81b49..5238426 100644
--- a/core/src/main/java/org/apache/oozie/servlet/V2JobServlet.java
+++ b/core/src/main/java/org/apache/oozie/servlet/V2JobServlet.java
@@ -27,6 +27,7 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration;
+import org.apache.oozie.BaseEngine;
import org.apache.oozie.BaseEngineException;
import org.apache.oozie.BundleEngine;
import org.apache.oozie.CoordinatorActionBean;
@@ -218,4 +219,44 @@ public class V2JobServlet extends V1JobServlet {
}
return status;
}
+ @SuppressWarnings("unchecked")
+ @Override
+ protected void streamJobErrorLog(HttpServletRequest request, HttpServletResponse response) throws XServletException,
+ IOException {
+
+ String jobId = getResourceName(request);
+ try {
+ getBaseEngine(jobId, getUser(request)).streamErrorLog(jobId, response.getWriter(), request.getParameterMap());
+ }
+ catch (DagEngineException ex) {
+ throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ex);
+ }
+ catch (BaseEngineException e) {
+ throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, e);
+ }
+
+ }
+
+ /**
+ * Gets the base engine based on jobId.
+ *
+ * @param jobId the jobId
+ * @param user the user
+ * @return the baseEngine
+ */
+ final public BaseEngine getBaseEngine(String jobId, String user) {
+ if (jobId.endsWith("-W")) {
+ return Services.get().get(DagEngineService.class).getDagEngine(user);
+ }
+ else if (jobId.endsWith("-B")) {
+ return Services.get().get(BundleEngineService.class).getBundleEngine(user);
+ }
+ else if (jobId.endsWith("-C")) {
+ return Services.get().get(CoordinatorEngineService.class).getCoordinatorEngine(user);
+ }
+ else {
+ throw new RuntimeException("Unknown job Type");
+ }
+ }
+
}
http://git-wip-us.apache.org/repos/asf/oozie/blob/95d17f26/core/src/main/java/org/apache/oozie/util/XLogUserFilterParam.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/util/XLogUserFilterParam.java b/core/src/main/java/org/apache/oozie/util/XLogUserFilterParam.java
index af9b979..a00a79f 100644
--- a/core/src/main/java/org/apache/oozie/util/XLogUserFilterParam.java
+++ b/core/src/main/java/org/apache/oozie/util/XLogUserFilterParam.java
@@ -109,7 +109,7 @@ public class XLogUserFilterParam {
private void parseFilterParam(String param) throws Exception {
this.params = param;
- if (StringUtils.isEmpty(param)) {
+ if (StringUtils.isEmpty(param) || StringUtils.equalsIgnoreCase(param, "null")) {
return;
}
for (String keyValue : param.split(";")) {
http://git-wip-us.apache.org/repos/asf/oozie/blob/95d17f26/core/src/test/java/org/apache/oozie/service/TestXLogStreamingService.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/oozie/service/TestXLogStreamingService.java b/core/src/test/java/org/apache/oozie/service/TestXLogStreamingService.java
index 5ad6dea..aedd35c 100644
--- a/core/src/test/java/org/apache/oozie/service/TestXLogStreamingService.java
+++ b/core/src/test/java/org/apache/oozie/service/TestXLogStreamingService.java
@@ -21,7 +21,6 @@ package org.apache.oozie.service;
import org.apache.commons.logging.LogFactory;
import org.apache.oozie.test.XTestCase;
import org.apache.oozie.util.XLogFilter;
-import org.apache.oozie.util.IOUtils;
import org.apache.oozie.util.XLogUserFilterParam;
import java.io.File;
@@ -129,6 +128,95 @@ public class TestXLogStreamingService extends XTestCase {
assertFalse(doStreamDisabledCheckWithServices());
}
+ public void testDisableErrorLogOverWS() throws Exception {
+ Properties props = new Properties();
+ // Test missing logfile
+ props.setProperty("log4j.appender.oozieError.File", "");
+ File propsFile = new File(getTestCaseConfDir(), "test-disable-log-over-ws-log4j.properties");
+ FileOutputStream fos = new FileOutputStream(propsFile);
+ props.store(fos, "");
+ setSystemProperty(XLogService.LOG4J_FILE, propsFile.getName());
+ assertTrue(doerrorStreamDisabledCheckWithServices());
+
+ // Test non-absolute path for logfile
+ props.setProperty("log4j.appender.oozieError.File", "oozie-error.log");
+ fos = new FileOutputStream(propsFile);
+ props.store(fos, "");
+ assertTrue(doerrorStreamDisabledCheckWithServices());
+
+ // Test missing appender class
+ props.setProperty("log4j.appender.oozieError.File", "${oozie.log.dir}/oozie-error.log");
+ props.setProperty("log4j.appender.oozieError", "");
+ fos = new FileOutputStream(propsFile);
+ props.store(fos, "");
+ assertTrue(doerrorStreamDisabledCheckWithServices());
+
+ // Test appender class not DailyRollingFileAppender or RollingFileAppender
+ props.setProperty("log4j.appender.oozieError", "org.blah.blah");
+ fos = new FileOutputStream(propsFile);
+ props.store(fos, "");
+ assertTrue(doerrorStreamDisabledCheckWithServices());
+
+ // Test DailyRollingFileAppender but missing DatePattern
+ props.setProperty("log4j.appender.oozieError", "org.apache.log4j.DailyRollingFileAppender");
+ props.setProperty("log4j.appender.oozieError.DatePattern", "");
+ fos = new FileOutputStream(propsFile);
+ props.store(fos, "");
+ assertTrue(doerrorStreamDisabledCheckWithServices());
+
+ // Test DailyRollingFileAppender but DatePattern that doesn't end with 'HH' or 'dd'
+ props.setProperty("log4j.appender.oozieError.DatePattern", "'.'yyyy-MM");
+ fos = new FileOutputStream(propsFile);
+ props.store(fos, "");
+ assertTrue(doerrorStreamDisabledCheckWithServices());
+
+ // Test DailyRollingFileAppender with everything correct (dd)
+ props.setProperty("log4j.appender.oozieError.DatePattern", "'.'yyyy-MM-dd");
+ fos = new FileOutputStream(propsFile);
+ props.store(fos, "");
+ assertFalse(doerrorStreamDisabledCheckWithServices());
+
+ // Test DailyRollingFileAppender with everything correct (HH)
+ props.setProperty("log4j.appender.oozieError.DatePattern", "'.'yyyy-MM-dd-HH");
+ fos = new FileOutputStream(propsFile);
+ props.store(fos, "");
+ assertFalse(doerrorStreamDisabledCheckWithServices());
+
+ // Test RollingFileAppender but missing FileNamePattern
+ props.setProperty("log4j.appender.oozieError", "org.apache.log4j.rolling.RollingFileAppender");
+ props.setProperty("log4j.appender.oozieError.RollingPolicy.FileNamePattern", "");
+ fos = new FileOutputStream(propsFile);
+ props.store(fos, "");
+ assertTrue(doerrorStreamDisabledCheckWithServices());
+
+ // Test RollingFileAppender but FileNamePattern with incorrect ending
+ props.setProperty("log4j.appender.oozieError.RollingPolicy.FileNamePattern", "${oozie.log.dir}/oozie-error.log-blah");
+ fos = new FileOutputStream(propsFile);
+ props.store(fos, "");
+ assertTrue(doerrorStreamDisabledCheckWithServices());
+
+ // Test RollingFileAppender but FileNamePattern with incorrect beginning
+ props.setProperty("log4j.appender.oozieError.RollingPolicy.FileNamePattern",
+ "${oozie.log.dir}/blah.log-%d{yyyy-MM-dd-HH}");
+ fos = new FileOutputStream(propsFile);
+ props.store(fos, "");
+ assertTrue(doerrorStreamDisabledCheckWithServices());
+
+ // Test RollingFileAppender with everything correct
+ props.setProperty("log4j.appender.oozieError.RollingPolicy.FileNamePattern",
+ "${oozie.log.dir}/oozie-error.log-%d{yyyy-MM-dd-HH}");
+ fos = new FileOutputStream(propsFile);
+ props.store(fos, "");
+ assertFalse(doerrorStreamDisabledCheckWithServices());
+
+ // Test RollingFileAppender with everything correct (gz)
+ props.setProperty("log4j.appender.oozieError.RollingPolicy.FileNamePattern",
+ "${oozie.log.dir}/oozie-error.log-%d{yyyy-MM-dd-HH}.gz");
+ fos = new FileOutputStream(propsFile);
+ props.store(fos, "");
+ assertFalse(doerrorStreamDisabledCheckWithServices());
+ }
+
public void testNoDashInConversionPattern() throws Exception{
XLogFilter.reset();
XLogFilter.defineParameter("USER");
@@ -177,6 +265,79 @@ public class TestXLogStreamingService extends XTestCase {
}
}
+ public void testErrorLog() throws Exception{
+ XLogFilter.reset();
+ XLogFilter.defineParameter("USER");
+ XLogFilter.defineParameter("GROUP");
+ XLogFilter.defineParameter("TOKEN");
+ XLogFilter.defineParameter("APP");
+ XLogFilter.defineParameter("JOB");
+ XLogFilter.defineParameter("ACTION");
+ XLogFilter xf = new XLogFilter(new XLogUserFilterParam(null));
+
+ xf.setParameter("USER", "oozie");
+ xf.setLogLevel("DEBUG|INFO");
+ // Previously, a dash ("-") was always required somewhere in a line in order for that line to pass the filter; this test
+ // checks that this condition is no longer required for log streaming to work
+ File log4jFile = new File(getTestCaseConfDir(), "test-log4j.properties");
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ InputStream is = cl.getResourceAsStream("test-no-dash-log4j.properties");
+ Properties log4jProps = new Properties();
+ log4jProps.load(is);
+ // prevent conflicts with other tests by changing the log file location
+ log4jProps.setProperty("log4j.appender.oozie.File", getTestCaseDir() + "/oozie.log");
+ log4jProps.setProperty("log4j.appender.oozieError.File", getTestCaseDir() + "/oozie-error.log");
+
+ log4jProps.store(new FileOutputStream(log4jFile), "");
+ setSystemProperty(XLogService.LOG4J_FILE, log4jFile.getName());
+ try {
+ new Services().init();
+ assertFalse(doStreamDisabledCheck());
+ LogFactory.getLog("a").info("2009-06-24 02:43:14,505 INFO _L1_:317 - SERVER[foo] USER[oozie] GROUP[oozie] TOKEN[-] "
+ + "APP[-] JOB[-] ACTION[-] Released Lock");
+ LogFactory.getLog("a").warn("2009-06-24 02:44:14,505 WARN _L2_:317 - SERVER[foo] USER[oozie] GROUP[oozie] TOKEN[-] "
+ + "APP[-] JOB[-] ACTION[-] Error while writing to file");
+ LogFactory.getLog("a").info("2009-06-24 02:45:14,505 INFO _L3_:317 - SERVER[foo] USER[blah] GROUP[oozie] TOKEN[-]"
+ + "APP[-] JOB[-] ACTION[-] Released Lock");
+ LogFactory.getLog("a").error("2009-06-24 02:46:14,505 ERROR _L4_:317 - SERVER[foo] USER[oozie] GROUP[oozie] TOKEN[-] "
+ + "APP[-] JOB[-] ACTION[-] Error while writing to DB");
+ LogFactory.getLog("a").info("2009-06-24 02:47:14,505 INFO _L5_:317 SERVER[foo] USER[oozie] GROUP[oozie] TOKEN[-] "
+ + "APP[-] JOB[-] ACTION[-] Released Lock");
+ LogFactory.getLog("a").fatal("2009-06-24 02:48:14,505 FATAL _L6_:317 SERVER[foo] USER[blah] GROUP[oozie] TOKEN[-] "
+ + "APP[-] JOB[-] ACTION[-] Released Lock");
+ String out = doStreamLog(xf);
+ String outArr[] = out.split("\n");
+ // Lines 2 and 4 are filtered out because they have the wrong user
+ assertEquals(2, outArr.length);
+ assertTrue(outArr[0].contains("_L1_"));
+ assertFalse(out.contains("_L3_"));
+ assertTrue(outArr[1].contains("_L5_"));
+ assertFalse(out.contains("_L4_"));
+ XLogFilter.reset();
+ XLogFilter.defineParameter("USER");
+ XLogFilter.defineParameter("GROUP");
+ XLogFilter.defineParameter("TOKEN");
+ XLogFilter.defineParameter("APP");
+ XLogFilter.defineParameter("JOB");
+ XLogFilter.defineParameter("ACTION");
+ xf = new XLogFilter(new XLogUserFilterParam(null));
+
+ xf.setParameter("USER", "oozie");
+
+ String errorOut = doStreamErrorLog(xf);
+ String errorOutArr[] = errorOut.split("\n");
+ // Lines 2 and 4 are filtered out because they have the wrong user
+ assertEquals(2, errorOutArr.length);
+ assertTrue(errorOutArr[0].contains("_L2_"));
+ assertTrue(errorOutArr[1].contains("_L4_"));
+ assertFalse(errorOut.contains("_L6_"));
+ }
+ finally {
+ Services.get().destroy();
+ }
+ }
+
+
private boolean doStreamDisabledCheckWithServices() throws Exception {
boolean result = false;
try {
@@ -200,4 +361,26 @@ public class TestXLogStreamingService extends XTestCase {
Services.get().get(XLogStreamingService.class).streamLog(xf, null, null, w, new HashMap<String, String[]>());
return w.toString();
}
+ private String doStreamErrorLog(XLogFilter xf) throws Exception {
+ StringWriter w = new StringWriter();
+ Services.get().get(XLogStreamingService.class).streamErrorLog(xf, null, null, w, new HashMap<String, String[]>());
+ return w.toString();
+ }
+
+ private boolean doErrorStreamDisabledCheck() throws Exception {
+ XLogFilter xf = new XLogFilter(new XLogUserFilterParam(null));
+ return doStreamErrorLog(xf).equals("Error Log is disabled!!");
+ }
+
+ private boolean doerrorStreamDisabledCheckWithServices() throws Exception {
+ boolean result = false;
+ try {
+ new Services().init();
+ result = doErrorStreamDisabledCheck();
+ }
+ finally {
+ Services.get().destroy();
+ }
+ return result;
+ }
}
http://git-wip-us.apache.org/repos/asf/oozie/blob/95d17f26/core/src/test/java/org/apache/oozie/service/TestZKXLogStreamingService.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/oozie/service/TestZKXLogStreamingService.java b/core/src/test/java/org/apache/oozie/service/TestZKXLogStreamingService.java
index 2fd08b3..fca8d84 100644
--- a/core/src/test/java/org/apache/oozie/service/TestZKXLogStreamingService.java
+++ b/core/src/test/java/org/apache/oozie/service/TestZKXLogStreamingService.java
@@ -15,7 +15,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.apache.oozie.service;
import java.io.File;
@@ -34,7 +33,6 @@ import org.apache.oozie.test.EmbeddedServletContainer;
import org.apache.oozie.test.ZKXTestCase;
import org.apache.oozie.util.DateUtils;
import org.apache.oozie.util.XLogFilter;
-import org.apache.oozie.util.IOUtils;
import org.apache.oozie.util.ZKUtils;
public class TestZKXLogStreamingService extends ZKXTestCase {
@@ -200,7 +198,15 @@ public class TestZKXLogStreamingService extends ZKXTestCase {
return doStreamLog(xf, new HashMap<String, String[]>());
}
+ protected String doStreamErrorLog(XLogFilter xf) throws Exception {
+ return doStreamLog(xf, new HashMap<String, String[]>(), true);
+ }
+
protected String doStreamLog(XLogFilter xf, Map<String, String[]> param) throws Exception {
+ return doStreamLog(xf, param, false);
+ }
+
+ protected String doStreamLog(XLogFilter xf, Map<String, String[]> param, boolean isErrorLog) throws Exception {
StringWriter w = new StringWriter();
ZKXLogStreamingService zkxlss = new ZKXLogStreamingService();
try {
@@ -208,7 +214,12 @@ public class TestZKXLogStreamingService extends ZKXTestCase {
services.setService(ZKJobsConcurrencyService.class);
zkxlss.init(services);
sleep(1000); // Sleep to allow ZKUtils ServiceCache to update
- zkxlss.streamLog(xf, null, null, w, param);
+ if (isErrorLog) {
+ zkxlss.streamErrorLog(xf, null, null, w, param);
+ }
+ else {
+ zkxlss.streamLog(xf, null, null, w, param);
+ }
}
finally {
zkxlss.destroy();
@@ -463,4 +474,113 @@ public class TestZKXLogStreamingService extends ZKXTestCase {
}
}
+ public void testStreamingWithMultipleOozieServers_errorLog() throws Exception {
+ XLogFilter.reset();
+
+ File log4jFile = new File(getTestCaseConfDir(), "test-log4j.properties");
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ InputStream is = cl.getResourceAsStream("test-no-dash-log4j.properties");
+ Properties log4jProps = new Properties();
+ log4jProps.load(is);
+ // prevent conflicts with other tests by changing the log file location
+ log4jProps.setProperty("log4j.appender.oozie.File", getTestCaseDir() + "/oozie.log");
+ log4jProps.setProperty("log4j.appender.oozieError.File", getTestCaseDir() + "/oozie-error.log");
+
+ log4jProps.store(new FileOutputStream(log4jFile), "");
+ setSystemProperty(XLogService.LOG4J_FILE, log4jFile.getName());
+ Services.get().get(XLogService.class).init(Services.get());
+
+ File logFile = new File(Services.get().get(XLogService.class).getOozieErrorLogPath(), Services.get()
+ .get(XLogService.class).getOozieErrorLogName());
+ logFile.getParentFile().mkdirs();
+ FileWriter logWriter = new FileWriter(logFile);
+ // local logs
+ StringBuffer bf = new StringBuffer();
+ bf.append(
+ "2014-02-06 00:26:56,126 WARN CoordActionInputCheckXCommand:545 [pool-2-thread-26] - USER[-] GROUP[-] "
+ + "TOKEN[-] APP[-] JOB[0000003-140205233038063-oozie-oozi-C] ACTION[0000003-140205233038063-oozie-oozi-C@1] "
+ + "checking for the file ~:8020/user/purushah/examples/input-data/rawLogs/2010/01/01/01/00/_SUCCESS\n")
+ .append("2014-02-06 00:26:56,150 WARN CoordActionInputCheckXCommand:539 [pool-2-thread-26] - USER[-] GROUP[-] "
+ + "TOKEN[-] APP[-] JOB[0000003-140205233038063-oozie-oozi-C] ACTION[0000003-140205233038063-oozie-oozi-C@1] "
+ + "[0000003-140205233038063-oozie-oozi-C@1]::ActionInputCheck::File::8020/user/purushah/examples/input-data/"
+ + "rawLogs/2010/01/01/01/00/_SUCCESS, Exists? :false" + "Action updated in DB! _L1_")
+ .append("\n")
+ .append("2014-02-06 00:27:56,126 WARN CoordActionInputCheckXCommand:545 [pool-2-thread-26] - USER[-] GROUP[-] "
+ + "TOKEN[-] APP[-] JOB[0000003-140205233038063-oozie-oozi-C] ACTION[0000003-140205233038063-oozie-oozi-C@2] "
+ + "checking for the file ~:8020/user/purushah/examples/input-data/rawLogs/2010/01/01/01/00/_SUCCESS\n")
+ .append("2014-02-06 00:27:56,150 WARN CoordActionInputCheckXCommand:539 [pool-2-thread-26] - USER[-] GROUP[-] "
+ + "TOKEN[-] APP[-] JOB[0000003-140205233038063-oozie-oozi-C] ACTION[0000003-140205233038063-oozie-oozi-C@2] "
+ + "[0000003-140205233038063-oozie-oozi-C@2]::ActionInputCheck::File::8020/user/purushah/examples/input-data/"
+ + "rawLogs/2010/01/01/01/00/_SUCCESS, Exists? :false" + "Action updated in DB! _L2_")
+ .append("\n");
+ logWriter.append(bf);
+
+ logWriter.close();
+
+ XLogFilter.reset();
+ XLogFilter.defineParameter("USER");
+ XLogFilter.defineParameter("GROUP");
+ XLogFilter.defineParameter("TOKEN");
+ XLogFilter.defineParameter("APP");
+ XLogFilter.defineParameter("JOB");
+ XLogFilter.defineParameter("ACTION");
+
+ XLogFilter xf = new XLogFilter();
+
+ xf.setParameter("USER", ".*");
+ xf.setParameter("GROUP", ".*");
+ xf.setParameter("TOKEN", ".*");
+ xf.setParameter("APP", ".*");
+ xf.setParameter("JOB", "0000003-140205233038063-oozie-oozi-C");
+ xf.setParameter(DagXLogInfoService.ACTION, "0000003-140205233038063-oozie-oozi-C@1");
+
+
+ String out = doStreamErrorLog(xf);
+ String[] outArr = out.split("\n");
+ assertEquals(2, outArr.length);
+ assertTrue(out.contains("_L1_"));
+ assertFalse(out.contains("_L2_"));
+
+
+ // We'll use a DummyZKOozie to create an entry in ZK and then set its
+ // url to an (unrelated) servlet that will simply return
+ // some log messages
+ DummyZKOozie dummyOozie = null;
+ EmbeddedServletContainer container = new EmbeddedServletContainer("oozie");
+ container.addServletEndpoint("/other-oozie-server/*", DummyLogStreamingServlet.class);
+ try {
+ container.start();
+ dummyOozie = new DummyZKOozie("9876", container.getServletURL("/other-oozie-server/*"));
+ StringBuffer newLog = new StringBuffer();
+
+ newLog.append(
+ "2014-02-07 00:26:56,126 WARN CoordActionInputCheckXCommand:545 [pool-2-thread-26] - USER[-] GROUP[-] "
+ + "TOKEN[-] APP[-] JOB[0000003-140205233038063-oozie-oozi-C] ACTION[0000003-140205233038063-oozie-oozi-C@1] "
+ + "checking for the file ~:8020/user/purushah/examples/input-data/rawLogs/2010/01/01/01/00/_SUCCESS\n")
+ .append("2014-02-07 00:26:56,150 WARN CoordActionInputCheckXCommand:539 [pool-2-thread-26] - USER[-] GROUP[-] "
+ + "TOKEN[-] APP[-] JOB[0000003-140205233038063-oozie-oozi-C] ACTION[0000003-140205233038063-oozie-oozi-C@1] "
+ + "[0000003-140205233038063-oozie-oozi-C@1]::ActionInputCheck::File::8020/user/purushah/examples/input-data/"
+ + "rawLogs/2010/01/01/01/00/_SUCCESS, Exists? :false" + "Action updated in DB! _L3_")
+ .append("\n");
+
+ DummyLogStreamingServlet.logs = newLog.toString();
+
+
+ out = doStreamErrorLog(xf);
+ outArr = out.split("\n");
+ assertEquals(4, outArr.length);
+ assertTrue(out.contains("_L1_"));
+ assertTrue(out.contains("_L3_"));
+ assertFalse(out.contains("_L2_"));
+
+ container.stop();
+ }
+ finally {
+ if (dummyOozie != null) {
+ dummyOozie.teardown();
+ }
+ container.stop();
+ }
+ }
+
}
http://git-wip-us.apache.org/repos/asf/oozie/blob/95d17f26/core/src/test/resources/test-no-dash-log4j.properties
----------------------------------------------------------------------
diff --git a/core/src/test/resources/test-no-dash-log4j.properties b/core/src/test/resources/test-no-dash-log4j.properties
index 36b7b18..2ff353e 100644
--- a/core/src/test/resources/test-no-dash-log4j.properties
+++ b/core/src/test/resources/test-no-dash-log4j.properties
@@ -27,4 +27,24 @@ log4j.appender.oozie.layout.ConversionPattern=%d{ISO8601} %5p %c{1}:%L %m%n
log4j.appender.oozie.RollingPolicy.FileNamePattern=${log4j.appender.oozie.File}-%d{yyyy-MM-dd-HH}
log4j.appender.oozie.RollingPolicy.MaxHistory=720
-log4j.logger.a=ALL, oozie
+log4j.appender.oozieError=org.apache.log4j.rolling.RollingFileAppender
+log4j.appender.oozieError.RollingPolicy=org.apache.oozie.util.OozieRollingPolicy
+log4j.appender.oozieError.File=${oozie.log.dir}/oozie-error.log
+log4j.appender.oozieError.Append=true
+log4j.appender.oozieError.layout=org.apache.log4j.PatternLayout
+log4j.appender.oozieError.layout.ConversionPattern=%d{ISO8601} %5p %c{1}:%L - SERVER[${oozie.instance.id}] %m%n
+# The FileNamePattern must end with "-%d{yyyy-MM-dd-HH}.gz" or "-%d{yyyy-MM-dd-HH}" and also start with the
+# value of log4j.appender.oozieError.File
+log4j.appender.oozieError.RollingPolicy.FileNamePattern=${log4j.appender.oozieError.File}-%d{yyyy-MM-dd-HH}
+# The MaxHistory controls how many log files will be retained (720 hours / 24 hours per day = 30 days); -1 to disable
+log4j.appender.oozieError.RollingPolicy.MaxHistory=720
+log4j.appender.oozieError.filter.1 = org.apache.log4j.varia.LevelMatchFilter
+log4j.appender.oozieError.filter.1.levelToMatch = WARN
+log4j.appender.oozieError.filter.2 = org.apache.log4j.varia.LevelMatchFilter
+log4j.appender.oozieError.filter.2.levelToMatch = ERROR
+log4j.appender.oozieError.filter.3 = org.apache.log4j.varia.LevelMatchFilter
+log4j.appender.oozieError.filter.3.levelToMatch = FATAL
+log4j.appender.oozieError.filter.4 = org.apache.log4j.varia.DenyAllFilter
+
+
+log4j.logger.a=ALL, oozie, oozieError
http://git-wip-us.apache.org/repos/asf/oozie/blob/95d17f26/docs/src/site/twiki/DG_CommandLineTool.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/DG_CommandLineTool.twiki b/docs/src/site/twiki/DG_CommandLineTool.twiki
index 4ac73f9..e801e31 100644
--- a/docs/src/site/twiki/DG_CommandLineTool.twiki
+++ b/docs/src/site/twiki/DG_CommandLineTool.twiki
@@ -606,6 +606,32 @@ $ oozie job -oozie http://localhost:11000/oozie -log 14-20090525161321-oozie-joe
</verbatim>
+---+++ Checking the server error logs of a Workflow, Coordinator or Bundle Job
+
+Example:
+
+<verbatim>
+$ oozie job -oozie http://localhost:11000/oozie -errorlog 0000000-150121110331712-oozie-puru-B
+2015-01-21 11:33:29,090 WARN CoordSubmitXCommand:523 - SERVER[-] USER[-] GROUP[-] TOKEN[-] APP[-] JOB[0000000-150121110331712-oozie-puru-B] ACTION[] SAXException :
+org.xml.sax.SAXParseException; lineNumber: 20; columnNumber: 22; cvc-complex-type.2.4.a: Invalid content was found starting with element 'concurrency'. One of '{"uri:oozie:coordinator:0.2":controls, "uri:oozie:coordinator:0.2":datasets, "uri:oozie:coordinator:0.2":input-events, "uri:oozie:coordinator:0.2":output-events, "uri:oozie:coordinator:0.2":action}' is expected.
+ at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
+ at org.apache.xerces.util.ErrorHandlerWrapper.error(Unknown Source)
+ at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
+ at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
+ at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
+ at org.apache.xerces.impl.xs.XMLSchemaValidator$XSIErrorReporter.reportError(Unknown Source)
+ at org.apache.xerces.impl.xs.XMLSchemaValidator.reportSchemaError(Unknown Source)
+ at org.apache.xerces.impl.xs.XMLSchemaValidator.handleStartElement(Unknown Source)
+ at org.apache.xerces.impl.xs.XMLSchemaValidator.startElement(Unknown Source)
+ at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
+ at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
+ at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
+ at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
+ at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
+ at org.apache.xerces.jaxp.validation.StreamValidatorHelper.validate(Unknown Source)
+ at org.apache.xerces.jaxp.validation.ValidatorImpl.validate(Unknown Source)
+</verbatim>
+
---+++ Checking the server logs for particular actions of a Coordinator Job
Example:
http://git-wip-us.apache.org/repos/asf/oozie/blob/95d17f26/docs/src/site/twiki/WebServicesAPI.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/WebServicesAPI.twiki b/docs/src/site/twiki/WebServicesAPI.twiki
index fc51934..fcefb4a 100644
--- a/docs/src/site/twiki/WebServicesAPI.twiki
+++ b/docs/src/site/twiki/WebServicesAPI.twiki
@@ -1431,6 +1431,29 @@ Content-Type: text/plain;charset=UTF-8
...
</verbatim>
+---++++ Job Error Log
+
+An HTTP GET request retrieves the job error log.
+
+*Request:*
+
+<verbatim>
+GET /oozie/v2/job/0000000-150121110331712-oozie-puru-B?show=errorlog
+</verbatim>
+
+*Response:*
+
+<verbatim>
+HTTP/1.1 200 OK
+Content-Type: text/plain;charset=UTF-8
+2015-01-21 11:33:29,090 WARN CoordSubmitXCommand:523 - SERVER[-] USER[-] GROUP[-] TOKEN[-] APP[-] JOB[0000000-150121110331712-oozie-puru-B] ACTION[] SAXException :
+org.xml.sax.SAXParseException; lineNumber: 20; columnNumber: 22; cvc-complex-type.2.4.a: Invalid content was found starting with element 'concurrency'. One of '{"uri:oozie:coordinator:0.2":controls, "uri:oozie:coordinator:0.2":datasets, "uri:oozie:coordinator:0.2":input-events, "uri:oozie:coordinator:0.2":output-events, "uri:oozie:coordinator:0.2":action}' is expected.
+ at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
+ at org.apache.xerces.util.ErrorHandlerWrapper.error(Unknown Source)
+...
+</verbatim>
+
+
---++++ Filtering the server logs with logfilter options
User can provide multiple option to filter logs using -logfilter opt1=val1;opt2=val1;opt3=val1. This can be used to fetch only just logs of interest faster as fetching Oozie server logs is slow due to the overhead of pattern matching.
http://git-wip-us.apache.org/repos/asf/oozie/blob/95d17f26/release-log.txt
----------------------------------------------------------------------
diff --git a/release-log.txt b/release-log.txt
index 4c60c64..88ba9e3 100644
--- a/release-log.txt
+++ b/release-log.txt
@@ -1,5 +1,6 @@
-- Oozie 4.2.0 release (trunk - unreleased)
+OOZIE-1894 Better error reporting to user (puru)
OOZIE-2120 Many JPAExecutor names are wrong (rkanter)
OOZIE-1722 Add support to Hadoop-2 for AM restarts of the launcher job (jaydeepvishwakarma via rkanter)
OOZIE-2107 Schema config properties should be consistent with ActionExecutor config properties (rkanter)
http://git-wip-us.apache.org/repos/asf/oozie/blob/95d17f26/webapp/src/main/webapp/oozie-console.js
----------------------------------------------------------------------
diff --git a/webapp/src/main/webapp/oozie-console.js b/webapp/src/main/webapp/oozie-console.js
index 8f2098d..e2b37a6 100644
--- a/webapp/src/main/webapp/oozie-console.js
+++ b/webapp/src/main/webapp/oozie-console.js
@@ -45,13 +45,13 @@ Ext.override(Ext.Component, {
function getLogs(url, searchFilter, logStatus, textArea, shouldParseResponse, errorMsg) {
textArea.getEl().dom.value = '';
- url = url + "&logfilter=" +searchFilter;
+ if (searchFilter) {
+ url = url + "&logfilter=" + searchFilter;
+ }
logStatus.getEl().dom.innerText = "Log status : Loading... done";
if (!errorMsg) {
errorMsg = "Fatal Error. Can't load logs.";
- logStatus.getEl().dom.innerText = "Log status : Errored out";
-
}
if (!window.XMLHttpRequest) {
Ext.Ajax.request({
@@ -404,6 +404,17 @@ function jobDetailsPopup(response, request) {
"Available options are recent, start, end, loglevel, text, limit and debug.\n" +
"For more detail refer documentation (/oozie/docs/DG_CommandLineTool.html#Filtering_the_server_logs_with_logfilter_options)"
});
+
+ var jobErrorLogArea = new Ext.form.TextArea({
+ fieldLabel: 'ErrorLogs',
+ editable: false,
+ name: 'errorlogs',
+ width: 1035,
+ height: 400,
+ autoScroll: true,
+ emptyText: ""
+ });
+
function fetchDefinition(workflowId) {
Ext.Ajax.request({
url: getOozieBase() + 'job/' + workflowId + "?show=definition",
@@ -414,6 +425,10 @@ function jobDetailsPopup(response, request) {
});
}
+
+ function fetchErrorLogs(workflowId, errorLogStatus) {
+ getLogs(getOozieBase() + 'job/' + workflowId + "?show=errorlog", null, errorLogStatus, jobErrorLogArea, false, null);
+ }
function fetchLogs(workflowId, logStatus) {
getLogs(getOozieBase() + 'job/' + workflowId + "?show=log", searchFilterBox.getValue(), logStatus, jobLogArea, false, null);
@@ -816,6 +831,9 @@ function jobDetailsPopup(response, request) {
text : 'Log Status : '
});
+ var errorLogStatus = new Ext.form.Label({
+ text : 'Log Status : '
+ });
var getLogButton = new Ext.Button({
text: 'Get Logs',
@@ -826,6 +844,7 @@ function jobDetailsPopup(response, request) {
});
var isLoadedDAG = false;
+ var isErrorLogLoaded = false;
var jobDetailsTab = new Ext.TabPanel({
activeTab: 0,
@@ -853,7 +872,19 @@ function jobDetailsPopup(response, request) {
title: 'Job Log',
items: jobLogArea,
tbar: [ searchFilter, searchFilterBox, getLogButton, {xtype: 'tbfill'}, logStatus]
- }, {
+ },
+ {
+ title: 'Job Error Log',
+ items: jobErrorLogArea,
+ tbar: [ {
+ text: " ",
+ icon: 'ext-2.2/resources/images/default/grid/refresh.gif',
+ handler: function() {
+ fetchErrorLogs(workflowId, errorLogStatus);
+ }
+ }, {xtype: 'tbfill'}, errorLogStatus]
+ },
+ {
title: 'Job DAG',
items: imageContainer,
tbar: [{
@@ -873,6 +904,12 @@ function jobDetailsPopup(response, request) {
}
else if (selectedTab.title == 'Job Definition') {
fetchDefinition(workflowId);
+ }
+ else if (selectedTab.title == 'Job Error Log') {
+ if(!isErrorLogLoaded){
+ fetchErrorLogs(workflowId, errorLogStatus);
+ isErrorLogLoaded=true;
+ }
} else if(selectedTab.title == 'Job DAG') {
if(!isLoadedDAG){
var dagImage= new Ext.ux.Image({
@@ -903,6 +940,7 @@ function jobDetailsPopup(response, request) {
}
function coordJobDetailsPopup(response, request) {
+ var isErrorLogLoaded= false;
var jobDefinitionArea = new Ext.form.TextArea({
fieldLabel: 'Definition',
@@ -927,6 +965,16 @@ function coordJobDetailsPopup(response, request) {
"Available options are recent, start, end, loglevel, text, limit and debug.\n" +
"For more detail refer documentation (/oozie/docs/DG_CommandLineTool.html#Filtering_the_server_logs_with_logfilter_options)"
});
+ var jobErrorLogArea = new Ext.form.TextArea({
+ fieldLabel: 'ErrorLogs',
+ editable: false,
+ id: 'jobErrorLogAreaId',
+ name: 'errorlogs',
+ width: 1035,
+ height: 400,
+ autoScroll: true,
+ emptyText: ""
+ });
var getLogButton = new Ext.Button({
text: 'Get Logs',
ctCls: 'x-btn-over',
@@ -959,8 +1007,9 @@ function coordJobDetailsPopup(response, request) {
var logStatus = new Ext.form.Label({
text : 'Log Status : '
});
-
-
+ var errorLogStatus = new Ext.form.Label({
+ text : 'Log Status : '
+ });
function fetchDefinition(coordJobId) {
Ext.Ajax.request({
url: getOozieBase() + 'job/' + coordJobId + "?show=definition",
@@ -981,6 +1030,11 @@ function coordJobDetailsPopup(response, request) {
'Action List format is wrong. Format should be similar to 1,3-4,7-40');
}
}
+ function fetchErrorLogs(coordJobId) {
+ getLogs(getOozieBase() + 'job/' + coordJobId + "?show=errorlog",
+ null, errorLogStatus, jobErrorLogArea, true, null);
+ }
+
var jobDetails = eval("(" + response.responseText + ")");
var coordJobId = jobDetails["coordJobId"];
@@ -1386,13 +1440,25 @@ function coordJobDetailsPopup(response, request) {
items: jobLogArea,
tbar: [
actionsText,actionsTextBox, searchFilter, searchFilterBox, getLogButton, {xtype: 'tbfill'}, logStatus]
- },{
+ },
+ {
+ title: 'Coord Error Log',
+ items: jobErrorLogArea,
+ tbar: [ {
+ text: " ",
+ icon: 'ext-2.2/resources/images/default/grid/refresh.gif',
+ handler: function() {
+ fetchErrorLogs(coordJobId);
+ }
+ },{xtype: 'tbfill'}, errorLogStatus]
+ },
+ {
title: 'Coord Action Reruns',
items: rerunsUnit,
tbar: [
rerunActionText, rerunActionTextBox, getRerunsButton]
- }]
-});
+ },
+ ]});
jobDetailsTab.addListener("tabchange", function(panel, selectedTab) {
if (selectedTab.title == "Coord Job Info") {
@@ -1405,6 +1471,12 @@ function coordJobDetailsPopup(response, request) {
else if (selectedTab.title == 'Coord Action Reruns') {
rerunsUnit.setVisible(true);
}
+ else if (selectedTab.title == 'Coord Error Log') {
+ if(!isErrorLogLoaded){
+ fetchErrorLogs(coordJobId);
+ isErrorLogLoaded=true;
+ }
+ }
coord_jobs_grid.setVisible(false);
});
var win = new Ext.Window({
@@ -1420,6 +1492,8 @@ function coordJobDetailsPopup(response, request) {
}
function bundleJobDetailsPopup(response, request) {
+
+ var isErrorLogLoaded = false;
var jobDefinitionArea = new Ext.form.TextArea({
fieldLabel: 'Definition',
editable: false,
@@ -1593,6 +1667,16 @@ function bundleJobDetailsPopup(response, request) {
"For more detail refer documentation (/oozie/docs/DG_CommandLineTool.html#Filtering_the_server_logs_with_logfilter_options)"
});
+ var jobErrorLogArea = new Ext.form.TextArea({
+ fieldLabel: 'ErrorLogs',
+ editable: false,
+ name: 'errorlogs',
+ width: 1010,
+ height: 400,
+ autoScroll: true,
+ emptyText: ""
+ });
+
var searchFilter = new Ext.form.Label({
text : 'Enter Search Filter'
});
@@ -1608,6 +1692,9 @@ function bundleJobDetailsPopup(response, request) {
text : 'Log Status : '
});
+ var errorLogStatus = new Ext.form.Label({
+ text : 'Log Status : '
+ });
var getLogButton = new Ext.Button({
text: 'Get Logs',
@@ -1643,8 +1730,20 @@ function bundleJobDetailsPopup(response, request) {
title: 'Bundle Job Log',
items: jobLogArea,
tbar: [searchFilter, searchFilterBox, getLogButton, {xtype: 'tbfill'}, logStatus]
- }]
- });
+ },
+ {
+ title: 'Bundle Error Log',
+ items: jobErrorLogArea,
+ tbar: [ {
+ text: " ",
+ icon: 'ext-2.2/resources/images/default/grid/refresh.gif',
+ handler: function() {
+ getLogs(getOozieBase() + 'job/' + bundleJobId + "?show=errorlog", null, errorLogStatus, jobErrorLogArea,
+ false, null);
+ }
+ }, {xtype: 'tbfill'}, errorLogStatus]
+ }
+ ]});
jobDetailsTab.addListener("tabchange", function(panel, selectedTab) {
if (selectedTab.title == "Bundle Job Info") {
@@ -1654,6 +1753,13 @@ function bundleJobDetailsPopup(response, request) {
else if (selectedTab.title == 'Bundle Job Definition') {
fetchDefinition(bundleJobId);
}
+ else if (selectedTab.title == 'Bundle Error Log') {
+ if(!isErrorLogLoaded){
+ getLogs(getOozieBase() + 'job/' + bundleJobId + "?show=errorlog", null, errorLogStatus, jobErrorLogArea,
+ false, null);
+ isErrorLogLoaded=true;
+ }
+ }
coord_jobs_grid.setVisible(false);
});
@@ -1667,8 +1773,6 @@ function bundleJobDetailsPopup(response, request) {
});
}
-
-
var win = new Ext.Window({
title: 'Job (Name: ' + bundleJobName + '/bundleJobId: ' + bundleJobId + ')',
closable: true,