You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@oozie.apache.org by rk...@apache.org on 2014/06/19 01:18:22 UTC
git commit: OOZIE-1817 Oozie timers are not biased (rkanter)
Repository: oozie
Updated Branches:
refs/heads/master d361ee4d4 -> e16448289
OOZIE-1817 Oozie timers are not biased (rkanter)
Project: http://git-wip-us.apache.org/repos/asf/oozie/repo
Commit: http://git-wip-us.apache.org/repos/asf/oozie/commit/e1644828
Tree: http://git-wip-us.apache.org/repos/asf/oozie/tree/e1644828
Diff: http://git-wip-us.apache.org/repos/asf/oozie/diff/e1644828
Branch: refs/heads/master
Commit: e164482891f0476f14480432f47689780c5c3bd8
Parents: d361ee4
Author: Robert Kanter <rk...@cloudera.com>
Authored: Wed Jun 18 16:08:58 2014 -0700
Committer: Robert Kanter <rk...@cloudera.com>
Committed: Wed Jun 18 16:08:58 2014 -0700
----------------------------------------------------------------------
.../apache/oozie/client/rest/RestConstants.java | 2 +
core/pom.xml | 24 ++
.../java/org/apache/oozie/command/Command.java | 44 +--
.../java/org/apache/oozie/command/XCommand.java | 3 +-
.../coord/CoordActionInputCheckXCommand.java | 6 -
.../coord/CoordActionMaterializeCommand.java | 3 -
.../CoordMaterializeTransitionXCommand.java | 5 +-
.../oozie/service/InstrumentationService.java | 72 ++--
.../service/MetricsInstrumentationService.java | 65 ++++
.../java/org/apache/oozie/service/Services.java | 17 +-
.../org/apache/oozie/service/XLogService.java | 5 -
.../apache/oozie/servlet/BaseAdminServlet.java | 12 +-
.../apache/oozie/servlet/JsonRestServlet.java | 6 +-
.../apache/oozie/servlet/V0AdminServlet.java | 7 +-
.../apache/oozie/servlet/V1AdminServlet.java | 9 +-
.../apache/oozie/servlet/V2AdminServlet.java | 40 +++
.../oozie/util/MetricsInstrumentation.java | 334 +++++++++++++++++++
.../main/java/org/apache/oozie/util/XLog.java | 2 +
.../service/TestInstrumentationService.java | 8 +
.../TestMetricsInstrumentationService.java | 51 +++
.../apache/oozie/util/TestInstrumentation.java | 83 ++---
.../oozie/util/TestMetricsInstrumentation.java | 192 +++++++++++
docs/src/site/twiki/AG_Install.twiki | 20 ++
docs/src/site/twiki/WebServicesAPI.twiki | 89 ++++-
pom.xml | 18 +
release-log.txt | 1 +
webapp/src/main/webapp/index.jsp | 9 +-
webapp/src/main/webapp/oozie-console.js | 135 ++++++--
28 files changed, 1108 insertions(+), 154 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/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 97fd465..5d3fc62 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
@@ -142,6 +142,8 @@ public interface RestConstants {
public static final String ADMIN_QUEUE_DUMP_RESOURCE = "queue-dump";
+ public static final String ADMIN_METRICS_RESOURCE = "metrics";
+
public static final String OOZIE_ERROR_CODE = "oozie-error-code";
public static final String OOZIE_ERROR_MESSAGE = "oozie-error-message";
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/core/pom.xml
----------------------------------------------------------------------
diff --git a/core/pom.xml b/core/pom.xml
index c935dd7..e152266 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -301,6 +301,30 @@
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <scope>compile</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>com.codahale.metrics</groupId>
+ <artifactId>metrics-core</artifactId>
+ <scope>compile</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>com.codahale.metrics</groupId>
+ <artifactId>metrics-jvm</artifactId>
+ <scope>compile</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>com.codahale.metrics</groupId>
+ <artifactId>metrics-json</artifactId>
+ <scope>compile</scope>
+ </dependency>
+
<!-- For drawing runtime DAG -->
<dependency>
<groupId>net.sf.jung</groupId>
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/core/src/main/java/org/apache/oozie/command/Command.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/command/Command.java b/core/src/main/java/org/apache/oozie/command/Command.java
index d3f1011..0e51b8e 100644
--- a/core/src/main/java/org/apache/oozie/command/Command.java
+++ b/core/src/main/java/org/apache/oozie/command/Command.java
@@ -38,6 +38,7 @@ import org.apache.oozie.service.XLogService;
import org.apache.oozie.store.Store;
import org.apache.oozie.store.StoreException;
import org.apache.oozie.store.WorkflowStore;
+import org.apache.oozie.util.InstrumentUtils;
import org.apache.oozie.util.Instrumentation;
import org.apache.oozie.util.ParamChecker;
import org.apache.oozie.util.XCallable;
@@ -295,7 +296,7 @@ public abstract class Command<T, S extends Store> implements XCallable<T> {
FaultInjection.deactivate("org.apache.oozie.command.SkipCommitFaultInjection");
cron.stop();
instrumentation.addCron(INSTRUMENTATION_GROUP, name, cron);
- incrCommandCounter(1);
+ InstrumentUtils.incrCommandCounter(name, 1, instrumentation);
log.trace(logMask, "End");
if (locks != null) {
for (LockToken lock : locks) {
@@ -506,47 +507,6 @@ public abstract class Command<T, S extends Store> implements XCallable<T> {
}
/**
- * Convenience method to increment counters.
- *
- * @param group the group name.
- * @param name the counter name.
- * @param count increment count.
- */
- private void incrCounter(String group, String name, int count) {
- if (instrumentation != null) {
- instrumentation.incr(group, name, count);
- }
- }
-
- /**
- * Used to increment command counters.
- *
- * @param count the increment count.
- */
- protected void incrCommandCounter(int count) {
- incrCounter(INSTRUMENTATION_GROUP, name, count);
- }
-
- /**
- * Used to increment job counters. The counter name s the same as the command name.
- *
- * @param count the increment count.
- */
- protected void incrJobCounter(int count) {
- incrJobCounter(name, count);
- }
-
- /**
- * Used to increment job counters.
- *
- * @param name the job name.
- * @param count the increment count.
- */
- protected void incrJobCounter(String name, int count) {
- incrCounter(INSTRUMENTATION_JOB_GROUP, name, count);
- }
-
- /**
* Return the {@link Instrumentation} instance in use.
*
* @return the {@link Instrumentation} instance in use.
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/core/src/main/java/org/apache/oozie/command/XCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/command/XCommand.java b/core/src/main/java/org/apache/oozie/command/XCommand.java
index b712ce0..44e1133 100644
--- a/core/src/main/java/org/apache/oozie/command/XCommand.java
+++ b/core/src/main/java/org/apache/oozie/command/XCommand.java
@@ -204,7 +204,6 @@ public abstract class XCommand<T> implements XCallable<T> {
}
lock = Services.get().get(MemoryLocksService.class).getWriteLock(getEntityKey(), getLockTimeOut());
if (lock == null) {
- Instrumentation instrumentation = Services.get().get(InstrumentationService.class).get();
instrumentation.incr(INSTRUMENTATION_GROUP, getName() + ".lockTimeOut", 1);
if (isReQueueRequired()) {
//if not acquire the lock, re-queue itself with default delay
@@ -242,7 +241,6 @@ public abstract class XCommand<T> implements XCallable<T> {
}
commandQueue = null;
- Instrumentation instrumentation = Services.get().get(InstrumentationService.class).get();
instrumentation.incr(INSTRUMENTATION_GROUP, getName() + ".executions", 1);
Instrumentation.Cron callCron = new Instrumentation.Cron();
try {
@@ -324,6 +322,7 @@ public abstract class XCommand<T> implements XCallable<T> {
}
catch (Error er) {
LOG.error("Error, ", er);
+ instrumentation.incr(INSTRUMENTATION_GROUP, getName() + ".errors", 1);
throw er;
}
finally {
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/core/src/main/java/org/apache/oozie/command/coord/CoordActionInputCheckXCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/command/coord/CoordActionInputCheckXCommand.java b/core/src/main/java/org/apache/oozie/command/coord/CoordActionInputCheckXCommand.java
index 0dc7e33..0a9e4fa 100644
--- a/core/src/main/java/org/apache/oozie/command/coord/CoordActionInputCheckXCommand.java
+++ b/core/src/main/java/org/apache/oozie/command/coord/CoordActionInputCheckXCommand.java
@@ -54,7 +54,6 @@ import org.apache.oozie.service.Services;
import org.apache.oozie.service.URIHandlerService;
import org.apache.oozie.util.DateUtils;
import org.apache.oozie.util.ELEvaluator;
-import org.apache.oozie.util.Instrumentation;
import org.apache.oozie.util.LogUtils;
import org.apache.oozie.util.ParamChecker;
import org.apache.oozie.util.StatusUtils;
@@ -145,11 +144,9 @@ public class CoordActionInputCheckXCommand extends CoordinatorXCommand<Void> {
}
StringBuilder actionXml = new StringBuilder(coordAction.getActionXml());
- Instrumentation.Cron cron = new Instrumentation.Cron();
boolean isChangeInDependency = false;
try {
Configuration actionConf = new XConfiguration(new StringReader(coordAction.getRunConf()));
- cron.start();
Date now = new Date();
if (coordJob.getExecutionOrder().equals(CoordinatorJobBean.Execution.LAST_ONLY)) {
Date nextNominalTime = computeNextNominalTime();
@@ -260,9 +257,6 @@ public class CoordActionInputCheckXCommand extends CoordinatorXCommand<Void> {
updateCoordAction(coordAction, isChangeInDependency);
throw new CommandException(ErrorCode.E1021, e.getMessage(), e);
}
- finally {
- cron.stop();
- }
return null;
}
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/core/src/main/java/org/apache/oozie/command/coord/CoordActionMaterializeCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/command/coord/CoordActionMaterializeCommand.java b/core/src/main/java/org/apache/oozie/command/coord/CoordActionMaterializeCommand.java
index 6962fb2..14dee97 100644
--- a/core/src/main/java/org/apache/oozie/command/coord/CoordActionMaterializeCommand.java
+++ b/core/src/main/java/org/apache/oozie/command/coord/CoordActionMaterializeCommand.java
@@ -127,8 +127,6 @@ public class CoordActionMaterializeCommand extends CoordinatorCommand<Void> {
throw new CommandException(ErrorCode.E1005, ioe.getMessage(), ioe);
}
- Instrumentation.Cron cron = new Instrumentation.Cron();
- cron.start();
try {
materializeJobs(false, job, jobConf, store);
updateJobTable(job, store);
@@ -142,7 +140,6 @@ public class CoordActionMaterializeCommand extends CoordinatorCommand<Void> {
log.error("Excepion thrown :", e);
throw new CommandException(ErrorCode.E1001, e.getMessage(), e);
}
- cron.stop();
}
else {
log.info("WARN: action is not in PREMATER state! It's in state=" + job.getStatus());
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/core/src/main/java/org/apache/oozie/command/coord/CoordMaterializeTransitionXCommand.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/command/coord/CoordMaterializeTransitionXCommand.java b/core/src/main/java/org/apache/oozie/command/coord/CoordMaterializeTransitionXCommand.java
index a562c77..23bafb8 100644
--- a/core/src/main/java/org/apache/oozie/command/coord/CoordMaterializeTransitionXCommand.java
+++ b/core/src/main/java/org/apache/oozie/command/coord/CoordMaterializeTransitionXCommand.java
@@ -357,9 +357,10 @@ public class CoordMaterializeTransitionXCommand extends MaterializeTransitionXCo
throw new CommandException(ErrorCode.E1011, jex);
}
throw new CommandException(ErrorCode.E1012, e.getMessage(), e);
+ } finally {
+ cron.stop();
+ instrumentation.addCron(INSTRUMENTATION_GROUP, getName() + ".materialize", cron);
}
- cron.stop();
-
}
/**
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/core/src/main/java/org/apache/oozie/service/InstrumentationService.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/service/InstrumentationService.java b/core/src/main/java/org/apache/oozie/service/InstrumentationService.java
index 80437b1..e17ceb8 100644
--- a/core/src/main/java/org/apache/oozie/service/InstrumentationService.java
+++ b/core/src/main/java/org/apache/oozie/service/InstrumentationService.java
@@ -36,29 +36,57 @@ public class InstrumentationService implements Service {
public static final String CONF_LOGGING_INTERVAL = CONF_PREFIX + "logging.interval";
- private final XLog log = XLog.getLog("oozieinstrumentation");
+ private final XLog log = XLog.getLog(XLog.INSTRUMENTATION_LOG_NAME);
- private Instrumentation instrumentation;
+ protected static Instrumentation instrumentation = null;
+
+ private static boolean isEnabled = false;
/**
* Initialize the instrumentation service.
*
* @param services services instance.
*/
+ @Override
public void init(Services services) throws ServiceException {
- instrumentation = new Instrumentation();
+ final Instrumentation instr = new Instrumentation();
+ int interval = services.getConf().getInt(CONF_LOGGING_INTERVAL, 60);
+ initLogging(services, instr, interval);
+ instr.addVariable(JVM_INSTRUMENTATION_GROUP, "free.memory", new Instrumentation.Variable<Long>() {
+ @Override
+ public Long getValue() {
+ return Runtime.getRuntime().freeMemory();
+ }
+ });
+ instr.addVariable(JVM_INSTRUMENTATION_GROUP, "max.memory", new Instrumentation.Variable<Long>() {
+ @Override
+ public Long getValue() {
+ return Runtime.getRuntime().maxMemory();
+ }
+ });
+ instr.addVariable(JVM_INSTRUMENTATION_GROUP, "total.memory", new Instrumentation.Variable<Long>() {
+ @Override
+ public Long getValue() {
+ return Runtime.getRuntime().totalMemory();
+ }
+ });
+ instrumentation = instr;
+ isEnabled = true;
+ }
+
+ protected void initLogging(Services services, final Instrumentation instr, int interval) throws ServiceException {
log.info("*********** Startup ***********");
- log.info("Java System Properties: {E}{0}", mapToString(instrumentation.getJavaSystemProperties()));
- log.info("OS Env: {E}{0}", mapToString(instrumentation.getOSEnv()));
+ log.info("Java System Properties: {E}{0}", mapToString(instr.getJavaSystemProperties()));
+ log.info("OS Env: {E}{0}", mapToString(instr.getOSEnv()));
SchedulerService schedulerService = services.get(SchedulerService.class);
if (schedulerService != null) {
- instrumentation.setScheduler(schedulerService.getScheduler());
- int interval = services.getConf().getInt(CONF_LOGGING_INTERVAL, 60);
+ instr.setScheduler(schedulerService.getScheduler());
if (interval > 0) {
Runnable instrumentationLogger = new Runnable() {
+ @Override
public void run() {
try {
- log.info("\n" + instrumentation.toString());
+ log.info("\n" + instr.toString());
}
catch (Throwable ex) {
log.warn("Instrumentation logging error", ex);
@@ -71,24 +99,9 @@ public class InstrumentationService implements Service {
else {
throw new ServiceException(ErrorCode.E0100, getClass().getName(), "SchedulerService unavailable");
}
- instrumentation.addVariable(JVM_INSTRUMENTATION_GROUP, "free.memory", new Instrumentation.Variable<Long>() {
- public Long getValue() {
- return Runtime.getRuntime().freeMemory();
- }
- });
- instrumentation.addVariable(JVM_INSTRUMENTATION_GROUP, "max.memory", new Instrumentation.Variable<Long>() {
- public Long getValue() {
- return Runtime.getRuntime().maxMemory();
- }
- });
- instrumentation.addVariable(JVM_INSTRUMENTATION_GROUP, "total.memory", new Instrumentation.Variable<Long>() {
- public Long getValue() {
- return Runtime.getRuntime().totalMemory();
- }
- });
}
- private String mapToString(Map<String, String> map) {
+ protected String mapToString(Map<String, String> map) {
String E = System.getProperty("line.separator");
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : map.entrySet()) {
@@ -100,7 +113,9 @@ public class InstrumentationService implements Service {
/**
* Destroy the instrumentation service.
*/
+ @Override
public void destroy() {
+ isEnabled = false;
instrumentation = null;
}
@@ -109,6 +124,7 @@ public class InstrumentationService implements Service {
*
* @return {@link InstrumentationService}.
*/
+ @Override
public Class<? extends Service> getInterface() {
return InstrumentationService.class;
}
@@ -122,4 +138,12 @@ public class InstrumentationService implements Service {
return instrumentation;
}
+ /**
+ * Returns if the InstrumentationService is enabled or not.
+ *
+ * @return true if the InstrumentationService is enabled; false if not
+ */
+ public static boolean isEnabled() {
+ return isEnabled;
+ }
}
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/core/src/main/java/org/apache/oozie/service/MetricsInstrumentationService.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/service/MetricsInstrumentationService.java b/core/src/main/java/org/apache/oozie/service/MetricsInstrumentationService.java
new file mode 100644
index 0000000..e428ed8
--- /dev/null
+++ b/core/src/main/java/org/apache/oozie/service/MetricsInstrumentationService.java
@@ -0,0 +1,65 @@
+/**
+ * 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 org.apache.oozie.util.Instrumentation;
+import org.apache.oozie.util.MetricsInstrumentation;
+
+
+/**
+ * This service provides an {@link Instrumentation} instance mostly compatible with the original Instrumentation, but backed by
+ * Codahale Metrics. <p/> This service depends on the {@link SchedulerService}. <p/> The {@link #CONF_LOGGING_INTERVAL}
+ * configuration property indicates how often snapshots of the instrumentation should be logged.
+ */
+public class MetricsInstrumentationService extends InstrumentationService {
+
+ private static boolean isEnabled = false;
+
+ /**
+ * Initialize the metrics instrumentation service.
+ *
+ * @param services services instance.
+ * @throws org.apache.oozie.service.ServiceException
+ */
+ @Override
+ public void init(Services services) throws ServiceException {
+ final MetricsInstrumentation instr = new MetricsInstrumentation();
+ int interval = services.getConf().getInt(CONF_LOGGING_INTERVAL, 60);
+ initLogging(services, instr, interval);
+ instrumentation = instr;
+ isEnabled = true;
+ }
+
+ /**
+ * Destroy the metrics instrumentation service.
+ */
+ @Override
+ public void destroy() {
+ isEnabled = false;
+ instrumentation = null;
+ }
+
+ /**
+ * Returns if the MetricsInstrumentationService is enabled or not.
+ *
+ * @return true if the MetricsInstrumentationService is enabled; false if not
+ */
+ public static boolean isEnabled() {
+ return isEnabled;
+ }
+}
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/core/src/main/java/org/apache/oozie/service/Services.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/service/Services.java b/core/src/main/java/org/apache/oozie/service/Services.java
index 5feac7b..398e91f 100644
--- a/core/src/main/java/org/apache/oozie/service/Services.java
+++ b/core/src/main/java/org/apache/oozie/service/Services.java
@@ -21,10 +21,12 @@ import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.util.ReflectionUtils;
import org.apache.hadoop.util.VersionInfo;
+import org.apache.oozie.BuildInfo;
import org.apache.oozie.client.OozieClient.SYSTEM_MODE;
import org.apache.oozie.util.DateUtils;
import org.apache.oozie.util.XLog;
import org.apache.oozie.util.Instrumentable;
+import org.apache.oozie.util.Instrumentation;
import org.apache.oozie.util.IOUtils;
import org.apache.oozie.ErrorCode;
@@ -218,11 +220,24 @@ public class Services {
}
InstrumentationService instrService = get(InstrumentationService.class);
if (instrService != null) {
+ Instrumentation instr = instrService.get();
for (Service service : services.values()) {
if (service instanceof Instrumentable) {
- ((Instrumentable) service).instrument(instrService.get());
+ ((Instrumentable) service).instrument(instr);
}
}
+ instr.addVariable("oozie", "version", new Instrumentation.Variable<String>() {
+ @Override
+ public String getValue() {
+ return BuildInfo.getBuildInfo().getProperty(BuildInfo.BUILD_VERSION);
+ }
+ });
+ instr.addVariable("oozie", "mode", new Instrumentation.Variable<String>() {
+ @Override
+ public String getValue() {
+ return getSystemMode().toString();
+ }
+ });
}
log.info("Initialized");
log.info("Running with JARs for Hadoop version [{0}]", VersionInfo.getVersion());
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/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 403a089..2df062e 100644
--- a/core/src/main/java/org/apache/oozie/service/XLogService.java
+++ b/core/src/main/java/org/apache/oozie/service/XLogService.java
@@ -312,11 +312,6 @@ public class XLogService implements Service, Instrumentable {
* @param instr instrumentation to use.
*/
public void instrument(Instrumentation instr) {
- instr.addVariable("oozie", "version", new Instrumentation.Variable<String>() {
- public String getValue() {
- return BuildInfo.getBuildInfo().getProperty(BuildInfo.BUILD_VERSION);
- }
- });
instr.addVariable(INSTRUMENTATION_GROUP, "config.file", new Instrumentation.Variable<String>() {
public String getValue() {
return log4jFileName;
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/core/src/main/java/org/apache/oozie/servlet/BaseAdminServlet.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/servlet/BaseAdminServlet.java b/core/src/main/java/org/apache/oozie/servlet/BaseAdminServlet.java
index 0739cae..128347e 100644
--- a/core/src/main/java/org/apache/oozie/servlet/BaseAdminServlet.java
+++ b/core/src/main/java/org/apache/oozie/servlet/BaseAdminServlet.java
@@ -120,7 +120,7 @@ public abstract class BaseAdminServlet extends JsonRestServlet {
sendJsonResponse(response, HttpServletResponse.SC_OK, json);
}
else if (resource.equals(RestConstants.ADMIN_INSTRUMENTATION_RESOURCE)) {
- sendJsonResponse(response, HttpServletResponse.SC_OK, instrToJson(instr));
+ sendInstrumentationResponse(response, instr);
}
else if (resource.equals(RestConstants.ADMIN_BUILD_VERSION_RESOURCE)) {
JSONObject json = new JSONObject();
@@ -156,6 +156,9 @@ public abstract class BaseAdminServlet extends JsonRestServlet {
String sharelibKey = request.getParameter(RestConstants.SHARE_LIB_REQUEST_KEY);
sendJsonResponse(response, HttpServletResponse.SC_OK, getShareLib(sharelibKey));
}
+ else if (resource.equals(RestConstants.ADMIN_METRICS_RESOURCE)) {
+ sendMetricsResponse(response);
+ }
}
/**
@@ -384,5 +387,12 @@ public abstract class BaseAdminServlet extends JsonRestServlet {
return array;
}
+ protected void sendInstrumentationResponse(HttpServletResponse response, Instrumentation instr)
+ throws IOException, XServletException {
+ sendJsonResponse(response, HttpServletResponse.SC_OK, instrToJson(instr));
+ }
+
protected abstract Map<String, String> getOozieURLs() throws XServletException;
+
+ protected abstract void sendMetricsResponse(HttpServletResponse response) throws IOException, XServletException;
}
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/core/src/main/java/org/apache/oozie/servlet/JsonRestServlet.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/servlet/JsonRestServlet.java b/core/src/main/java/org/apache/oozie/servlet/JsonRestServlet.java
index 5c05acd..f7458dc 100644
--- a/core/src/main/java/org/apache/oozie/servlet/JsonRestServlet.java
+++ b/core/src/main/java/org/apache/oozie/servlet/JsonRestServlet.java
@@ -48,7 +48,7 @@ import java.util.concurrent.atomic.AtomicLong;
*/
public abstract class JsonRestServlet extends HttpServlet {
- private static final String JSTON_UTF8 = RestConstants.JSON_CONTENT_TYPE + "; charset=\"UTF-8\"";
+ static final String JSON_UTF8 = RestConstants.JSON_CONTENT_TYPE + "; charset=\"UTF-8\"";
protected static final String XML_UTF8 = RestConstants.XML_CONTENT_TYPE + "; charset=\"UTF-8\"";
@@ -367,7 +367,7 @@ public abstract class JsonRestServlet extends HttpServlet {
throws IOException {
response.setStatus(statusCode);
JSONObject json = bean.toJSONObject(timeZoneId);
- response.setContentType(JSTON_UTF8);
+ response.setContentType(JSON_UTF8);
json.writeJSONString(response.getWriter());
}
@@ -396,7 +396,7 @@ public abstract class JsonRestServlet extends HttpServlet {
response.sendError(statusCode);
}
response.setStatus(statusCode);
- response.setContentType(JSTON_UTF8);
+ response.setContentType(JSON_UTF8);
json.writeJSONString(response.getWriter());
}
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/core/src/main/java/org/apache/oozie/servlet/V0AdminServlet.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/servlet/V0AdminServlet.java b/core/src/main/java/org/apache/oozie/servlet/V0AdminServlet.java
index 97bd81c..803dbf6 100644
--- a/core/src/main/java/org/apache/oozie/servlet/V0AdminServlet.java
+++ b/core/src/main/java/org/apache/oozie/servlet/V0AdminServlet.java
@@ -122,6 +122,11 @@ public class V0AdminServlet extends BaseAdminServlet {
@Override
protected Map<String, String> getOozieURLs() throws XServletException {
- throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0302, "Not supported in v1");
+ throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0302, "Not supported in v0");
+ }
+
+ @Override
+ protected void sendMetricsResponse(HttpServletResponse response) throws IOException, XServletException {
+ throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0302, "Not supported in v0");
}
}
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/core/src/main/java/org/apache/oozie/servlet/V1AdminServlet.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/servlet/V1AdminServlet.java b/core/src/main/java/org/apache/oozie/servlet/V1AdminServlet.java
index a47f737..93e5ac9 100644
--- a/core/src/main/java/org/apache/oozie/servlet/V1AdminServlet.java
+++ b/core/src/main/java/org/apache/oozie/servlet/V1AdminServlet.java
@@ -46,7 +46,7 @@ public class V1AdminServlet extends BaseAdminServlet {
private static final long serialVersionUID = 1L;
private static final String INSTRUMENTATION_NAME = "v1admin";
- private static final ResourceInfo RESOURCES_INFO[] = new ResourceInfo[12];
+ private static final ResourceInfo RESOURCES_INFO[] = new ResourceInfo[13];
static {
RESOURCES_INFO[0] = new ResourceInfo(RestConstants.ADMIN_STATUS_RESOURCE, Arrays.asList("PUT", "GET"),
@@ -74,6 +74,8 @@ public class V1AdminServlet extends BaseAdminServlet {
Collections.EMPTY_LIST);
RESOURCES_INFO[11] = new ResourceInfo(RestConstants.ADMIN_LIST_SHARELIB, Arrays.asList("GET"),
Collections.EMPTY_LIST);
+ RESOURCES_INFO[12] = new ResourceInfo(RestConstants.ADMIN_METRICS_RESOURCE, Arrays.asList("GET"),
+ Collections.EMPTY_LIST);
}
@@ -163,4 +165,9 @@ public class V1AdminServlet extends BaseAdminServlet {
protected Map<String, String> getOozieURLs() throws XServletException {
throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0302, "Not supported in v1");
}
+
+ @Override
+ protected void sendMetricsResponse(HttpServletResponse response) throws IOException, XServletException {
+ throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0302, "Not supported in v1");
+ }
}
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/core/src/main/java/org/apache/oozie/servlet/V2AdminServlet.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/servlet/V2AdminServlet.java b/core/src/main/java/org/apache/oozie/servlet/V2AdminServlet.java
index 002a367..b51ffb8 100644
--- a/core/src/main/java/org/apache/oozie/servlet/V2AdminServlet.java
+++ b/core/src/main/java/org/apache/oozie/servlet/V2AdminServlet.java
@@ -30,9 +30,12 @@ import org.apache.oozie.client.rest.JMSConnectionInfoBean;
import org.apache.oozie.client.rest.JsonBean;
import org.apache.oozie.jms.JMSConnectionInfo;
import org.apache.oozie.jms.JMSJobEventListener;
+import org.apache.oozie.service.InstrumentationService;
import org.apache.oozie.service.JMSTopicService;
import org.apache.oozie.service.JobsConcurrencyService;
import org.apache.oozie.service.Services;
+import org.apache.oozie.util.Instrumentation;
+import org.apache.oozie.util.MetricsInstrumentation;
/**
* V2 admin servlet
@@ -42,9 +45,19 @@ public class V2AdminServlet extends V1AdminServlet {
private static final long serialVersionUID = 1L;
private static final String INSTRUMENTATION_NAME = "v2admin";
+ private static MetricsInstrumentation metricsInstrumentation = null;
public V2AdminServlet() {
super(INSTRUMENTATION_NAME);
+
+ // If MetricsInstrumentationService is used, we will enable the metrics endpoint and disable the instrumentation endpoint
+ Services services = Services.get();
+ if (services != null) {
+ Instrumentation instrumentation = services.get(InstrumentationService.class).get();
+ if (instrumentation instanceof MetricsInstrumentation) {
+ metricsInstrumentation = (MetricsInstrumentation) instrumentation;
+ }
+ }
}
@Override
@@ -86,4 +99,31 @@ public class V2AdminServlet extends V1AdminServlet {
}
return serverUrls;
}
+
+ @Override
+ protected void sendMetricsResponse(HttpServletResponse response) throws IOException, XServletException {
+ if (metricsInstrumentation != null) {
+ response.setStatus(HttpServletResponse.SC_OK);
+ response.setContentType(JSON_UTF8);
+ try {
+ metricsInstrumentation.writeJSONResponse(response.getOutputStream());
+ } finally {
+ response.getOutputStream().close();
+ }
+ } else {
+ response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
+ response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "MetricsInstrumentationService is not running");
+ }
+ }
+
+ @Override
+ protected void sendInstrumentationResponse(HttpServletResponse response, Instrumentation instr)
+ throws IOException, XServletException {
+ if (metricsInstrumentation == null) {
+ super.sendInstrumentationResponse(response, instr);
+ } else {
+ response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
+ response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "InstrumentationService is not running");
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/core/src/main/java/org/apache/oozie/util/MetricsInstrumentation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/util/MetricsInstrumentation.java b/core/src/main/java/org/apache/oozie/util/MetricsInstrumentation.java
new file mode 100644
index 0000000..b5b4337
--- /dev/null
+++ b/core/src/main/java/org/apache/oozie/util/MetricsInstrumentation.java
@@ -0,0 +1,334 @@
+/**
+ * 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.util;
+
+import com.codahale.metrics.Counter;
+import com.codahale.metrics.ExponentiallyDecayingReservoir;
+import com.codahale.metrics.Gauge;
+import com.codahale.metrics.Histogram;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.json.MetricsModule;
+import com.codahale.metrics.jvm.MemoryUsageGaugeSet;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Instrumentation framework that is mostly compatible with {@link Instrumentation} but is backed by Codahale Metrics. This class
+ * was designed to minimize the changes required to switch from {@link Instrumentation} to {@link MetricsInstrumentation} by keeping
+ * the same API. However, certain operations are obviously implemented differently or are no longer needed; and the output format
+ * is a little different. Internally, this class maps Cron to {@link com.codahale.metrics.Timer}, Variable to {@link Gauge},
+ * counter to {@link Counter}, and Sampler to {@link Histogram}.
+ */
+@SuppressWarnings("unchecked")
+public class MetricsInstrumentation extends Instrumentation {
+
+ private final MetricRegistry metricRegistry;
+ private transient ObjectMapper jsonMapper;
+ private ScheduledExecutorService scheduler;
+ private final LoadingCache<String, Counter> counters;
+ private final Map<String, Gauge> gauges;
+ private final LoadingCache<String, com.codahale.metrics.Timer> timers;
+ private final Map<String, Histogram> histograms;
+ private Lock timersLock;
+ private Lock gaugesLock;
+ private Lock countersLock;
+ private Lock histogramsLock;
+
+ private static final TimeUnit RATE_UNIT = TimeUnit.MILLISECONDS;
+ private static final TimeUnit DURATION_UNIT = TimeUnit.MILLISECONDS;
+
+ /**
+ * Creates the MetricsInstrumentation and starts taking some metrics.
+ */
+ public MetricsInstrumentation() {
+ metricRegistry = new MetricRegistry();
+
+ timersLock = new ReentrantLock();
+ gaugesLock = new ReentrantLock();
+ countersLock = new ReentrantLock();
+ histogramsLock = new ReentrantLock();
+
+ // Used for writing the json for the metrics (see com.codahale.metrics.servlets.MetricsServlet)
+ // The "false" is to prevent it from printing out all of the values used in the histograms and timers
+ this.jsonMapper = new ObjectMapper().registerModule(new MetricsModule(RATE_UNIT, DURATION_UNIT, false));
+
+ // Register the JVM memory gauges and prefix the keys
+ MemoryUsageGaugeSet memorySet = new MemoryUsageGaugeSet();
+ for (String key : memorySet.getMetrics().keySet()) {
+ metricRegistry.register(MetricRegistry.name("jvm", "memory", key), memorySet.getMetrics().get(key));
+ }
+
+ // By setting this up as a cache, if a counter doesn't exist when we try to retrieve it, it will automatically be created
+ counters = CacheBuilder.newBuilder().build(
+ new CacheLoader<String, Counter>() {
+ @Override
+ public Counter load(String key) throws Exception {
+ Counter counter = new Counter();
+ metricRegistry.register(key, counter);
+ return counter;
+ }
+ }
+ );
+ timers = CacheBuilder.newBuilder().build(
+ new CacheLoader<String, com.codahale.metrics.Timer>() {
+ @Override
+ public com.codahale.metrics.Timer load(String key) throws Exception {
+ com.codahale.metrics.Timer timer
+ = new com.codahale.metrics.Timer(new ExponentiallyDecayingReservoir());
+ metricRegistry.register(key, timer);
+ return timer;
+ }
+ }
+ );
+ gauges = new ConcurrentHashMap<String, Gauge>();
+ histograms = new ConcurrentHashMap<String, Histogram>();
+ }
+
+ /**
+ * Add a cron to an instrumentation timer. The timer is created if it does not exists. <p/>
+ * Internally, this is backed by a {@link com.codahale.metrics.Timer}.
+ *
+ * @param group timer group.
+ * @param name timer name.
+ * @param cron cron to add to the timer.
+ */
+ @Override
+ public void addCron(String group, String name, Cron cron) {
+ String key = MetricRegistry.name(group, name, "timer");
+ try {
+ timersLock.lock();
+ com.codahale.metrics.Timer timer = timers.get(key);
+ timer.update(cron.getOwn(), TimeUnit.MILLISECONDS);
+ } catch(ExecutionException ee) {
+ throw new RuntimeException(ee);
+ } finally {
+ timersLock.unlock();
+ }
+ }
+
+ /**
+ * Add an instrumentation variable. <p/>
+ * Internally, this is backed by a {@link Gauge}.
+ *
+ * @param group counter group.
+ * @param name counter name.
+ * @param variable variable to add.
+ */
+ @Override
+ public void addVariable(String group, String name, final Variable variable) {
+ Gauge gauge = new Gauge() {
+ @Override
+ public Object getValue() {
+ return variable.getValue();
+ }
+ };
+ String key = MetricRegistry.name(group, name);
+
+ try {
+ gaugesLock.lock();
+ gauges.put(key, gauge);
+ // Metrics throws an Exception if we don't do this when the key already exists
+ if (metricRegistry.getGauges().containsKey(key)) {
+ XLog.getLog(MetricsInstrumentation.class).debug("A Variable with name [" + key + "] already exists. "
+ + " The old Variable will be overwritten, but this is not recommended");
+ metricRegistry.remove(key);
+ }
+ metricRegistry.register(key, gauge);
+ } finally {
+ gaugesLock.unlock();
+ }
+ }
+
+ /**
+ * Increment an instrumentation counter. The counter is created if it does not exists. <p/>
+ * Internally, this is backed by a {@link Counter}.
+ *
+ * @param group counter group.
+ * @param name counter name.
+ * @param count increment to add to the counter.
+ */
+ @Override
+ public void incr(String group, String name, long count) {
+ String key = MetricRegistry.name(group, name);
+ try {
+ countersLock.lock();
+ counters.get(key).inc(count);
+ } catch(ExecutionException ee) {
+ throw new RuntimeException(ee);
+ } finally {
+ countersLock.unlock();
+ }
+ }
+
+ /**
+ * Add a sampling variable. <p/>
+ * Internally, this is backed by a biased (decaying) {@link Histogram}.
+ *
+ * @param group timer group.
+ * @param name timer name.
+ * @param period (ignored)
+ * @param interval sampling frequency, how often the variable is probed.
+ * @param variable variable to sample.
+ */
+ @Override
+ public void addSampler(String group, String name, int period, int interval, Variable<Long> variable) {
+ if (scheduler == null) {
+ throw new IllegalStateException("scheduler not set, cannot sample");
+ }
+ Histogram histogram = new Histogram(new ExponentiallyDecayingReservoir());
+ Sampler sampler = new Sampler(variable, histogram);
+ scheduler.scheduleAtFixedRate(sampler, 0, interval, TimeUnit.SECONDS);
+ String key = MetricRegistry.name(group, name, "histogram");
+ try {
+ histogramsLock.lock();
+ histograms.put(key, histogram);
+ // Metrics throws an Exception if we don't do this when the key already exists
+ if (metricRegistry.getHistograms().containsKey(key)) {
+ XLog.getLog(MetricsInstrumentation.class).debug("A Sampler with name [" + key + "] already exists. "
+ + " The old Sampler will be overwritten, but this is not recommended");
+ metricRegistry.remove(key);
+ }
+ metricRegistry.register(key, histogram);
+ } finally {
+ histogramsLock.unlock();
+ }
+ }
+
+ public static class Sampler implements Runnable {
+ private final Variable<Long> variable;
+ private final Histogram histogram;
+ public Sampler(Variable<Long> variable, Histogram histogram) {
+ this.variable = variable;
+ this.histogram = histogram;
+ }
+
+ @Override
+ public void run() {
+ histogram.update(variable.getValue());
+ }
+ }
+
+ /**
+ * Set the scheduler instance to handle the samplers.
+ *
+ * @param scheduler scheduler instance.
+ */
+ @Override
+ public void setScheduler(ScheduledExecutorService scheduler) {
+ this.scheduler = scheduler;
+ }
+
+ /**
+ * Return the string representation of the instrumentation. It does a JSON pretty-print.
+ *
+ * @return the string representation of the instrumentation.
+ */
+ @Override
+ public String toString() {
+ try {
+ return jsonMapper.writerWithDefaultPrettyPrinter().writeValueAsString(metricRegistry);
+ } catch (JsonProcessingException jpe) {
+ throw new RuntimeException(jpe);
+ }
+ }
+
+ /**
+ * Converts the current state of the metrics and writes them to the OutputStream.
+ *
+ * @param os The OutputStream to write the metrics to
+ * @throws IOException
+ */
+ public void writeJSONResponse(OutputStream os) throws IOException {
+ jsonMapper.writer().writeValue(os, metricRegistry);
+ }
+
+ /**
+ * Returns the MetricRegistry: public for unit tests -- do not use.
+ *
+ * @return the MetricRegistry
+ */
+ @VisibleForTesting
+ MetricRegistry getMetricRegistry() {
+ return metricRegistry;
+ }
+
+ /**
+ * Not Supported: throws {@link UnsupportedOperationException}
+ *
+ * @return nothing
+ */
+ @Override
+ public Map<String, Map<String, Map<String, Object>>> getAll() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not Supported: throws {@link UnsupportedOperationException}
+ *
+ * @return nothing
+ */
+ @Override
+ public Map<String, Map<String, Element<Long>>> getCounters() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not Supported: throws {@link UnsupportedOperationException}
+ *
+ * @return nothing
+ */
+ @Override
+ public Map<String, Map<String, Element<Double>>> getSamplers() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not Supported: throws {@link UnsupportedOperationException}
+ *
+ * @return nothing
+ */
+ @Override
+ public Map<String, Map<String, Element<Timer>>> getTimers() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Not Supported: throws {@link UnsupportedOperationException}
+ *
+ * @return nothing
+ */
+ @Override
+ public Map<String, Map<String, Element<Variable>>> getVariables() {
+ throw new UnsupportedOperationException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/core/src/main/java/org/apache/oozie/util/XLog.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/oozie/util/XLog.java b/core/src/main/java/org/apache/oozie/util/XLog.java
index 21e00c0..31a5ba0 100644
--- a/core/src/main/java/org/apache/oozie/util/XLog.java
+++ b/core/src/main/java/org/apache/oozie/util/XLog.java
@@ -34,6 +34,8 @@ import java.util.Map;
*/
public class XLog implements Log {
+ public static final String INSTRUMENTATION_LOG_NAME = "oozieinstrumentation";
+
/**
* <code>LogInfo</code> stores contextual information to create log prefixes. <p/> <code>LogInfo</code> uses a
* <code>ThreadLocal</code> to propagate the context. <p/> <code>LogInfo</code> context parameters are configurable
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/core/src/test/java/org/apache/oozie/service/TestInstrumentationService.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/oozie/service/TestInstrumentationService.java b/core/src/test/java/org/apache/oozie/service/TestInstrumentationService.java
index b5206cf..65c4cb2 100644
--- a/core/src/test/java/org/apache/oozie/service/TestInstrumentationService.java
+++ b/core/src/test/java/org/apache/oozie/service/TestInstrumentationService.java
@@ -18,6 +18,8 @@
package org.apache.oozie.service;
import org.apache.oozie.test.XTestCase;
+import org.apache.oozie.util.Instrumentation;
+import org.apache.oozie.util.MetricsInstrumentation;
public class TestInstrumentationService extends XTestCase {
@@ -36,6 +38,12 @@ public class TestInstrumentationService extends XTestCase {
public void testInstrumentation() throws Exception {
assertNotNull(Services.get().get(InstrumentationService.class));
assertNotNull(Services.get().get(InstrumentationService.class).get());
+ Instrumentation instr = Services.get().get(InstrumentationService.class).get();
+ assertFalse(instr instanceof MetricsInstrumentation);
}
+ public void testIsEnabled() {
+ assertTrue(InstrumentationService.isEnabled());
+ assertFalse(MetricsInstrumentationService.isEnabled());
+ }
}
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/core/src/test/java/org/apache/oozie/service/TestMetricsInstrumentationService.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/oozie/service/TestMetricsInstrumentationService.java b/core/src/test/java/org/apache/oozie/service/TestMetricsInstrumentationService.java
new file mode 100644
index 0000000..314d5a3
--- /dev/null
+++ b/core/src/test/java/org/apache/oozie/service/TestMetricsInstrumentationService.java
@@ -0,0 +1,51 @@
+/**
+ * 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 org.apache.oozie.test.XTestCase;
+import org.apache.oozie.util.Instrumentation;
+import org.apache.oozie.util.MetricsInstrumentation;
+
+public class TestMetricsInstrumentationService extends XTestCase {
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ Services services = new Services();
+ services.getConf().set(Services.CONF_SERVICE_EXT_CLASSES, "org.apache.oozie.service.MetricsInstrumentationService");
+ services.init();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ Services.get().destroy();
+ super.tearDown();
+ }
+
+ public void testInstrumentation() throws Exception {
+ assertNotNull(Services.get().get(InstrumentationService.class));
+ assertNotNull(Services.get().get(InstrumentationService.class).get());
+ Instrumentation instr = Services.get().get(InstrumentationService.class).get();
+ assertTrue(instr instanceof MetricsInstrumentation);
+ }
+
+ public void testIsEnabled() {
+ assertFalse(InstrumentationService.isEnabled());
+ assertTrue(MetricsInstrumentationService.isEnabled());
+ }
+}
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/core/src/test/java/org/apache/oozie/util/TestInstrumentation.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/oozie/util/TestInstrumentation.java b/core/src/test/java/org/apache/oozie/util/TestInstrumentation.java
index 6040b47..47b0d8b 100644
--- a/core/src/test/java/org/apache/oozie/util/TestInstrumentation.java
+++ b/core/src/test/java/org/apache/oozie/util/TestInstrumentation.java
@@ -237,46 +237,49 @@ public class TestInstrumentation extends XTestCase {
public void testSamplers() throws Exception {
Instrumentation inst = new Instrumentation();
ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(1);
- inst.setScheduler(scheduledExecutorService);
-
- inst.addSampler("a", "1", 10, 1, new Instrumentation.Variable<Long>() {
- public Long getValue() {
- return 1L;
- }
- });
- assertEquals(1, inst.getSamplers().size());
- assertEquals(1, inst.getSamplers().get("a").size());
-
- inst.addSampler("a", "2", 10, 1, new Instrumentation.Variable<Long>() {
- public Long getValue() {
- return 2L;
- }
- });
- assertEquals(1, inst.getSamplers().size());
- assertEquals(2, inst.getSamplers().get("a").size());
-
- inst.addSampler("b", "1", 10, 1, new Instrumentation.Variable<Long>() {
- private long counter = 0;
-
- public Long getValue() {
- return counter++ % 10;
- }
- });
- assertEquals(2, inst.getSamplers().size());
- assertEquals(2, inst.getSamplers().get("a").size());
- assertEquals(1, inst.getSamplers().get("b").size());
-
- waitFor(20 * 1000, new Predicate() {
- public boolean evaluate() throws Exception {
- return false;
- }
- });
-
- assertEquals("", 1D, inst.getSamplers().get("a").get("1").getValue(), 0.01D);
- assertEquals("", 2D, inst.getSamplers().get("a").get("2").getValue(), 0.02D);
- assertEquals("", 5D, inst.getSamplers().get("b").get("1").getValue(), 0.5D);
-
- scheduledExecutorService.shutdownNow();
+ try {
+ inst.setScheduler(scheduledExecutorService);
+
+ inst.addSampler("a", "1", 10, 1, new Instrumentation.Variable<Long>() {
+ public Long getValue() {
+ return 1L;
+ }
+ });
+ assertEquals(1, inst.getSamplers().size());
+ assertEquals(1, inst.getSamplers().get("a").size());
+
+ inst.addSampler("a", "2", 10, 1, new Instrumentation.Variable<Long>() {
+ public Long getValue() {
+ return 2L;
+ }
+ });
+ assertEquals(1, inst.getSamplers().size());
+ assertEquals(2, inst.getSamplers().get("a").size());
+
+ inst.addSampler("b", "1", 10, 1, new Instrumentation.Variable<Long>() {
+ private long counter = 0;
+
+ public Long getValue() {
+ return counter++ % 10;
+ }
+ });
+ assertEquals(2, inst.getSamplers().size());
+ assertEquals(2, inst.getSamplers().get("a").size());
+ assertEquals(1, inst.getSamplers().get("b").size());
+
+ waitFor(20 * 1000, new Predicate() {
+ public boolean evaluate() throws Exception {
+ return false;
+ }
+ });
+
+ assertEquals("", 1D, inst.getSamplers().get("a").get("1").getValue(), 0.01D);
+ assertEquals("", 2D, inst.getSamplers().get("a").get("2").getValue(), 0.02D);
+ assertEquals("", 4D, inst.getSamplers().get("b").get("1").getValue(), 0.5D);
+
+ } finally {
+ scheduledExecutorService.shutdownNow();
+ }
}
public void testAll() throws Exception {
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/core/src/test/java/org/apache/oozie/util/TestMetricsInstrumentation.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/oozie/util/TestMetricsInstrumentation.java b/core/src/test/java/org/apache/oozie/util/TestMetricsInstrumentation.java
new file mode 100644
index 0000000..b6aed44
--- /dev/null
+++ b/core/src/test/java/org/apache/oozie/util/TestMetricsInstrumentation.java
@@ -0,0 +1,192 @@
+/**
+ * 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.util;
+
+import com.codahale.metrics.Metric;
+import com.codahale.metrics.MetricFilter;
+import com.codahale.metrics.Timer;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import org.apache.oozie.test.XTestCase;
+
+// Most tests adpated from TestInstrumentation
+public class TestMetricsInstrumentation extends XTestCase {
+ private static final long INTERVAL = 300;
+
+ // Filter that removes the "jvm.memory" gauges
+ private final MetricFilter noJvm = new MetricFilter() {
+ @Override
+ public boolean matches(String name, Metric metric) {
+ return !name.startsWith("jvm.memory");
+ }
+ };
+
+ public void testInstrumentationCounter() throws Exception {
+ MetricsInstrumentation inst = new MetricsInstrumentation();
+ assertEquals(0, inst.getMetricRegistry().getCounters().size());
+ inst.incr("a", "1", 1);
+ assertEquals(1, inst.getMetricRegistry().getCounters().size());
+ inst.incr("a", "2", 2);
+ assertEquals(2, inst.getMetricRegistry().getCounters().size());
+ inst.incr("b", "1", 3);
+ assertEquals(3, inst.getMetricRegistry().getCounters().size());
+ assertEquals(1L, inst.getMetricRegistry().getCounters().get("a.1").getCount());
+ assertEquals(2L, inst.getMetricRegistry().getCounters().get("a.2").getCount());
+ assertEquals(3L, inst.getMetricRegistry().getCounters().get("b.1").getCount());
+ }
+
+ private long getTimerValue(Timer timer) {
+ long[] values = timer.getSnapshot().getValues();
+ // These get stored in nanoseconds but Cron is in milliseconds
+ return TimeUnit.NANOSECONDS.toMillis(values[0]);
+ }
+
+ public void testInstrumentationTimer() throws Exception {
+ MetricsInstrumentation inst = new MetricsInstrumentation();
+ assertEquals(0, inst.getMetricRegistry().getTimers().size());
+ Instrumentation.Cron cron1 = new Instrumentation.Cron();
+ inst.addCron("a", "1", cron1);
+ assertEquals(1, inst.getMetricRegistry().getTimers().size());
+ Instrumentation.Cron cron2 = new Instrumentation.Cron();
+ cron2.start();
+ Thread.sleep(INTERVAL);
+ cron2.stop();
+ inst.addCron("a", "2", cron2);
+ assertEquals(2, inst.getMetricRegistry().getTimers().size());
+ Instrumentation.Cron cron3 = new Instrumentation.Cron();
+ cron3.start();
+ Thread.sleep(INTERVAL * 2);
+ cron3.stop();
+ inst.addCron("b", "1", cron3);
+ assertEquals(3, inst.getMetricRegistry().getTimers().size());
+
+ assertEquals(cron1.getOwn(), getTimerValue(inst.getMetricRegistry().getTimers().get("a.1.timer")));
+ assertEquals(cron2.getOwn(), getTimerValue(inst.getMetricRegistry().getTimers().get("a.2.timer")));
+ assertEquals(cron3.getOwn(), getTimerValue(inst.getMetricRegistry().getTimers().get("b.1.timer")));
+ }
+
+ public void testVariables() throws Exception {
+ MetricsInstrumentation inst = new MetricsInstrumentation();
+
+ inst.addVariable("a", "1", new Instrumentation.Variable<Long>() {
+ private long counter = 0;
+
+ public Long getValue() {
+ return counter++;
+ }
+ });
+ assertEquals(1, inst.getMetricRegistry().getGauges(noJvm).size());
+
+ inst.addVariable("a", "2", new Instrumentation.Variable<Long>() {
+ private long counter = 1;
+
+ public Long getValue() {
+ return counter++;
+ }
+ });
+ assertEquals(2, inst.getMetricRegistry().getGauges(noJvm).size());
+ inst.addVariable("b", "1", new Instrumentation.Variable<Long>() {
+ private long counter = 2;
+
+ public Long getValue() {
+ return counter++;
+ }
+ });
+ assertEquals(3, inst.getMetricRegistry().getGauges(noJvm).size());
+
+ assertEquals(0L, inst.getMetricRegistry().getGauges(noJvm).get("a.1").getValue());
+ assertEquals(1L, inst.getMetricRegistry().getGauges(noJvm).get("a.2").getValue());
+ assertEquals(2L, inst.getMetricRegistry().getGauges(noJvm).get("b.1").getValue());
+ assertEquals(1L, inst.getMetricRegistry().getGauges(noJvm).get("a.1").getValue());
+ assertEquals(2L, inst.getMetricRegistry().getGauges(noJvm).get("a.2").getValue());
+ assertEquals(3L, inst.getMetricRegistry().getGauges(noJvm).get("b.1").getValue());
+ }
+
+ public void testSamplers() throws Exception {
+ MetricsInstrumentation inst = new MetricsInstrumentation();
+ ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(1);
+ try {
+ inst.setScheduler(scheduledExecutorService);
+
+ inst.addSampler("a", "1", 10, 1, new Instrumentation.Variable<Long>() {
+ public Long getValue() {
+ return 1L;
+ }
+ });
+ assertEquals(1, inst.getMetricRegistry().getHistograms().size());
+
+ inst.addSampler("a", "2", 10, 1, new Instrumentation.Variable<Long>() {
+ public Long getValue() {
+ return 2L;
+ }
+ });
+ assertEquals(2, inst.getMetricRegistry().getHistograms().size());
+
+ inst.addSampler("b", "1", 10, 1, new Instrumentation.Variable<Long>() {
+ private long counter = 0;
+
+ public Long getValue() {
+ return counter++ % 10;
+ }
+ });
+ assertEquals(3, inst.getMetricRegistry().getHistograms().size());
+
+ waitFor(20 * 1000, new Predicate() {
+ public boolean evaluate() throws Exception {
+ return false;
+ }
+ });
+
+ assertEquals(1D, inst.getMetricRegistry().getHistograms().get("a.1.histogram").getSnapshot().getMean(), 0.01D);
+ assertEquals(2D, inst.getMetricRegistry().getHistograms().get("a.2.histogram").getSnapshot().getMean(), 0.02D);
+ assertEquals(4D, inst.getMetricRegistry().getHistograms().get("b.1.histogram").getSnapshot().getMean(), 0.5D);
+ } finally {
+ scheduledExecutorService.shutdownNow();
+ }
+ }
+
+ public void testUnsupportedOpertation() {
+ MetricsInstrumentation instr = new MetricsInstrumentation();
+ try {
+ instr.getAll();
+ fail();
+ } catch (UnsupportedOperationException uoe) {
+ }
+ try {
+ instr.getCounters();
+ fail();
+ } catch (UnsupportedOperationException uoe) {
+ }
+ try {
+ instr.getSamplers();
+ fail();
+ } catch (UnsupportedOperationException uoe) {
+ }
+ try {
+ instr.getTimers();
+ fail();
+ } catch (UnsupportedOperationException uoe) {
+ }
+ try {
+ instr.getVariables();
+ fail();
+ } catch (UnsupportedOperationException uoe) {
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/docs/src/site/twiki/AG_Install.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/AG_Install.twiki b/docs/src/site/twiki/AG_Install.twiki
index ce84e54..0d22fe9 100644
--- a/docs/src/site/twiki/AG_Install.twiki
+++ b/docs/src/site/twiki/AG_Install.twiki
@@ -706,6 +706,26 @@ similar. You will probably have to add your certificate as an exception.
Refer to the [[./oozie-default.xml][oozie-default.xml]] for details.
+---+++ Using Metrics instead of Instrumentation
+
+As of version 4.1.0, Oozie includes a replacement for the Instrumentation based on Codahale's Metrics library. It includes a
+number of improvements over the original Instrumentation included in Oozie. They both report most of the same information, though
+the formatting is slightly different and there's some additional information in the Metrics version; the format of the output to the
+oozie-instrumentation log is also different. The Metrics version can be enabled by adding the =MetricsInstrumentationService= to
+the list of services:
+ <verbatim>
+ <property>
+ <name>oozie.services.ext</name>
+ <value>
+ org.apache.oozie.service.MetricsInstrumentationService
+ </value>
+ </property>
+ </verbatim>
+
+Once enabled, the =admin/instrumentation= REST endpoint will no longer be available and instead the =admin/metrics= endpoint should
+be used (see the [[WebServicesAPI#Oozie_Metrics][Web Services API]] documentation for more details); the Oozie Web UI will also
+replace the "Instrumentation" tab with a "Metrics" tab.
+
#HA
---+++ High Availability (HA)
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/docs/src/site/twiki/WebServicesAPI.twiki
----------------------------------------------------------------------
diff --git a/docs/src/site/twiki/WebServicesAPI.twiki b/docs/src/site/twiki/WebServicesAPI.twiki
index 5769924..6f31240 100644
--- a/docs/src/site/twiki/WebServicesAPI.twiki
+++ b/docs/src/site/twiki/WebServicesAPI.twiki
@@ -191,7 +191,10 @@ Content-Type: application/json;charset=UTF-8
_Identical to the corresponding Oozie v0 WS API_
-A HTTP GET request returns the Oozie instrumentation information.
+A HTTP GET request returns the Oozie instrumentation information. Keep in mind that timers and counters that the Oozie server
+hasn't incremented yet will not show up.
+
+*Note:* If Instrumentation is enabled, then Metrics is unavailable.
*Request:*
@@ -270,6 +273,90 @@ Content-Type: application/json;charset=UTF-8
}
</verbatim>
+---++++ Oozie Metrics
+
+_Available in the Oozie v2 WS API and later_
+
+A HTTP GET request returns the Oozie metrics information. Keep in mind that timers and counters that the Oozie server
+hasn't incremented yet will not show up.
+
+*Note:* If Metrics is enabled, then Instrumentation is unavailable.
+
+*Request:*
+
+<verbatim>
+GET /oozie/v2/admin/metrics
+</verbatim>
+
+*Response:*
+
+<verbatim>
+HTTP/1.1 200 OK
+Content-Type: application/json;charset=UTF-8
+.
+{
+ "gauges" : {
+ "jvm.memory.non-heap.committed" : {
+ "value" : 62590976
+ },
+ "oozie.mode" : {
+ "value" : "NORMAL"
+ },
+ ...
+ },
+ "timers" : {
+ "commands.action.end.call.timer" : {
+ "mean" : 108.5,
+ "p50" : 111.5,
+ "p75" : 165.5,
+ "p999" : 169,
+ "count" : 4,
+ "p95" : 169,
+ "max" : 169,
+ "mean_rate" : 0,
+ "duration_units" : "milliseconds",
+ "p98" : 169,
+ "m1_rate" : 0,
+ "rate_units" : "calls/millisecond",
+ "m15_rate" : 0,
+ "stddev" : 62.9417720330995,
+ "m5_rate" : 0,
+ "p99" : 169,
+ "min" : 42
+ },
+ ...
+ },
+ "histograms" : {
+ "callablequeue.threads.active.histogram" : {
+ "p999" : 1,
+ "mean" : 0.0625,
+ "min" : 0,
+ "p75" : 0,
+ "p95" : 1,
+ "count" : 48,
+ "p98" : 1,
+ "stddev" : 0.24462302739504083,
+ "max" : 1,
+ "p99" : 1,
+ "p50" : 0
+ },
+ ...
+ },
+ "counters" : {
+ "commands.job.info.executions" : {
+ "count" : 9
+ },
+ "jpa.CoordJobsGetPendingJPAExecutor" : {
+ "count" : 1
+ },
+ "jpa.GET_WORKFLOW" : {
+ "count" : 10
+ },
+ ...
+ }
+}
+</verbatim>
+
---++++ Version
_Identical to the corresponding Oozie v0 WS API_
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index b5e0e4e..bad1e0f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -742,6 +742,24 @@
<version>2.1.7</version>
</dependency>
+ <dependency>
+ <groupId>com.codahale.metrics</groupId>
+ <artifactId>metrics-core</artifactId>
+ <version>3.0.2</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.codahale.metrics</groupId>
+ <artifactId>metrics-jvm</artifactId>
+ <version>3.0.2</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.codahale.metrics</groupId>
+ <artifactId>metrics-json</artifactId>
+ <version>3.0.2</version>
+ </dependency>
+
<!-- For drawing runtime DAG -->
<dependency>
<groupId>net.sf.jung</groupId>
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/release-log.txt
----------------------------------------------------------------------
diff --git a/release-log.txt b/release-log.txt
index f14f81d..01d54a4 100644
--- a/release-log.txt
+++ b/release-log.txt
@@ -1,5 +1,6 @@
-- Oozie 4.1.0 release (trunk - unreleased)
+OOZIE-1817 Oozie timers are not biased (rkanter)
OOZIE-1807 Make bundle change command synchronous (puru via rohini)
OOZIE-1678 HA support for SLA (ryota)
OOZIE-1685 Oozie doesn’t process correctly workflows with a non-default name node (benjzh via rohini)
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/webapp/src/main/webapp/index.jsp
----------------------------------------------------------------------
diff --git a/webapp/src/main/webapp/index.jsp b/webapp/src/main/webapp/index.jsp
index 3c7ffe5..feedde9 100644
--- a/webapp/src/main/webapp/index.jsp
+++ b/webapp/src/main/webapp/index.jsp
@@ -53,9 +53,14 @@
<a href="./docs/index.html" target="bottom">Documentation</a>
</div>
<%@ page
- import="org.apache.oozie.sla.service.SLAService"%>
+ import="org.apache.oozie.sla.service.SLAService"
+ import="org.apache.oozie.service.InstrumentationService"
+ import="org.apache.oozie.service.MetricsInstrumentationService"
+ %>
<%
boolean isSLAServiceEnabled = SLAService.isEnabled();
+ boolean isInstrumentationServiceEnabled = InstrumentationService.isEnabled();
+ boolean isMetricsInstrumentationServiceEnabled = MetricsInstrumentationService.isEnabled();
%>
<div id="oozie-body" style="padding:2">
<div class="x-tab-panel-header x-unselectable x-tab-strip-top" style="width:1048">
@@ -63,6 +68,8 @@
<script type="text/javascript">
var msg = "Oozie Web Console";
var isSLAServiceEnabled = "<%=isSLAServiceEnabled%>";
+ var isInstrumentationServiceEnabled = "<%=isInstrumentationServiceEnabled%>";
+ var isMetricsInstrumentationServiceEnabled = "<%=isMetricsInstrumentationServiceEnabled%>";
document.title = msg;
document.write(msg);
</script>
http://git-wip-us.apache.org/repos/asf/oozie/blob/e1644828/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 764d888..8f2098d 100644
--- a/webapp/src/main/webapp/oozie-console.js
+++ b/webapp/src/main/webapp/oozie-console.js
@@ -244,7 +244,7 @@ function treeNodeFromXml(XmlEl) {
return result;
}
-function treeNodeFromJson(json, rootText) {
+function treeNodeFromJsonInstrumentation(json, rootText) {
var result = new Ext.tree.TreeNode({
text: rootText
});
@@ -255,10 +255,10 @@ function treeNodeFromJson(json, rootText) {
if (typeof json[i] == 'object') {
var c;
if (json[i]['group']) {
- c = treeNodeFromJson(json[i]['data'], json[i]['group']);
+ c = treeNodeFromJsonInstrumentation(json[i]['data'], json[i]['group']);
}
else {
- c = treeNodeFromJson(json[i], json[i]['name']);
+ c = treeNodeFromJsonInstrumentation(json[i], json[i]['name']);
}
if (c)
result.appendChild(c);
@@ -284,6 +284,44 @@ function treeNodeFromJson(json, rootText) {
return result;
}
+function treeNodeFromJsonMetrics(json, rootText) {
+ var result = new Ext.tree.TreeNode({
+ text: rootText
+ });
+ // For Elements, process attributes and children
+ if (typeof json === 'object') {
+ for (var i in json) {
+ if (json[i]) {
+ if (typeof json[i] == 'object') {
+ var c;
+ if (json[i]) {
+ c = treeNodeFromJsonMetrics(json[i], i);
+ if (c) {
+ result.appendChild(c);
+ }
+ }
+ }
+ else if (typeof json[i] != 'function') {
+ result.appendChild(new Ext.tree.TreeNode({
+ text: i + " -> " + json[i]
+ }));
+ }
+ }
+ else {
+ result.appendChild(new Ext.tree.TreeNode({
+ text: i + " -> " + json[i]
+ }));
+ }
+ }
+ }
+ else {
+ result.appendChild(new Ext.tree.TreeNode({
+ text: json
+ }));
+ }
+ return result;
+}
+
// Common stuff to get a paging toolbar for a data store
function getPagingBar(dataStore) {
var pagingBar = new Ext.PagingToolbar({
@@ -2147,23 +2185,54 @@ var viewInstrumentation = new Ext.Action({
url: getOozieBase() + 'admin/instrumentation',
success: function(response, request) {
var jsonData = eval("(" + response.responseText + ")");
- var timers = treeNodeFromJson(jsonData["timers"], "timers");
+ var timers = treeNodeFromJsonInstrumentation(jsonData["timers"], "timers");
timers.expanded = false;
- var samplers = treeNodeFromJson(jsonData["samplers"], "samplers");
+ var samplers = treeNodeFromJsonInstrumentation(jsonData["samplers"], "samplers");
samplers.expanded = false;
- var counters = treeNodeFromJson(jsonData["counters"], "counters");
+ var counters = treeNodeFromJsonInstrumentation(jsonData["counters"], "counters");
counters.expanded = false;
- var variables = treeNodeFromJson(jsonData["variables"], "variables");
+ var variables = treeNodeFromJsonInstrumentation(jsonData["variables"], "variables");
variables.expanded = false;
- while (treeRoot.hasChildNodes()) {
- var child = treeRoot.firstChild;
- treeRoot.removeChild(child);
+ while (instrumentationTreeRoot.hasChildNodes()) {
+ var child = instrumentationTreeRoot.firstChild;
+ instrumentationTreeRoot.removeChild(child);
}
- treeRoot.appendChild(samplers);
- treeRoot.appendChild(counters);
- treeRoot.appendChild(timers);
- treeRoot.appendChild(variables);
- treeRoot.expand(false, true);
+ instrumentationTreeRoot.appendChild(samplers);
+ instrumentationTreeRoot.appendChild(counters);
+ instrumentationTreeRoot.appendChild(timers);
+ instrumentationTreeRoot.appendChild(variables);
+ instrumentationTreeRoot.expand(false, true);
+ }
+
+ });
+ }
+
+});
+var viewMetrics = new Ext.Action({
+ text: " ",
+ icon: 'ext-2.2/resources/images/default/grid/refresh.gif',
+ handler: function() {
+ Ext.Ajax.request({
+ url: getOozieBase() + 'admin/metrics',
+ success: function(response, request) {
+ var jsonData = eval("(" + response.responseText + ")");
+ var timers = treeNodeFromJsonMetrics(jsonData["timers"], "timers");
+ timers.expanded = false;
+ var histograms = treeNodeFromJsonMetrics(jsonData["histograms"], "histograms");
+ histograms.expanded = false;
+ var counters = treeNodeFromJsonMetrics(jsonData["counters"], "counters");
+ counters.expanded = false;
+ var gauges = treeNodeFromJsonMetrics(jsonData["gauges"], "gauges");
+ gauges.expanded = false;
+ while (metricsTreeRoot.hasChildNodes()) {
+ var child = metricsTreeRoot.firstChild;
+ metricsTreeRoot.removeChild(child);
+ }
+ metricsTreeRoot.appendChild(counters);
+ metricsTreeRoot.appendChild(timers);
+ metricsTreeRoot.appendChild(histograms);
+ metricsTreeRoot.appendChild(gauges);
+ metricsTreeRoot.expand(false, true);
}
});
@@ -2199,11 +2268,16 @@ var viewOSDetails = new Ext.Action({
}
});
-var treeRoot = new Ext.tree.TreeNode({
+var instrumentationTreeRoot = new Ext.tree.TreeNode({
text: "Instrumentation",
expanded: true
});
+var metricsTreeRoot = new Ext.tree.TreeNode({
+ text: "Metrics",
+ expanded: true
+});
+
var timeZones_store = new Ext.data.JsonStore({
autoLoad: true,
root: 'available-timezones',
@@ -2349,16 +2423,25 @@ function initConsole() {
animCollapse: false,
title: "System Info"
});
- var resultArea = new Ext.tree.TreePanel({
+ var instrumentationArea = new Ext.tree.TreePanel({
autoScroll: true,
useArrows: true,
height: 300,
- root: treeRoot,
+ root: instrumentationTreeRoot,
tbar: [viewInstrumentation, {
xtype: 'tbfill'
}, checkStatus, serverVersion],
title: 'Instrumentation'
-
+ });
+ var metricsArea = new Ext.tree.TreePanel({
+ autoScroll: true,
+ useArrows: true,
+ height: 300,
+ root: metricsTreeRoot,
+ tbar: [viewMetrics, {
+ xtype: 'tbfill'
+ }, checkStatus, serverVersion],
+ title: 'Metrics'
});
var slaDashboard = new Ext.Panel({
@@ -2606,7 +2689,12 @@ function initConsole() {
tabs.add(slaDashboard);
}
tabs.add(adminGrid);
- tabs.add(resultArea);
+ if (isInstrumentationServiceEnabled == "true") {
+ tabs.add(instrumentationArea);
+ }
+ if (isMetricsInstrumentationServiceEnabled == "true") {
+ tabs.add(metricsArea);
+ }
tabs.add(settingsArea);
tabs.setActiveTab(jobs_grid);
// showing Workflow Jobs active tab as default
@@ -2639,7 +2727,12 @@ function initConsole() {
checkStatus.execute();
viewConfig.execute();
serverVersion.execute();
- viewInstrumentation.execute();
+ if (isInstrumentationServiceEnabled == "true") {
+ viewInstrumentation.execute();
+ }
+ if (isMetricsInstrumentationServiceEnabled == "true") {
+ viewMetrics.execute();
+ }
var jobId = getReqParam("job");
if (jobId != "") {
if (jobId.endsWith("-C")) {