KYLIN-2776 Using dropwizard as default metric framework

Project: http://git-wip-us.apache.org/repos/asf/kylin/repo
Commit: http://git-wip-us.apache.org/repos/asf/kylin/commit/8e078847
Tree: http://git-wip-us.apache.org/repos/asf/kylin/tree/8e078847
Diff: http://git-wip-us.apache.org/repos/asf/kylin/diff/8e078847

Branch: refs/heads/master
Commit: 8e078847a42b4f7853a2c1a75afa405c09c4ea7b
Parents: d85f6ab
Author: yiming.xu <100650...@qq.com>
Authored: Wed Aug 23 13:12:58 2017 +0800
Committer: Hongbin Ma <m...@kyligence.io>
Committed: Wed Aug 23 13:49:23 2017 +0800

----------------------------------------------------------------------
 core-common/pom.xml                             |  17 +
 .../apache/kylin/common/KylinConfigBase.java    |  20 +
 .../kylin/common/metrics/common/Metrics.java    | 162 ++++++
 .../common/metrics/common/MetricsConstant.java  |  38 ++
 .../common/metrics/common/MetricsFactory.java   |  62 +++
 .../common/metrics/common/MetricsScope.java     |  33 ++
 .../common/metrics/common/MetricsVariable.java  |  27 +
 .../kylin/common/metrics/common/Metricss.java   |  40 ++
 .../metrics/metrics2/CodahaleMetrics.java       | 508 +++++++++++++++++++
 .../metrics/metrics2/CodahaleReporter.java      |  31 ++
 .../metrics2/ConsoleMetricsReporter.java        |  51 ++
 .../metrics/metrics2/JmxMetricsReporter.java    |  55 ++
 .../metrics2/JsonFileMetricsReporter.java       | 136 +++++
 .../metrics2/KylinObjectNameFactory.java        |  68 +++
 .../metrics2/MetricVariableRatioGauge.java      |  47 ++
 .../metrics/metrics2/Metrics2Reporter.java      |  60 +++
 .../metrics/metrics2/MetricsReporting.java      |  26 +
 .../common/metrics/perflog/IPerfLogger.java     |  48 ++
 .../common/metrics/perflog/PerfLogger.java      | 158 ++++++
 .../metrics/perflog/PerfLoggerFactory.java      |  56 ++
 .../metrics/perflog/SimplePerfLogger.java       |  73 +++
 pom.xml                                         |   3 +-
 .../kylin/rest/init/InitialTaskManager.java     |   4 +-
 .../kylin/rest/metrics/QueryMetrics2Facade.java | 106 ++++
 .../apache/kylin/rest/service/QueryService.java |   2 +
 .../kylin/rest/metrics/QueryMetrics2Test.java   | 128 +++++
 26 files changed, 1957 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kylin/blob/8e078847/core-common/pom.xml
----------------------------------------------------------------------
diff --git a/core-common/pom.xml b/core-common/pom.xml
index 8852743..d58de36 100644
--- a/core-common/pom.xml
+++ b/core-common/pom.xml
@@ -68,6 +68,23 @@
             <artifactId>junit</artifactId>
             <scope>test</scope>
         </dependency>
+        
+        <dependency>
+            <groupId>io.dropwizard.metrics</groupId>
+            <artifactId>metrics-jvm</artifactId>
+            <version>${dropwizard.version}</version>
+        </dependency>
 
+        <dependency>
+            <groupId>io.dropwizard.metrics</groupId>
+            <artifactId>metrics-json</artifactId>
+            <version>${dropwizard.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.joshelser</groupId>
+            
<artifactId>dropwizard-metrics-hadoop-metrics2-reporter</artifactId>
+            <version>0.1.2</version>
+        </dependency>
     </dependencies>
 </project>

http://git-wip-us.apache.org/repos/asf/kylin/blob/8e078847/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java
----------------------------------------------------------------------
diff --git 
a/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java 
b/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java
index b622825..99b9bb2 100644
--- a/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java
+++ b/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java
@@ -1173,4 +1173,24 @@ abstract public class KylinConfigBase implements 
Serializable {
     public boolean isWebCrossDomainEnabled() {
         return 
Boolean.parseBoolean(getOptional("kylin.web.cross-domain-enabled", "true"));
     }
+
+    /**
+     * metric
+     */
+    public String getCoadhaleMetricReportClassesName() {
+        return getOptional("kylin.metric.codahale-metric-report-classes",
+                
"org.apache.kylin.common.metrics.metrics2.JsonFileMetricsReporter,org.apache.kylin.common.metrics.metrics2.JmxMetricsReporter");
+    }
+
+    public String getMetricFileLocation() {
+        return getOptional("kylin.metric.file.location", "/tmp/report.json");
+    }
+
+    public Long getJsonFileMetricsReporterInterval() {
+        return 
Long.parseLong(getOptional("kylin.metric.json-file-metric-reporter.interval", 
"5000"));
+    }
+
+    public String getPerfLoggerClassName() {
+        return getOptional("kylin.metric.perf-logger.class", 
"org.apache.kylin.common.metrics.perflog.PerfLogger");
+    }
 }

http://git-wip-us.apache.org/repos/asf/kylin/blob/8e078847/core-common/src/main/java/org/apache/kylin/common/metrics/common/Metrics.java
----------------------------------------------------------------------
diff --git 
a/core-common/src/main/java/org/apache/kylin/common/metrics/common/Metrics.java 
b/core-common/src/main/java/org/apache/kylin/common/metrics/common/Metrics.java
new file mode 100644
index 0000000..dcda3cd
--- /dev/null
+++ 
b/core-common/src/main/java/org/apache/kylin/common/metrics/common/Metrics.java
@@ -0,0 +1,162 @@
+/*
+ * 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.kylin.common.metrics.common;
+
+import com.codahale.metrics.Counter;
+import com.codahale.metrics.Histogram;
+import com.codahale.metrics.Meter;
+import com.codahale.metrics.Timer;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Generic Metics interface.
+ */
+public interface Metrics {
+
+    /**
+     * Deinitializes the Metrics system.
+     */
+    public void close() throws Exception;
+
+    /**
+     *
+     * @param name starts a scope of a given name.  Scopes is stored as 
thread-local variable.
+     */
+    public void startStoredScope(String name);
+
+    /**
+     * Closes the stored scope of a given name.
+     * Note that this must be called on the same thread as where the scope was 
started.
+     * @param name
+     */
+    public void endStoredScope(String name);
+
+    /**
+     * Create scope with given name and returns it.
+     * @param name
+     * @return
+     */
+    public MetricsScope createScope(String name);
+
+    /**
+     * Close the given scope.
+     * @param scope
+     */
+    public void endScope(MetricsScope scope);
+
+    //Counter-related methods
+
+    /**
+     * Increments a counter of the given name by 1.
+     * @param name
+     * @return
+     */
+    public Long incrementCounter(String name);
+
+    /**
+     * Increments a counter of the given name by "increment"
+     * @param name
+     * @param increment
+     * @return
+     */
+    public Long incrementCounter(String name, long increment);
+
+    /**
+     * Decrements a counter of the given name by 1.
+     * @param name
+     * @return
+     */
+    public Long decrementCounter(String name);
+
+    /**
+     * Decrements a counter of the given name by "decrement"
+     * @param name
+     * @param decrement
+     * @return
+     */
+    public Long decrementCounter(String name, long decrement);
+
+    /**
+     * Adds a metrics-gauge to track variable.  For example, number of open 
database connections.
+     * @param name name of gauge
+     * @param variable variable to track.
+     */
+    public void addGauge(String name, final MetricsVariable variable);
+
+    /**
+     * Add a ratio metric to track the correlation between two variables
+     * @param name name of the ratio gauge
+     * @param numerator numerator of the ratio
+     * @param denominator denominator of the ratio
+     */
+    public void addRatio(String name, MetricsVariable<Integer> numerator, 
MetricsVariable<Integer> denominator);
+
+    /**
+     * Mark an event occurance for a meter. Meters measure the rate of an 
event and track
+     * 1/5/15 minute moving averages
+     * @param name name of the meter
+     */
+    public void markMeter(String name);
+
+    /**
+     *
+     * @param name         name of the Timer
+     * @param duration
+     * @param unit
+     */
+
+    public void updateTimer(String name, long duration, TimeUnit unit);
+
+
+    /**
+     *
+     * @param name        name of the histogram
+     * @param count
+     */
+    public void updateHistogram(String name, long count);
+
+    /**
+     *
+     * @param name      name of the time
+     * @return
+     */
+    public Timer getTimer(String name);
+
+    /**
+     *
+     * @param name      name of the counter
+     * @return
+     */
+    public Counter getCounter(String name);
+
+    /**
+     *
+     * @param name      name of the time
+     * @return
+     */
+    public Histogram getHistogram(String name);
+
+    /**
+     *
+     * @param name      name of the meter
+     * @return
+     */
+    public Meter getMeter(String name);
+
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/8e078847/core-common/src/main/java/org/apache/kylin/common/metrics/common/MetricsConstant.java
----------------------------------------------------------------------
diff --git 
a/core-common/src/main/java/org/apache/kylin/common/metrics/common/MetricsConstant.java
 
b/core-common/src/main/java/org/apache/kylin/common/metrics/common/MetricsConstant.java
new file mode 100644
index 0000000..49c8d8e
--- /dev/null
+++ 
b/core-common/src/main/java/org/apache/kylin/common/metrics/common/MetricsConstant.java
@@ -0,0 +1,38 @@
+/*
+ * 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.kylin.common.metrics.common;
+
+/**
+ * This class defines some metrics generated by Hive processes.
+ */
+public class MetricsConstant {
+
+    public static final String API_PREFIX = "api_";
+    public static final String ACTIVE_CALLS = 
"metrics:name=active_calls,method=";
+    public static final String CALLS = "metrics:name=calls,method=";
+
+    public static final String QUERY_SUCCESS_COUNT = "QuerySuccessCount";
+    public static final String QUERY_FAIL_COUNT = "QueryFailCount";
+    public static final String QUERY_CACHE_COUNT = "QueryCacheCount";
+    public static final String QUERY_COUNT = "QueryCount";
+    public static final String QUERY_DURATION = "QueryDuration";
+    public static final String QUERY_RESULT_ROWCOUNT = "QueryResultRowcount";
+    public static final String QUERY_SCAN_ROWCOUNT = "QueryScanRowcount";
+    public static final String TOTAL = "total";
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/kylin/blob/8e078847/core-common/src/main/java/org/apache/kylin/common/metrics/common/MetricsFactory.java
----------------------------------------------------------------------
diff --git 
a/core-common/src/main/java/org/apache/kylin/common/metrics/common/MetricsFactory.java
 
b/core-common/src/main/java/org/apache/kylin/common/metrics/common/MetricsFactory.java
new file mode 100644
index 0000000..ff0ab7d
--- /dev/null
+++ 
b/core-common/src/main/java/org/apache/kylin/common/metrics/common/MetricsFactory.java
@@ -0,0 +1,62 @@
+/*
+ * 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.kylin.common.metrics.common;
+
+
+import org.apache.kylin.common.metrics.metrics2.CodahaleMetrics;
+
+/**
+ * Class that manages a static Metric instance for this process.
+ */
+public class MetricsFactory {
+
+    //Volatile ensures that static access returns Metrics instance in 
fully-initialized state.
+    //Alternative is to synchronize static access, which has performance 
penalties.
+    private volatile static Metrics metrics;
+    static {
+        MetricsFactory.init();
+    }
+
+    /**
+     * Initializes static Metrics instance.
+     */
+    public synchronized static void init() {
+        if (metrics == null) {
+            Class metricsClass = MetricsFactory.class;
+            metrics = new CodahaleMetrics();
+        }
+    }
+
+    /**
+     * Returns static Metrics instance, null if not initialized or closed.
+     */
+    public static Metrics getInstance() {
+        return metrics;
+    }
+
+    /**
+     * Closes and removes static Metrics instance.
+     */
+    public synchronized static void close() throws Exception {
+        if (metrics != null) {
+            metrics.close();
+            metrics = null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/8e078847/core-common/src/main/java/org/apache/kylin/common/metrics/common/MetricsScope.java
----------------------------------------------------------------------
diff --git 
a/core-common/src/main/java/org/apache/kylin/common/metrics/common/MetricsScope.java
 
b/core-common/src/main/java/org/apache/kylin/common/metrics/common/MetricsScope.java
new file mode 100644
index 0000000..8a72073
--- /dev/null
+++ 
b/core-common/src/main/java/org/apache/kylin/common/metrics/common/MetricsScope.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+package org.apache.kylin.common.metrics.common;
+
+/**
+ * Metrics Scope to represent duration of an event.
+ *
+ * Implementation can capture information like the average duration of open 
scopes,
+ * number of open scopes, number of completed scopes.
+ *
+ * Scopes are created via the Metrics framework (see Metrics#createScope or 
Metrics$createStoredScope)
+ *
+ * Scope may be stored by the Metrics framework via 'storedScope' concept for 
further reference.
+ *
+ * In either case, it is the caller's responsibility to end the scope via the 
Metrics framework (see Metrics#endScope)
+ */
+public interface MetricsScope {
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/8e078847/core-common/src/main/java/org/apache/kylin/common/metrics/common/MetricsVariable.java
----------------------------------------------------------------------
diff --git 
a/core-common/src/main/java/org/apache/kylin/common/metrics/common/MetricsVariable.java
 
b/core-common/src/main/java/org/apache/kylin/common/metrics/common/MetricsVariable.java
new file mode 100644
index 0000000..3273c7f
--- /dev/null
+++ 
b/core-common/src/main/java/org/apache/kylin/common/metrics/common/MetricsVariable.java
@@ -0,0 +1,27 @@
+/*
+ * 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.kylin.common.metrics.common;
+
+/**
+ * Interface for metrics variables. For example a the database service could 
expose the number of
+ * currently active connections.
+ */
+public interface MetricsVariable<T> {
+    public T getValue();
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/kylin/blob/8e078847/core-common/src/main/java/org/apache/kylin/common/metrics/common/Metricss.java
----------------------------------------------------------------------
diff --git 
a/core-common/src/main/java/org/apache/kylin/common/metrics/common/Metricss.java
 
b/core-common/src/main/java/org/apache/kylin/common/metrics/common/Metricss.java
new file mode 100644
index 0000000..105ab5d
--- /dev/null
+++ 
b/core-common/src/main/java/org/apache/kylin/common/metrics/common/Metricss.java
@@ -0,0 +1,40 @@
+/*
+ * 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.kylin.common.metrics.common;
+
+public final class Metricss {
+    public final static String METRICS = "metrics:";
+    public final static String PROJECT_TEMPLATE = METRICS + "project=%s";
+    public final static String CUBE_TEMPLATE = METRICS + "project=%s,cube=%s";
+
+
+    public static String buildMetricName(String prefix, String name) {
+        return String.format(prefix+",name=%s", name);
+    }
+
+    public static String buildCubeMetricPrefix(String project) {
+        return String.format(PROJECT_TEMPLATE, project);
+    }
+
+    public static String buildCubeMetricPrefix(String project, String cube) {
+        return String.format(CUBE_TEMPLATE, project, cube);
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/8e078847/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/CodahaleMetrics.java
----------------------------------------------------------------------
diff --git 
a/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/CodahaleMetrics.java
 
b/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/CodahaleMetrics.java
new file mode 100644
index 0000000..d7e2f8c
--- /dev/null
+++ 
b/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/CodahaleMetrics.java
@@ -0,0 +1,508 @@
+/*
+ * 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.kylin.common.metrics.metrics2;
+
+import java.io.Closeable;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.apache.commons.lang3.ClassUtils;
+import org.apache.kylin.common.KylinConfig;
+import org.apache.kylin.common.metrics.common.Metrics;
+import org.apache.kylin.common.metrics.common.MetricsConstant;
+import org.apache.kylin.common.metrics.common.MetricsScope;
+import org.apache.kylin.common.metrics.common.MetricsVariable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.codahale.metrics.Counter;
+import com.codahale.metrics.ExponentiallyDecayingReservoir;
+import com.codahale.metrics.Gauge;
+import com.codahale.metrics.Histogram;
+import com.codahale.metrics.Meter;
+import com.codahale.metrics.Metric;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.MetricSet;
+import com.codahale.metrics.Timer;
+import com.codahale.metrics.json.MetricsModule;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Splitter;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.Lists;
+
+/**
+ * Codahale-backed Metrics implementation.
+ */
+public class CodahaleMetrics implements Metrics {
+
+    public static final Logger LOGGER = 
LoggerFactory.getLogger(CodahaleMetrics.class);
+
+    public final MetricRegistry metricRegistry = new MetricRegistry();
+    private final Lock timersLock = new ReentrantLock();
+    private final Lock countersLock = new ReentrantLock();
+    private final Lock gaugesLock = new ReentrantLock();
+    private final Lock metersLock = new ReentrantLock();
+    private final Lock histogramLock = new ReentrantLock();
+    private final Set<Closeable> reporters = new HashSet<Closeable>();
+    private final ThreadLocal<HashMap<String, CodahaleMetricsScope>> 
threadLocalScopes = new ThreadLocal<HashMap<String, CodahaleMetricsScope>>() {
+        @Override
+        protected HashMap<String, CodahaleMetricsScope> initialValue() {
+            return new HashMap<String, CodahaleMetricsScope>();
+        }
+    };
+    private LoadingCache<String, Timer> timers;
+    private LoadingCache<String, Counter> counters;
+    private LoadingCache<String, Meter> meters;
+    private LoadingCache<String, Histogram> histograms;
+    private ConcurrentHashMap<String, Gauge> gauges;
+    private KylinConfig conf;
+
+    public CodahaleMetrics() {
+        this.conf = conf;
+        //Codahale artifacts are lazily-created.
+        timers = CacheBuilder.newBuilder().build(new CacheLoader<String, 
Timer>() {
+            @Override
+            public Timer load(String key) {
+                Timer timer = new Timer(new ExponentiallyDecayingReservoir());
+                metricRegistry.register(key, timer);
+                return timer;
+            }
+        });
+        counters = CacheBuilder.newBuilder().build(new CacheLoader<String, 
Counter>() {
+            @Override
+            public Counter load(String key) {
+                Counter counter = new Counter();
+                metricRegistry.register(key, counter);
+                return counter;
+            }
+        });
+        meters = CacheBuilder.newBuilder().build(new CacheLoader<String, 
Meter>() {
+            @Override
+            public Meter load(String key) {
+                Meter meter = new Meter();
+                metricRegistry.register(key, meter);
+                return meter;
+            }
+        });
+        histograms = CacheBuilder.newBuilder().build(new CacheLoader<String, 
Histogram>() {
+            @Override
+            public Histogram load(String key) {
+                Histogram histogram = new Histogram(new 
ExponentiallyDecayingReservoir());
+                metricRegistry.register(key, histogram);
+                return histogram;
+            }
+        });
+        gauges = new ConcurrentHashMap<String, Gauge>();
+        //register JVM metrics
+        //        registerAll("gc", new GarbageCollectorMetricSet());
+        //        registerAll("buffers", new 
BufferPoolMetricSet(ManagementFactory.getPlatformMBeanServer()));
+        //        registerAll("memory", new MemoryUsageGaugeSet());
+        //        registerAll("threads", new ThreadStatesGaugeSet());
+        //        registerAll("classLoadingz", new ClassLoadingGaugeSet());
+
+        //initialize reporters
+        initReporting();
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (reporters != null) {
+            for (Closeable reporter : reporters) {
+                reporter.close();
+            }
+        }
+        for (Map.Entry<String, Metric> metric : 
metricRegistry.getMetrics().entrySet()) {
+            metricRegistry.remove(metric.getKey());
+        }
+        timers.invalidateAll();
+        counters.invalidateAll();
+        meters.invalidateAll();
+    }
+
+    @Override
+    public void startStoredScope(String name) {
+        if (threadLocalScopes.get().containsKey(name)) {
+            threadLocalScopes.get().get(name).open();
+        } else {
+            threadLocalScopes.get().put(name, new CodahaleMetricsScope(name));
+        }
+    }
+
+    public MetricsScope getStoredScope(String name) throws 
IllegalArgumentException {
+        if (threadLocalScopes.get().containsKey(name)) {
+            return threadLocalScopes.get().get(name);
+        } else {
+            throw new IllegalArgumentException("No metrics scope named " + 
name);
+        }
+    }
+
+    @Override
+    public void endStoredScope(String name) {
+        if (threadLocalScopes.get().containsKey(name)) {
+            threadLocalScopes.get().get(name).close();
+            threadLocalScopes.get().remove(name);
+        }
+    }
+
+    public MetricsScope createScope(String name) {
+        return new CodahaleMetricsScope(name);
+    }
+
+    public void endScope(MetricsScope scope) {
+        ((CodahaleMetricsScope) scope).close();
+    }
+
+    @Override
+    public Long incrementCounter(String name) {
+        return incrementCounter(name, 1L);
+    }
+
+    @Override
+    public Long incrementCounter(String name, long increment) {
+        String key = name;
+        try {
+            countersLock.lock();
+            counters.get(key).inc(increment);
+            return counters.get(key).getCount();
+        } catch (ExecutionException ee) {
+            throw new IllegalStateException("Error retrieving counter from the 
metric registry ", ee);
+        } finally {
+            countersLock.unlock();
+        }
+    }
+
+    @Override
+    public Long decrementCounter(String name) {
+        return decrementCounter(name, 1L);
+    }
+
+    @Override
+    public Long decrementCounter(String name, long decrement) {
+        String key = name;
+        try {
+            countersLock.lock();
+            counters.get(key).dec(decrement);
+            return counters.get(key).getCount();
+        } catch (ExecutionException ee) {
+            throw new IllegalStateException("Error retrieving counter from the 
metric registry ", ee);
+        } finally {
+            countersLock.unlock();
+        }
+    }
+
+    @Override
+    public void addGauge(String name, final MetricsVariable variable) {
+        Gauge gauge = new Gauge() {
+            @Override
+            public Object getValue() {
+                return variable.getValue();
+            }
+        };
+        addGaugeInternal(name, gauge);
+    }
+
+    @Override
+    public void addRatio(String name, MetricsVariable<Integer> numerator, 
MetricsVariable<Integer> denominator) {
+        Preconditions.checkArgument(numerator != null, "Numerator must not be 
null");
+        Preconditions.checkArgument(denominator != null, "Denominator must not 
be null");
+
+        MetricVariableRatioGauge gauge = new 
MetricVariableRatioGauge(numerator, denominator);
+        addGaugeInternal(name, gauge);
+    }
+
+    private void addGaugeInternal(String name, Gauge gauge) {
+        try {
+            gaugesLock.lock();
+            gauges.put(name, gauge);
+            // Metrics throws an Exception if we don't do this when the key 
already exists
+            if (metricRegistry.getGauges().containsKey(name)) {
+                LOGGER.warn("A Gauge with name [" + name + "] already exists. "
+                        + " The old gauge will be overwritten, but this is not 
recommended");
+                metricRegistry.remove(name);
+            }
+            metricRegistry.register(name, gauge);
+        } finally {
+            gaugesLock.unlock();
+        }
+    }
+
+    @Override
+    public void markMeter(String name) {
+        String key = name;
+        try {
+            metersLock.lock();
+            Meter meter = meters.get(name);
+            meter.mark();
+        } catch (ExecutionException e) {
+            throw new IllegalStateException("Error retrieving meter " + name + 
" from the metric registry ", e);
+        } finally {
+            metersLock.unlock();
+        }
+    }
+
+    @Override
+    public void updateHistogram(String name, long count) {
+        try {
+            histogramLock.lock();
+            Histogram histogram = histograms.get(name);
+            histogram.update(count);
+        } catch (ExecutionException e) {
+            throw new IllegalStateException("Error retrieving meter " + name + 
" from the metric registry ", e);
+        } finally {
+            histogramLock.unlock();
+        }
+    }
+
+    @Override
+    public void updateTimer(String name, long duration, TimeUnit unit) {
+        String key = name;
+        try {
+            timersLock.lock();
+            Timer timer = timers.get(key);
+            timer.update(duration, unit);
+        } catch (ExecutionException e) {
+            throw new IllegalStateException("Error retrieving timer " + name + 
" from the metric registry ", e);
+        } finally {
+            timersLock.unlock();
+        }
+    }
+
+    // This method is necessary to synchronize lazy-creation to the timers.
+    public Timer getTimer(String name) {
+        try {
+            timersLock.lock();
+            return timers.get(name);
+        } catch (ExecutionException e) {
+            throw new IllegalStateException("Error retrieving timer " + name + 
" from the metric registry ", e);
+        } finally {
+            timersLock.unlock();
+        }
+    }
+
+    public Counter getCounter(String name) {
+        try {
+            countersLock.lock();
+            return counters.get(name);
+        } catch (ExecutionException e) {
+            throw new IllegalStateException("Error retrieving counter " + name 
+ " from the metric registry ", e);
+        } finally {
+            countersLock.unlock();
+        }
+    }
+
+    public Histogram getHistogram(String name) {
+        try {
+            histogramLock.lock();
+            return histograms.get(name);
+        } catch (ExecutionException e) {
+            throw new IllegalStateException("Error retrieving histogram " + 
name + " from the metric registry ", e);
+        } finally {
+            histogramLock.unlock();
+        }
+    }
+
+    public Meter getMeter(String name) {
+        try {
+            metersLock.lock();
+            return meters.get(name);
+        } catch (ExecutionException e) {
+            throw new IllegalStateException("Error retrieving meter " + name + 
" from the metric registry ", e);
+        } finally {
+            metersLock.unlock();
+        }
+    }
+
+    private void registerAll(String prefix, MetricSet metricSet) {
+        for (Map.Entry<String, Metric> entry : 
metricSet.getMetrics().entrySet()) {
+            if (entry.getValue() instanceof MetricSet) {
+                registerAll(prefix + "." + entry.getKey(), (MetricSet) 
entry.getValue());
+            } else {
+                metricRegistry.register(prefix + "." + entry.getKey(), 
entry.getValue());
+            }
+        }
+    }
+
+    @VisibleForTesting
+    public MetricRegistry getMetricRegistry() {
+        return metricRegistry;
+    }
+
+    @VisibleForTesting
+    public String dumpJson() throws Exception {
+        ObjectMapper jsonMapper = new ObjectMapper()
+                .registerModule(new MetricsModule(TimeUnit.MILLISECONDS, 
TimeUnit.MILLISECONDS, false));
+        return 
jsonMapper.writerWithDefaultPrettyPrinter().writeValueAsString(metricRegistry);
+    }
+
+    /**
+     * Initializes reporters from HIVE_CODAHALE_METRICS_REPORTER_CLASSES or 
HIVE_METRICS_REPORTER if the former is not defined.
+     * Note: if both confs are defined, only  
HIVE_CODAHALE_METRICS_REPORTER_CLASSES will be used.
+     */
+    private void initReporting() {
+
+        if (!(initCodahaleMetricsReporterClasses() || initMetricsReporter())) {
+            LOGGER.warn("Unable to initialize metrics reporting");
+        }
+        if (reporters.isEmpty()) {
+            // log a warning incase no reporters were successfully added
+            LOGGER.warn("No reporters configured for codahale metrics!");
+        }
+    }
+
+    /**
+     * Initializes reporting using HIVE_CODAHALE_METRICS_REPORTER_CLASSES.
+     * @return whether initialization was successful or not
+     */
+    private boolean initCodahaleMetricsReporterClasses() {
+
+        List<String> reporterClasses = 
Lists.newArrayList(Splitter.on(",").trimResults().omitEmptyStrings()
+                
.split(KylinConfig.getInstanceFromEnv().getCoadhaleMetricReportClassesName()));
+        if (reporterClasses.isEmpty()) {
+            return false;
+        }
+
+        for (String reporterClass : reporterClasses) {
+            Class name = null;
+            try {
+                name = ClassUtils.getClass(reporterClass);
+            } catch (ClassNotFoundException e) {
+                LOGGER.error("Unable to instantiate metrics reporter class " + 
reporterClass
+                        + " from conf HIVE_CODAHALE_METRICS_REPORTER_CLASSES", 
e);
+                throw new IllegalArgumentException(e);
+            }
+            try {
+                Constructor constructor = 
name.getConstructor(MetricRegistry.class, KylinConfig.class);
+                CodahaleReporter reporter = (CodahaleReporter) 
constructor.newInstance(metricRegistry, conf);
+                reporter.start();
+                reporters.add(reporter);
+            } catch (NoSuchMethodException | InstantiationException | 
IllegalAccessException
+                    | InvocationTargetException e) {
+                LOGGER.error("Unable to instantiate using 
constructor(MetricRegistry, HiveConf) for" + " reporter "
+                        + reporterClass + " from conf 
HIVE_CODAHALE_METRICS_REPORTER_CLASSES", e);
+                throw new IllegalArgumentException(e);
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Initializes reporting using HIVE_METRICS+REPORTER.
+     * @return whether initialization was successful or not
+     */
+    private boolean initMetricsReporter() {
+
+        List<String> metricsReporterNames = 
Lists.newArrayList(Splitter.on(",").trimResults().omitEmptyStrings()
+                
.split(KylinConfig.getInstanceFromEnv().getCoadhaleMetricReportClassesName()));
+        if (metricsReporterNames.isEmpty()) {
+            return false;
+        }
+
+        MetricsReporting reporter = null;
+        for (String metricsReportingName : metricsReporterNames) {
+            try {
+                reporter = 
MetricsReporting.valueOf(metricsReportingName.trim().toUpperCase());
+            } catch (IllegalArgumentException e) {
+                LOGGER.error("Invalid reporter name " + metricsReportingName, 
e);
+                throw e;
+            }
+            CodahaleReporter codahaleReporter = null;
+            switch (reporter) {
+            case CONSOLE:
+                codahaleReporter = new ConsoleMetricsReporter(metricRegistry, 
conf);
+                break;
+            case JMX:
+                codahaleReporter = new JmxMetricsReporter(metricRegistry, 
conf);
+                break;
+            case JSON_FILE:
+                codahaleReporter = new JsonFileMetricsReporter(metricRegistry, 
conf);
+                break;
+            case HADOOP2:
+                codahaleReporter = new Metrics2Reporter(metricRegistry, conf);
+                break;
+            default:
+                LOGGER.warn("Unhandled reporter " + reporter + " provided.");
+            }
+            if (codahaleReporter != null) {
+                codahaleReporter.start();
+                reporters.add(codahaleReporter);
+            }
+        }
+        return true;
+    }
+
+    public class CodahaleMetricsScope implements MetricsScope {
+
+        private final String name;
+        private final Timer timer;
+        private Timer.Context timerContext;
+
+        private boolean isOpen = false;
+
+        /**
+         * Instantiates a named scope - intended to only be called by Metrics, 
so locally scoped.
+         * @param name - name of the variable
+         */
+        private CodahaleMetricsScope(String name) {
+            this.name = name;
+            this.timer = CodahaleMetrics.this.getTimer(MetricsConstant.CALLS + 
name);
+            open();
+        }
+
+        /**
+         * Opens scope, and makes note of the time started, increments run 
counter
+         *
+         */
+        public void open() {
+            if (!isOpen) {
+                isOpen = true;
+                this.timerContext = timer.time();
+                
CodahaleMetrics.this.incrementCounter(MetricsConstant.ACTIVE_CALLS + name);
+            } else {
+                LOGGER.warn("Scope named " + name + " is not closed, cannot be 
opened.");
+            }
+        }
+
+        /**
+         * Closes scope, and records the time taken
+         */
+        public void close() {
+            if (isOpen) {
+                timerContext.close();
+                
CodahaleMetrics.this.decrementCounter(MetricsConstant.ACTIVE_CALLS + name);
+            } else {
+                LOGGER.warn("Scope named " + name + " is not open, cannot be 
closed.");
+            }
+            isOpen = false;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/8e078847/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/CodahaleReporter.java
----------------------------------------------------------------------
diff --git 
a/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/CodahaleReporter.java
 
b/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/CodahaleReporter.java
new file mode 100644
index 0000000..354f427
--- /dev/null
+++ 
b/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/CodahaleReporter.java
@@ -0,0 +1,31 @@
+/*
+ * 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.kylin.common.metrics.metrics2;
+
+import java.io.Closeable;
+
+import com.codahale.metrics.Reporter;
+
+public interface CodahaleReporter extends Closeable, Reporter {
+
+    /**
+     * Start the reporter.
+     */
+    public void start();
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/8e078847/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/ConsoleMetricsReporter.java
----------------------------------------------------------------------
diff --git 
a/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/ConsoleMetricsReporter.java
 
b/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/ConsoleMetricsReporter.java
new file mode 100644
index 0000000..b292443
--- /dev/null
+++ 
b/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/ConsoleMetricsReporter.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.kylin.common.metrics.metrics2;
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.kylin.common.KylinConfig;
+
+import com.codahale.metrics.ConsoleReporter;
+import com.codahale.metrics.MetricRegistry;
+
+/**
+ * A wrapper around Codahale ConsoleReporter to make it a 
pluggable/configurable Hive Metrics reporter.
+ */
+public class ConsoleMetricsReporter implements CodahaleReporter {
+
+    private final ConsoleReporter reporter;
+
+    public ConsoleMetricsReporter(MetricRegistry registry, KylinConfig conf) {
+
+        reporter = 
ConsoleReporter.forRegistry(registry).convertRatesTo(TimeUnit.SECONDS)
+                .convertDurationsTo(TimeUnit.MILLISECONDS).build();
+
+    }
+
+    @Override
+    public void start() {
+        reporter.start(10, TimeUnit.SECONDS);
+    }
+
+    @Override
+    public void close() {
+        reporter.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/8e078847/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/JmxMetricsReporter.java
----------------------------------------------------------------------
diff --git 
a/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/JmxMetricsReporter.java
 
b/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/JmxMetricsReporter.java
new file mode 100644
index 0000000..2b18f2e
--- /dev/null
+++ 
b/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/JmxMetricsReporter.java
@@ -0,0 +1,55 @@
+/*
+ * 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.kylin.common.metrics.metrics2;
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.kylin.common.KylinConfig;
+
+import com.codahale.metrics.JmxReporter;
+import com.codahale.metrics.MetricRegistry;
+
+/**
+ * A wrapper around Codahale JmxReporter to make it a pluggable/configurable 
Hive Metrics reporter.
+ */
+public class JmxMetricsReporter implements CodahaleReporter {
+
+    private final MetricRegistry registry;
+    private final KylinConfig conf;
+    private final JmxReporter jmxReporter;
+
+    public JmxMetricsReporter(MetricRegistry registry, KylinConfig conf) {
+        this.registry = registry;
+        this.conf = conf;
+
+        jmxReporter = 
JmxReporter.forRegistry(registry).convertRatesTo(TimeUnit.SECONDS)
+                .createsObjectNamesWith(new 
KylinObjectNameFactory()).convertDurationsTo(TimeUnit.MILLISECONDS).build();
+    }
+
+    @Override
+    public void start() {
+        jmxReporter.start();
+    }
+
+    @Override
+    public void close() {
+        jmxReporter.close();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/8e078847/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/JsonFileMetricsReporter.java
----------------------------------------------------------------------
diff --git 
a/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/JsonFileMetricsReporter.java
 
b/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/JsonFileMetricsReporter.java
new file mode 100644
index 0000000..6e8ad76
--- /dev/null
+++ 
b/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/JsonFileMetricsReporter.java
@@ -0,0 +1,136 @@
+/*
+ * 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.kylin.common.metrics.metrics2;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.net.URI;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.fs.permission.FsPermission;
+import org.apache.kylin.common.KylinConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.json.MetricsModule;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectWriter;
+
+/**
+ * A metrics reporter for CodahaleMetrics that dumps metrics periodically into 
a file in JSON format.
+ */
+
+public class JsonFileMetricsReporter implements CodahaleReporter {
+
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(JsonFileMetricsReporter.class);
+    private final MetricRegistry metricRegistry;
+    private final ObjectWriter jsonWriter;
+    private final ScheduledExecutorService executorService;
+    private final KylinConfig conf;
+    private final long interval;
+    private final String pathString;
+    private final Path path;
+
+    public JsonFileMetricsReporter(MetricRegistry registry, KylinConfig conf) {
+        this.metricRegistry = registry;
+        this.jsonWriter = new ObjectMapper()
+                .registerModule(new MetricsModule(TimeUnit.MILLISECONDS, 
TimeUnit.MILLISECONDS, false))
+                .writerWithDefaultPrettyPrinter();
+        executorService = Executors.newSingleThreadScheduledExecutor();
+        this.conf = conf;
+
+        interval = 
KylinConfig.getInstanceFromEnv().getJsonFileMetricsReporterInterval();
+        pathString = KylinConfig.getInstanceFromEnv().getMetricFileLocation();
+        path = new Path(pathString);
+    }
+
+    @Override
+    public void start() {
+
+        final Path tmpPath = new Path(pathString + ".tmp");
+        URI tmpPathURI = tmpPath.toUri();
+        final FileSystem fs;
+        try {
+            if (tmpPathURI.getScheme() == null && tmpPathURI.getAuthority() == 
null) {
+                //default local
+                fs = FileSystem.getLocal(new Configuration());
+            } else {
+                fs = FileSystem.get(tmpPathURI, new Configuration());
+            }
+        } catch (IOException e) {
+            LOGGER.error("Unable to access filesystem for path " + tmpPath + 
". Aborting reporting", e);
+            return;
+        }
+
+        Runnable task = new Runnable() {
+            public void run() {
+                try {
+                    String json = null;
+                    try {
+                        json = jsonWriter.writeValueAsString(metricRegistry);
+                    } catch (JsonProcessingException e) {
+                        LOGGER.error("Unable to convert json to string ", e);
+                        return;
+                    }
+
+                    BufferedWriter bw = null;
+                    try {
+                        fs.delete(tmpPath, true);
+                        bw = new BufferedWriter(new 
OutputStreamWriter(fs.create(tmpPath, true)));
+                        bw.write(json);
+                        fs.setPermission(tmpPath, 
FsPermission.createImmutable((short) 0644));
+                    } catch (IOException e) {
+                        LOGGER.error("Unable to write to temp file " + 
tmpPath, e);
+                        return;
+                    } finally {
+                        if (bw != null) {
+                            bw.close();
+                        }
+                    }
+
+                    try {
+                        fs.rename(tmpPath, path);
+                        fs.setPermission(path, 
FsPermission.createImmutable((short) 0644));
+                    } catch (IOException e) {
+                        LOGGER.error("Unable to rename temp file " + tmpPath + 
" to " + pathString, e);
+                        return;
+                    }
+                } catch (Throwable t) {
+                    // catch all errors (throwable and execptions to prevent 
subsequent tasks from being suppressed)
+                    LOGGER.error("Error executing scheduled task ", t);
+                }
+            }
+        };
+
+        executorService.scheduleWithFixedDelay(task, 0, interval, 
TimeUnit.MILLISECONDS);
+    }
+
+    @Override
+    public void close() {
+        executorService.shutdown();
+    }
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/8e078847/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/KylinObjectNameFactory.java
----------------------------------------------------------------------
diff --git 
a/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/KylinObjectNameFactory.java
 
b/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/KylinObjectNameFactory.java
new file mode 100644
index 0000000..3348999
--- /dev/null
+++ 
b/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/KylinObjectNameFactory.java
@@ -0,0 +1,68 @@
+/*
+ * 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.kylin.common.metrics.metrics2;
+
+import java.util.Hashtable;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.codahale.metrics.ObjectNameFactory;
+
+public class KylinObjectNameFactory implements ObjectNameFactory {
+
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(KylinObjectNameFactory.class);
+
+    @Override
+    public ObjectName createName(String type, String domain, String name) {
+        try {
+            if (name.startsWith(domain)) {
+                ObjectName objectName = new ObjectName(name);
+                return objectName;
+            }
+
+            ObjectName objectName = new ObjectName(domain, "name", name);
+            if (objectName.isPattern()) {
+                objectName = new ObjectName(domain, "name", 
ObjectName.quote(name));
+            }
+            return objectName;
+        } catch (MalformedObjectNameException e) {
+            try {
+                return new ObjectName(domain, "name", ObjectName.quote(name));
+            } catch (MalformedObjectNameException e1) {
+                LOGGER.warn("Unable to register {} {}", type, name, e1);
+                throw new RuntimeException(e1);
+            }
+        }
+    }
+
+    public ObjectName process(String domain, String name) throws 
MalformedObjectNameException {
+        String[] kvArry = name.split(",");
+        Hashtable<String, String> hashTable = new Hashtable<>();
+        for (int i = 0; i < kvArry.length; i++) {
+            String[] split = kvArry[i].split("=");
+            hashTable.put(split[0], split[1]);
+        }
+        ObjectName objectName = new ObjectName(domain, hashTable);
+        return objectName;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/kylin/blob/8e078847/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/MetricVariableRatioGauge.java
----------------------------------------------------------------------
diff --git 
a/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/MetricVariableRatioGauge.java
 
b/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/MetricVariableRatioGauge.java
new file mode 100644
index 0000000..b49093d
--- /dev/null
+++ 
b/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/MetricVariableRatioGauge.java
@@ -0,0 +1,47 @@
+/*
+ * 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.kylin.common.metrics.metrics2;
+
+import com.codahale.metrics.RatioGauge;
+import org.apache.kylin.common.metrics.common.MetricsVariable;
+
+
+/**
+ * Combines two numeric metric variables into one gauge type metric displaying 
their ratio
+ */
+public class MetricVariableRatioGauge extends RatioGauge {
+
+    private final MetricsVariable<Integer> numerator;
+    private final MetricsVariable<Integer> denominator;
+
+    public MetricVariableRatioGauge(MetricsVariable<Integer> numerator, 
MetricsVariable<Integer> denominator) {
+        this.numerator = numerator;
+        this.denominator = denominator;
+    }
+
+    @Override
+    protected Ratio getRatio() {
+        Integer numValue = numerator.getValue();
+        Integer denomValue = denominator.getValue();
+        if (numValue != null && denomValue != null) {
+            return Ratio.of(numValue.doubleValue(), denomValue.doubleValue());
+        }
+        return Ratio.of(0d, 0d);
+    }
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/8e078847/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/Metrics2Reporter.java
----------------------------------------------------------------------
diff --git 
a/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/Metrics2Reporter.java
 
b/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/Metrics2Reporter.java
new file mode 100644
index 0000000..d1c3c7f
--- /dev/null
+++ 
b/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/Metrics2Reporter.java
@@ -0,0 +1,60 @@
+/*
+ * 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.kylin.common.metrics.metrics2;
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
+import org.apache.kylin.common.KylinConfig;
+
+import com.codahale.metrics.MetricRegistry;
+import com.github.joshelser.dropwizard.metrics.hadoop.HadoopMetrics2Reporter;
+
+/**
+ * A wrapper around Codahale HadoopMetrics2Reporter to make it a 
pluggable/configurable Hive Metrics reporter.
+ */
+public class Metrics2Reporter implements CodahaleReporter {
+
+    private final MetricRegistry metricRegistry;
+    private final KylinConfig conf;
+    private final HadoopMetrics2Reporter reporter;
+
+    public Metrics2Reporter(MetricRegistry registry, KylinConfig conf) {
+        this.metricRegistry = registry;
+        this.conf = conf;
+        String applicationName = "kylin";
+
+        reporter = 
HadoopMetrics2Reporter.forRegistry(metricRegistry).convertRatesTo(TimeUnit.SECONDS)
+                
.convertDurationsTo(TimeUnit.MILLISECONDS).build(DefaultMetricsSystem.initialize(applicationName),
 // The application-level name
+                        applicationName, // Component name
+                        applicationName, // Component description
+                        "General"); // Name for each metric record
+    }
+
+    @Override
+    public void start() {
+        long reportingInterval = 30;
+        reporter.start(reportingInterval, TimeUnit.SECONDS);
+    }
+
+    @Override
+    public void close() {
+        reporter.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/8e078847/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/MetricsReporting.java
----------------------------------------------------------------------
diff --git 
a/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/MetricsReporting.java
 
b/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/MetricsReporting.java
new file mode 100644
index 0000000..fc1b663
--- /dev/null
+++ 
b/core-common/src/main/java/org/apache/kylin/common/metrics/metrics2/MetricsReporting.java
@@ -0,0 +1,26 @@
+/*
+ * 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.kylin.common.metrics.metrics2;
+
+/**
+ * Reporting options for 
org.apache.hadoop.hive.common.metrics.metrics2.Metrics.
+ */
+public enum MetricsReporting {
+    JMX, CONSOLE, JSON_FILE, HADOOP2
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/8e078847/core-common/src/main/java/org/apache/kylin/common/metrics/perflog/IPerfLogger.java
----------------------------------------------------------------------
diff --git 
a/core-common/src/main/java/org/apache/kylin/common/metrics/perflog/IPerfLogger.java
 
b/core-common/src/main/java/org/apache/kylin/common/metrics/perflog/IPerfLogger.java
new file mode 100644
index 0000000..83a4210
--- /dev/null
+++ 
b/core-common/src/main/java/org/apache/kylin/common/metrics/perflog/IPerfLogger.java
@@ -0,0 +1,48 @@
+/*
+ * 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.kylin.common.metrics.perflog;
+
+public interface IPerfLogger {
+
+    /**
+     * Call this function when you start to measure time spent by a piece of 
code.
+     *
+     * @param callerName the logging object to be used.
+     * @param method     method or ID that identifies this perf log element.
+     */
+    public void perfLogBegin(String callerName, String method);
+
+    /**
+     * Call this function in correspondence of perfLogBegin to mark the end of 
the measurement.
+     *
+     * @param callerName
+     * @param method
+     * @return long duration  the difference between now and startTime, or -1 
if startTime is null
+     */
+    public long perfLogEnd(String callerName, String method);
+
+    /**
+     * Call this function in correspondence of perfLogBegin to mark the end of 
the measurement.
+     *
+     * @param callerName
+     * @param method
+     * @return long duration  the difference between now and startTime, or -1 
if startTime is null
+     */
+    public long perfLogEnd(String callerName, String method, String 
additionalInfo);
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/8e078847/core-common/src/main/java/org/apache/kylin/common/metrics/perflog/PerfLogger.java
----------------------------------------------------------------------
diff --git 
a/core-common/src/main/java/org/apache/kylin/common/metrics/perflog/PerfLogger.java
 
b/core-common/src/main/java/org/apache/kylin/common/metrics/perflog/PerfLogger.java
new file mode 100644
index 0000000..cf235bb
--- /dev/null
+++ 
b/core-common/src/main/java/org/apache/kylin/common/metrics/perflog/PerfLogger.java
@@ -0,0 +1,158 @@
+/*
+ * 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.kylin.common.metrics.perflog;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.kylin.common.metrics.common.Metrics;
+import org.apache.kylin.common.metrics.common.MetricsFactory;
+import org.apache.kylin.common.metrics.common.MetricsScope;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableMap;
+
+
+/**
+ * PerfLogger.
+ * <p>
+ * Can be used to measure and log the time spent by a piece of code.
+ */
+public class PerfLogger implements IPerfLogger {
+
+    static final private Logger LOG = 
LoggerFactory.getLogger(PerfLogger.class.getName());
+    protected final Map<String, Long> startTimes = new HashMap<String, Long>();
+    protected final Map<String, Long> endTimes = new HashMap<String, Long>();
+    //Methods for metrics integration.  Each thread-local PerfLogger will 
open/close scope during each perf-log method.
+    transient Map<String, MetricsScope> openScopes = new HashMap<String, 
MetricsScope>();
+
+    public void perfLogBegin(String callerName, String method) {
+        long startTime = System.currentTimeMillis();
+        startTimes.put(method, new Long(startTime));
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("<PERFLOG method=" + method + " from=" + callerName + 
">");
+        }
+        beginMetrics(callerName + "." +  method);
+    }
+
+    public long perfLogEnd(String callerName, String method) {
+        return perfLogEnd(callerName, method, null);
+    }
+
+    public long perfLogEnd(String callerName, String method, String 
additionalInfo) {
+        Long startTime = startTimes.get(method);
+        long endTime = System.currentTimeMillis();
+        endTimes.put(method, new Long(endTime));
+        long duration = startTime == null ? -1 : endTime - 
startTime.longValue();
+
+        if (LOG.isDebugEnabled()) {
+            StringBuilder sb = new StringBuilder("</PERFLOG 
method=").append(method);
+            if (startTime != null) {
+                sb.append(" start=").append(startTime);
+            }
+            sb.append(" end=").append(endTime);
+            if (startTime != null) {
+                sb.append(" duration=").append(duration);
+            }
+            sb.append(" from=").append(callerName);
+            if (additionalInfo != null) {
+                sb.append(" ").append(additionalInfo);
+            }
+            sb.append(">");
+            LOG.debug(sb.toString());
+        }
+        endMetrics(callerName + "." + method);
+        return duration;
+    }
+
+    public Long getStartTime(String method) {
+        long startTime = 0L;
+
+        if (startTimes.containsKey(method)) {
+            startTime = startTimes.get(method);
+        }
+        return startTime;
+    }
+
+    public Long getEndTime(String method) {
+        long endTime = 0L;
+
+        if (endTimes.containsKey(method)) {
+            endTime = endTimes.get(method);
+        }
+        return endTime;
+    }
+
+    public boolean startTimeHasMethod(String method) {
+        return startTimes.containsKey(method);
+    }
+
+    public boolean endTimeHasMethod(String method) {
+        return endTimes.containsKey(method);
+    }
+
+    public Long getDuration(String method) {
+        long duration = 0;
+        if (startTimes.containsKey(method) && endTimes.containsKey(method)) {
+            duration = endTimes.get(method) - startTimes.get(method);
+        }
+        return duration;
+    }
+
+    public ImmutableMap<String, Long> getStartTimes() {
+        return ImmutableMap.copyOf(startTimes);
+    }
+
+    public ImmutableMap<String, Long> getEndTimes() {
+        return ImmutableMap.copyOf(endTimes);
+    }
+
+    private void beginMetrics(String method) {
+        Metrics metrics = MetricsFactory.getInstance();
+        if (metrics != null) {
+            MetricsScope scope = metrics.createScope(method);
+            openScopes.put(method, scope);
+        }
+
+    }
+
+    private void endMetrics(String method) {
+        Metrics metrics = MetricsFactory.getInstance();
+        if (metrics != null) {
+            MetricsScope scope = openScopes.remove(method);
+            if (scope != null) {
+                metrics.endScope(scope);
+            }
+        }
+    }
+
+    /**
+     * Cleans up any dangling perfLog metric call scopes.
+     */
+    public void cleanupPerfLogMetrics() {
+        Metrics metrics = MetricsFactory.getInstance();
+        if (metrics != null) {
+            for (MetricsScope openScope : openScopes.values()) {
+                metrics.endScope(openScope);
+            }
+        }
+        openScopes.clear();
+    }
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/8e078847/core-common/src/main/java/org/apache/kylin/common/metrics/perflog/PerfLoggerFactory.java
----------------------------------------------------------------------
diff --git 
a/core-common/src/main/java/org/apache/kylin/common/metrics/perflog/PerfLoggerFactory.java
 
b/core-common/src/main/java/org/apache/kylin/common/metrics/perflog/PerfLoggerFactory.java
new file mode 100644
index 0000000..4fc43a8
--- /dev/null
+++ 
b/core-common/src/main/java/org/apache/kylin/common/metrics/perflog/PerfLoggerFactory.java
@@ -0,0 +1,56 @@
+/*
+ * 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.kylin.common.metrics.perflog;
+
+import org.apache.commons.lang3.ClassUtils;
+import org.apache.kylin.common.KylinConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PerfLoggerFactory {
+
+    protected static final ThreadLocal<IPerfLogger> perfLogger = new 
ThreadLocal<IPerfLogger>();
+    static final private Logger LOG = 
LoggerFactory.getLogger(PerfLoggerFactory.class.getName());
+
+    public static IPerfLogger getPerfLogger() {
+        return getPerfLogger(false);
+    }
+
+    public static void setPerfLogger(IPerfLogger iPerfLogger) {
+        perfLogger.set(iPerfLogger);
+    }
+
+    public static IPerfLogger getPerfLogger(boolean resetPerfLogger) {
+        IPerfLogger result = perfLogger.get();
+        if (resetPerfLogger || result == null) {
+            try {
+                result = (IPerfLogger) 
ClassUtils.getClass(KylinConfig.getInstanceFromEnv().getPerfLoggerClassName())
+                        .newInstance();
+            } catch (ClassNotFoundException e) {
+                LOG.error("Performance Logger Class not found:" + 
e.getMessage());
+                result = new SimplePerfLogger();
+            } catch (IllegalAccessException | InstantiationException e) {
+                e.printStackTrace();
+            }
+            perfLogger.set(result);
+        }
+        return result;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/8e078847/core-common/src/main/java/org/apache/kylin/common/metrics/perflog/SimplePerfLogger.java
----------------------------------------------------------------------
diff --git 
a/core-common/src/main/java/org/apache/kylin/common/metrics/perflog/SimplePerfLogger.java
 
b/core-common/src/main/java/org/apache/kylin/common/metrics/perflog/SimplePerfLogger.java
new file mode 100644
index 0000000..cd88c65
--- /dev/null
+++ 
b/core-common/src/main/java/org/apache/kylin/common/metrics/perflog/SimplePerfLogger.java
@@ -0,0 +1,73 @@
+/*
+ * 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.kylin.common.metrics.perflog;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SimplePerfLogger implements IPerfLogger {
+
+    static final private Logger LOG = 
LoggerFactory.getLogger(SimplePerfLogger.class.getName());
+    protected final Map<String, Long> startTimes = new HashMap<String, Long>();
+    protected final Map<String, Long> endTimes = new HashMap<String, Long>();
+
+    protected SimplePerfLogger() {
+    }
+
+    public void perfLogBegin(String callerName, String method) {
+        long startTime = System.currentTimeMillis();
+        startTimes.put(method, new Long(startTime));
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("<PERFLOG method=" + method + " from=" + callerName + 
">");
+        }
+    }
+
+    public long perfLogEnd(String callerName, String method) {
+        return perfLogEnd(callerName, method, null);
+    }
+
+    public long perfLogEnd(String callerName, String method, String 
additionalInfo) {
+        Long startTime = startTimes.get(method);
+        long endTime = System.currentTimeMillis();
+        endTimes.put(method, new Long(endTime));
+        long duration = startTime == null ? -1 : endTime - 
startTime.longValue();
+
+        if (LOG.isDebugEnabled()) {
+            StringBuilder sb = new StringBuilder("</PERFLOG 
method=").append(method);
+            if (startTime != null) {
+                sb.append(" start=").append(startTime);
+            }
+            sb.append(" end=").append(endTime);
+            if (startTime != null) {
+                sb.append(" duration=").append(duration);
+            }
+            sb.append(" from=").append(callerName);
+            if (additionalInfo != null) {
+                sb.append(" ").append(additionalInfo);
+            }
+            sb.append(">");
+            LOG.debug(sb.toString());
+        }
+        return duration;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/8e078847/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index f7444cd..5b00798 100644
--- a/pom.xml
+++ b/pom.xml
@@ -114,7 +114,8 @@
         <cors.version>2.5</cors.version>
         <tomcat.version>7.0.69</tomcat.version>
         <t-digest.version>3.1</t-digest.version>
-
+        <!--metric-->
+        <dropwizard.version>3.1.2</dropwizard.version>
         <!-- REST Service, ref 
https://github.com/spring-projects/spring-boot/blob/v1.3.8.RELEASE/spring-boot-dependencies/pom.xml
 -->
         <spring.boot.version>1.3.8.RELEASE</spring.boot.version>
         <spring.framework.version>4.2.8.RELEASE</spring.framework.version>

http://git-wip-us.apache.org/repos/asf/kylin/blob/8e078847/server-base/src/main/java/org/apache/kylin/rest/init/InitialTaskManager.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/init/InitialTaskManager.java 
b/server-base/src/main/java/org/apache/kylin/rest/init/InitialTaskManager.java
index 8bba674..0194334 100644
--- 
a/server-base/src/main/java/org/apache/kylin/rest/init/InitialTaskManager.java
+++ 
b/server-base/src/main/java/org/apache/kylin/rest/init/InitialTaskManager.java
@@ -20,6 +20,7 @@ package org.apache.kylin.rest.init;
 
 import org.apache.commons.lang.StringUtils;
 import org.apache.kylin.common.KylinConfig;
+import org.apache.kylin.rest.metrics.QueryMetrics2Facade;
 import org.apache.kylin.rest.metrics.QueryMetricsFacade;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -42,7 +43,8 @@ public class InitialTaskManager implements InitializingBean {
     private void runInitialTasks() {
         // init metrics system for kylin
         QueryMetricsFacade.init();
-        
+        QueryMetrics2Facade.init();
+
         KylinConfig kylinConfig = KylinConfig.getInstanceFromEnv();
         String initTasks = kylinConfig.getInitTasks();
         if (!StringUtils.isEmpty(initTasks)) {

http://git-wip-us.apache.org/repos/asf/kylin/blob/8e078847/server-base/src/main/java/org/apache/kylin/rest/metrics/QueryMetrics2Facade.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/metrics/QueryMetrics2Facade.java
 
b/server-base/src/main/java/org/apache/kylin/rest/metrics/QueryMetrics2Facade.java
new file mode 100644
index 0000000..b42e65c
--- /dev/null
+++ 
b/server-base/src/main/java/org/apache/kylin/rest/metrics/QueryMetrics2Facade.java
@@ -0,0 +1,106 @@
+/*
+ * 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.kylin.rest.metrics;
+
+import static org.apache.kylin.common.metrics.common.MetricsConstant.TOTAL;
+import static 
org.apache.kylin.common.metrics.common.Metricss.buildCubeMetricPrefix;
+
+import java.util.concurrent.TimeUnit;
+
+import javax.annotation.concurrent.ThreadSafe;
+
+import org.apache.kylin.common.KylinConfig;
+import org.apache.kylin.common.metrics.common.Metrics;
+import org.apache.kylin.common.metrics.common.MetricsConstant;
+import org.apache.kylin.common.metrics.common.MetricsFactory;
+import org.apache.kylin.common.metrics.common.Metricss;
+import org.apache.kylin.rest.request.SQLRequest;
+import org.apache.kylin.rest.response.SQLResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The entrance of metrics features.
+ */
+@ThreadSafe
+public class QueryMetrics2Facade {
+
+    private static final Logger logger = 
LoggerFactory.getLogger(QueryMetrics2Facade.class);
+    private static Metrics metrics;
+    private static boolean enabled = false;
+
+    public static void init() {
+        enabled = KylinConfig.getInstanceFromEnv().getQueryMetricsEnabled();
+    }
+
+    public static void updateMetrics(SQLRequest sqlRequest, SQLResponse 
sqlResponse) {
+        if (!enabled) {
+            return;
+        }
+        if (metrics == null) {
+            metrics = MetricsFactory.getInstance();
+        }
+        String projectName = sqlRequest.getProject();
+        String cube = sqlResponse.getCube();
+        if (cube == null) {
+            return;
+        }
+        String cubeName = cube.replace("=", "->");
+
+        //        update(getQueryMetrics("Server_Total"), sqlResponse);
+        update(buildCubeMetricPrefix(TOTAL), sqlResponse);
+        update(buildCubeMetricPrefix(projectName), sqlResponse);
+        String cubeMetricName = buildCubeMetricPrefix(projectName, cubeName);
+        update(cubeMetricName, sqlResponse);
+    }
+
+    private static void update(String name, SQLResponse sqlResponse) {
+        try {
+            incrQueryCount(name, sqlResponse);
+            incrCacheHitCount(name, sqlResponse);
+            if (!sqlResponse.getIsException()) {
+                metrics.updateTimer(Metricss.buildMetricName(name, 
MetricsConstant.QUERY_DURATION),
+                        sqlResponse.getDuration(), TimeUnit.MILLISECONDS);
+                metrics.updateHistogram(Metricss.buildMetricName(name, 
MetricsConstant.QUERY_RESULT_ROWCOUNT),
+                        sqlResponse.getResults().size());
+                metrics.updateHistogram(Metricss.buildMetricName(name, 
MetricsConstant.QUERY_SCAN_ROWCOUNT),
+                        sqlResponse.getTotalScanCount());
+            }
+        } catch (Exception e) {
+            logger.error(e.getMessage());
+        }
+
+    }
+
+    private static void incrQueryCount(String name, SQLResponse sqlResponse) {
+        if (!sqlResponse.isHitExceptionCache() && 
!sqlResponse.getIsException()) {
+            metrics.incrementCounter(Metricss.buildMetricName(name, 
MetricsConstant.QUERY_SUCCESS_COUNT));
+        } else {
+            metrics.incrementCounter(Metricss.buildMetricName(name, 
MetricsConstant.QUERY_FAIL_COUNT));
+        }
+        metrics.incrementCounter(Metricss.buildMetricName(name, 
MetricsConstant.QUERY_COUNT));
+    }
+
+    private static void incrCacheHitCount(String name, SQLResponse 
sqlResponse) {
+        if (sqlResponse.isStorageCacheUsed()) {
+            metrics.incrementCounter(Metricss.buildMetricName(name, 
MetricsConstant.QUERY_CACHE_COUNT));
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/8e078847/server-base/src/main/java/org/apache/kylin/rest/service/QueryService.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/service/QueryService.java 
b/server-base/src/main/java/org/apache/kylin/rest/service/QueryService.java
index 24ac5a0..533b93d 100644
--- a/server-base/src/main/java/org/apache/kylin/rest/service/QueryService.java
+++ b/server-base/src/main/java/org/apache/kylin/rest/service/QueryService.java
@@ -87,6 +87,7 @@ import org.apache.kylin.query.util.QueryUtil;
 import org.apache.kylin.rest.constant.Constant;
 import org.apache.kylin.rest.exception.BadRequestException;
 import org.apache.kylin.rest.exception.InternalErrorException;
+import org.apache.kylin.rest.metrics.QueryMetrics2Facade;
 import org.apache.kylin.rest.metrics.QueryMetricsFacade;
 import org.apache.kylin.rest.model.Query;
 import org.apache.kylin.rest.msg.Message;
@@ -436,6 +437,7 @@ public class QueryService extends BasicService {
             logQuery(sqlRequest, sqlResponse);
 
             QueryMetricsFacade.updateMetrics(sqlRequest, sqlResponse);
+            QueryMetrics2Facade.updateMetrics(sqlRequest, sqlResponse);
 
             if (sqlResponse.getIsException())
                 throw new 
InternalErrorException(sqlResponse.getExceptionMessage());

Reply via email to