You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by el...@apache.org on 2016/02/04 19:33:36 UTC

[1/3] calcite git commit: [CALCITE-642] Add an avatica-metrics API

Repository: calcite
Updated Branches:
  refs/heads/master 7ce2e6213 -> 7e5710fc7


http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/dropwizard-metrics2/src/test/java/org/apache/calcite/dropwizard/metrics/hadoop/HadoopMetrics2ReporterTest.java
----------------------------------------------------------------------
diff --git a/dropwizard-metrics2/src/test/java/org/apache/calcite/dropwizard/metrics/hadoop/HadoopMetrics2ReporterTest.java b/dropwizard-metrics2/src/test/java/org/apache/calcite/dropwizard/metrics/hadoop/HadoopMetrics2ReporterTest.java
new file mode 100644
index 0000000..4eee7a2
--- /dev/null
+++ b/dropwizard-metrics2/src/test/java/org/apache/calcite/dropwizard/metrics/hadoop/HadoopMetrics2ReporterTest.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.calcite.dropwizard.metrics.hadoop;
+
+import org.apache.calcite.dropwizard.metrics.hadoop.HadoopMetrics2Reporter.Builder;
+
+import org.apache.hadoop.metrics2.MetricsCollector;
+import org.apache.hadoop.metrics2.MetricsRecordBuilder;
+import org.apache.hadoop.metrics2.MetricsSystem;
+import org.apache.hadoop.metrics2.lib.Interns;
+
+import com.codahale.metrics.Counter;
+import com.codahale.metrics.Gauge;
+import com.codahale.metrics.Histogram;
+import com.codahale.metrics.Meter;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.Snapshot;
+import com.codahale.metrics.Timer;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.mockito.Mockito;
+
+import java.util.AbstractMap.SimpleEntry;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests for {@link HadoopMetrics2Reporter}.
+ */
+public class HadoopMetrics2ReporterTest {
+
+  private MetricRegistry mockRegistry;
+  private MetricsSystem mockMetricsSystem;
+  private String recordName = "myserver";
+  private HadoopMetrics2Reporter metrics2Reporter;
+
+  @Before public void setup() {
+    mockRegistry = mock(MetricRegistry.class);
+    mockMetricsSystem = mock(MetricsSystem.class);
+
+    recordName = "myserver";
+    metrics2Reporter = HadoopMetrics2Reporter.forRegistry(mockRegistry)
+        .convertDurationsTo(TimeUnit.MILLISECONDS)
+        .convertRatesTo(TimeUnit.SECONDS)
+        .build(mockMetricsSystem, "MyServer", "My Cool Server", recordName);
+  }
+
+  private void verifyRecordBuilderUnits(MetricsRecordBuilder recordBuilder) {
+    verify(recordBuilder).tag(HadoopMetrics2Reporter.RATE_UNIT_LABEL,
+        metrics2Reporter.getRateUnit());
+    verify(recordBuilder).tag(HadoopMetrics2Reporter.DURATION_UNIT_LABEL,
+        metrics2Reporter.getDurationUnit());
+  }
+
+  @Test public void testBuilderDefaults() {
+    Builder builder = HadoopMetrics2Reporter.forRegistry(mockRegistry);
+
+    final String jmxContext = "MyJmxContext;sub=Foo";
+    final String desc = "Description";
+    final String recordName = "Metrics";
+
+    HadoopMetrics2Reporter reporter =
+        builder.build(mockMetricsSystem, jmxContext, desc, recordName);
+
+    assertEquals(mockMetricsSystem, reporter.getMetrics2System());
+    // The Context "tag", not the jmx context
+    assertEquals(null, reporter.getContext());
+    assertEquals(recordName, reporter.getRecordName());
+  }
+
+  @Test public void testGaugeReporting() {
+    final AtomicLong gaugeValue = new AtomicLong(0L);
+    @SuppressWarnings("rawtypes")
+    final Gauge gauge = new Gauge<Long>() {
+      @Override public Long getValue() {
+        return gaugeValue.get();
+      }
+    };
+
+    // Add the metrics objects to the internal "queues" by hand
+    metrics2Reporter.getDropwizardGauges().add(new SimpleEntry<>("my_gauge", gauge));
+
+    // Set some values
+    gaugeValue.set(5L);
+
+    MetricsCollector collector = mock(MetricsCollector.class);
+    MetricsRecordBuilder recordBuilder = mock(MetricsRecordBuilder.class);
+
+    Mockito.when(collector.addRecord(recordName)).thenReturn(recordBuilder);
+
+    // Make sure a value of 5 gets reported
+    metrics2Reporter.getMetrics(collector, true);
+
+    verify(recordBuilder).addGauge(Interns.info("my_gauge", ""), gaugeValue.get());
+    verifyRecordBuilderUnits(recordBuilder);
+  }
+
+  @Test public void testCounterReporting() {
+    final Counter counter = new Counter();
+
+    // Add the metrics objects to the internal "queues" by hand
+    metrics2Reporter.getDropwizardCounters().add(new SimpleEntry<>("my_counter", counter));
+
+    // Set some values
+    counter.inc(5L);
+
+    MetricsCollector collector = mock(MetricsCollector.class);
+    MetricsRecordBuilder recordBuilder = mock(MetricsRecordBuilder.class);
+
+    Mockito.when(collector.addRecord(recordName)).thenReturn(recordBuilder);
+
+    metrics2Reporter.getMetrics(collector, true);
+
+    verify(recordBuilder).addCounter(Interns.info("my_counter", ""), 5L);
+    verifyRecordBuilderUnits(recordBuilder);
+  }
+
+  @Test public void testHistogramReporting() {
+    final String metricName = "my_histogram";
+    final Histogram histogram = mock(Histogram.class);
+    final Snapshot snapshot = mock(Snapshot.class);
+
+    long count = 10L;
+    double percentile75 = 75;
+    double percentile95 = 95;
+    double percentile98 = 98;
+    double percentile99 = 99;
+    double percentile999 = 999;
+    double median = 50;
+    double mean = 60;
+    long min = 1L;
+    long max = 100L;
+    double stddev = 10;
+
+    when(snapshot.get75thPercentile()).thenReturn(percentile75);
+    when(snapshot.get95thPercentile()).thenReturn(percentile95);
+    when(snapshot.get98thPercentile()).thenReturn(percentile98);
+    when(snapshot.get99thPercentile()).thenReturn(percentile99);
+    when(snapshot.get999thPercentile()).thenReturn(percentile999);
+    when(snapshot.getMedian()).thenReturn(median);
+    when(snapshot.getMean()).thenReturn(mean);
+    when(snapshot.getMin()).thenReturn(min);
+    when(snapshot.getMax()).thenReturn(max);
+    when(snapshot.getStdDev()).thenReturn(stddev);
+
+    when(histogram.getCount()).thenReturn(count);
+    when(histogram.getSnapshot()).thenReturn(snapshot);
+
+    MetricsCollector collector = mock(MetricsCollector.class);
+    MetricsRecordBuilder recordBuilder = mock(MetricsRecordBuilder.class);
+
+    Mockito.when(collector.addRecord(recordName)).thenReturn(recordBuilder);
+
+    // Add the metrics objects to the internal "queues" by hand
+    metrics2Reporter.getDropwizardHistograms().add(new SimpleEntry<>(metricName, histogram));
+
+    metrics2Reporter.getMetrics(collector, true);
+
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_max", ""),
+        metrics2Reporter.convertDuration(max));
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_min", ""),
+        metrics2Reporter.convertDuration(min));
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_median", ""),
+        metrics2Reporter.convertDuration(median));
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_count", ""), count);
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_stddev", ""),
+        metrics2Reporter.convertDuration(stddev));
+
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_75thpercentile", ""),
+        metrics2Reporter.convertDuration(percentile75));
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_95thpercentile", ""),
+        metrics2Reporter.convertDuration(percentile95));
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_98thpercentile", ""),
+        metrics2Reporter.convertDuration(percentile98));
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_99thpercentile", ""),
+        metrics2Reporter.convertDuration(percentile99));
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_999thpercentile", ""),
+        metrics2Reporter.convertDuration(percentile999));
+
+    verifyRecordBuilderUnits(recordBuilder);
+  }
+
+  @Test public void testTimerReporting() {
+    final String metricName = "my_timer";
+    final Timer timer = mock(Timer.class);
+    final Snapshot snapshot = mock(Snapshot.class);
+
+    // Add the metrics objects to the internal "queues" by hand
+    metrics2Reporter.getDropwizardTimers().add(new SimpleEntry<>(metricName, timer));
+
+    long count = 10L;
+    double meanRate = 1.0;
+    double oneMinRate = 2.0;
+    double fiveMinRate = 5.0;
+    double fifteenMinRate = 10.0;
+
+    when(timer.getCount()).thenReturn(count);
+    when(timer.getMeanRate()).thenReturn(meanRate);
+    when(timer.getOneMinuteRate()).thenReturn(oneMinRate);
+    when(timer.getFiveMinuteRate()).thenReturn(fiveMinRate);
+    when(timer.getFifteenMinuteRate()).thenReturn(fifteenMinRate);
+    when(timer.getSnapshot()).thenReturn(snapshot);
+
+    double percentile75 = 75;
+    double percentile95 = 95;
+    double percentile98 = 98;
+    double percentile99 = 99;
+    double percentile999 = 999;
+    double median = 50;
+    double mean = 60;
+    long min = 1L;
+    long max = 100L;
+    double stddev = 10;
+
+    when(snapshot.get75thPercentile()).thenReturn(percentile75);
+    when(snapshot.get95thPercentile()).thenReturn(percentile95);
+    when(snapshot.get98thPercentile()).thenReturn(percentile98);
+    when(snapshot.get99thPercentile()).thenReturn(percentile99);
+    when(snapshot.get999thPercentile()).thenReturn(percentile999);
+    when(snapshot.getMedian()).thenReturn(median);
+    when(snapshot.getMean()).thenReturn(mean);
+    when(snapshot.getMin()).thenReturn(min);
+    when(snapshot.getMax()).thenReturn(max);
+    when(snapshot.getStdDev()).thenReturn(stddev);
+
+    MetricsCollector collector = mock(MetricsCollector.class);
+    MetricsRecordBuilder recordBuilder = mock(MetricsRecordBuilder.class);
+
+    Mockito.when(collector.addRecord(recordName)).thenReturn(recordBuilder);
+
+    metrics2Reporter.getMetrics(collector, true);
+
+    // We get the count from the meter and histogram
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_count", ""), count);
+
+    // Verify the rates
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_mean_rate", ""),
+        metrics2Reporter.convertRate(meanRate));
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_1min_rate", ""),
+        metrics2Reporter.convertRate(oneMinRate));
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_5min_rate", ""),
+        metrics2Reporter.convertRate(fiveMinRate));
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_15min_rate", ""),
+        metrics2Reporter.convertRate(fifteenMinRate));
+
+    // Verify the histogram
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_max", ""),
+        metrics2Reporter.convertDuration(max));
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_min", ""),
+        metrics2Reporter.convertDuration(min));
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_median", ""),
+        metrics2Reporter.convertDuration(median));
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_stddev", ""),
+        metrics2Reporter.convertDuration(stddev));
+
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_75thpercentile", ""),
+        metrics2Reporter.convertDuration(percentile75));
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_95thpercentile", ""),
+        metrics2Reporter.convertDuration(percentile95));
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_98thpercentile", ""),
+        metrics2Reporter.convertDuration(percentile98));
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_99thpercentile", ""),
+        metrics2Reporter.convertDuration(percentile99));
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_999thpercentile", ""),
+        metrics2Reporter.convertDuration(percentile999));
+
+    verifyRecordBuilderUnits(recordBuilder);
+  }
+
+  @Test public void testMeterReporting() {
+    final String metricName = "my_meter";
+    final Meter meter = mock(Meter.class);
+
+    // Add the metrics objects to the internal "queues" by hand
+    metrics2Reporter.getDropwizardMeters().add(new SimpleEntry<>(metricName, meter));
+
+    // Set some values
+    long count = 10L;
+    double meanRate = 1.0;
+    double oneMinRate = 2.0;
+    double fiveMinRate = 5.0;
+    double fifteenMinRate = 10.0;
+
+    when(meter.getCount()).thenReturn(count);
+    when(meter.getMeanRate()).thenReturn(meanRate);
+    when(meter.getOneMinuteRate()).thenReturn(oneMinRate);
+    when(meter.getFiveMinuteRate()).thenReturn(fiveMinRate);
+    when(meter.getFifteenMinuteRate()).thenReturn(fifteenMinRate);
+
+    MetricsCollector collector = mock(MetricsCollector.class);
+    MetricsRecordBuilder recordBuilder = mock(MetricsRecordBuilder.class);
+
+    Mockito.when(collector.addRecord(recordName)).thenReturn(recordBuilder);
+
+    metrics2Reporter.getMetrics(collector, true);
+
+    // Verify the rates
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_count", ""), count);
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_mean_rate", ""),
+        metrics2Reporter.convertRate(meanRate));
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_1min_rate", ""),
+        metrics2Reporter.convertRate(oneMinRate));
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_5min_rate", ""),
+        metrics2Reporter.convertRate(fiveMinRate));
+    verify(recordBuilder).addGauge(Interns.info(metricName + "_15min_rate", ""),
+        metrics2Reporter.convertRate(fifteenMinRate));
+
+    // Verify the units
+    verifyRecordBuilderUnits(recordBuilder);
+  }
+}
+
+// End HadoopMetrics2ReporterTest.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index a2dffd4..f7477da 100644
--- a/pom.xml
+++ b/pom.xml
@@ -58,6 +58,7 @@ limitations under the License.
     <commons-dbcp.version>1.4</commons-dbcp.version>
     <commons-lang3.version>3.2</commons-lang3.version>
     <commons-logging.version>1.1.3</commons-logging.version>
+    <dropwizard-metrics3.version>3.1.2</dropwizard-metrics3.version>
     <eigenbase-properties.version>1.1.5</eigenbase-properties.version>
     <findbugs.version>1.3.9</findbugs.version>
     <fmpp-maven-plugin.version>1.0</fmpp-maven-plugin.version>
@@ -70,6 +71,7 @@ limitations under the License.
          but prefer more recent versions. -->
     <guava.version>14.0.1</guava.version>
     <h2.version>1.4.185</h2.version>
+    <hadoop.version>2.6.0</hadoop.version>
     <hamcrest.version>1.3</hamcrest.version>
     <hsqldb.version>2.3.1</hsqldb.version>
     <hydromatic-resource.version>0.5.1</hydromatic-resource.version>
@@ -123,8 +125,11 @@ limitations under the License.
 
   <modules>
     <module>avatica</module>
+    <module>avatica-metrics</module>
+    <module>avatica-metrics-dropwizardmetrics3</module>
     <module>avatica-server</module>
     <module>core</module>
+    <module>dropwizard-metrics2</module>
     <module>example</module>
     <module>linq4j</module>
     <module>mongodb</module>
@@ -145,35 +150,40 @@ limitations under the License.
       <!-- Sorted by groupId, artifactId; calcite dependencies first. -->
       <dependency>
         <groupId>org.apache.calcite</groupId>
+        <artifactId>calcite-avatica-metrics</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.calcite</groupId>
         <artifactId>calcite-avatica</artifactId>
-        <version>1.7.0-SNAPSHOT</version>
+        <version>${project.version}</version>
       </dependency>
       <dependency>
         <groupId>org.apache.calcite</groupId>
         <artifactId>calcite-avatica</artifactId>
-        <version>1.7.0-SNAPSHOT</version>
+        <version>${project.version}</version>
         <type>test-jar</type>
       </dependency>
       <dependency>
         <groupId>org.apache.calcite</groupId>
         <artifactId>calcite-avatica-server</artifactId>
-        <version>1.7.0-SNAPSHOT</version>
+        <version>${project.version}</version>
       </dependency>
       <dependency>
         <groupId>org.apache.calcite</groupId>
         <artifactId>calcite-core</artifactId>
-        <version>1.7.0-SNAPSHOT</version>
+        <version>${project.version}</version>
       </dependency>
       <dependency>
         <groupId>org.apache.calcite</groupId>
         <artifactId>calcite-core</artifactId>
         <type>test-jar</type>
-        <version>1.7.0-SNAPSHOT</version>
+        <version>${project.version}</version>
       </dependency>
       <dependency>
         <groupId>org.apache.calcite</groupId>
         <artifactId>calcite-linq4j</artifactId>
-        <version>1.7.0-SNAPSHOT</version>
+        <version>${project.version}</version>
       </dependency>
 
       <!-- Now third-party dependencies, sorted by groupId and artifactId. -->
@@ -278,6 +288,11 @@ limitations under the License.
         <version>${commons-lang3.version}</version>
       </dependency>
       <dependency>
+        <groupId>org.apache.hadoop</groupId>
+        <artifactId>hadoop-common</artifactId>
+        <version>${hadoop.version}</version>
+      </dependency>
+      <dependency>
         <groupId>org.mockito</groupId>
         <artifactId>mockito-all</artifactId>
         <version>${mockito-all.version}</version>


[2/3] calcite git commit: [CALCITE-642] Add an avatica-metrics API

Posted by el...@apache.org.
http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopMetricsSystemConfiguration.java
----------------------------------------------------------------------
diff --git a/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopMetricsSystemConfiguration.java b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopMetricsSystemConfiguration.java
new file mode 100644
index 0000000..42b3f24
--- /dev/null
+++ b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopMetricsSystemConfiguration.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.calcite.avatica.metrics.noop;
+
+import org.apache.calcite.avatica.metrics.MetricsSystemConfiguration;
+
+/**
+ * An empty configuration for the {@link NoopMetricsSystem}.
+ */
+public class NoopMetricsSystemConfiguration implements MetricsSystemConfiguration<Void> {
+
+  private static final NoopMetricsSystemConfiguration INSTANCE =
+      new NoopMetricsSystemConfiguration();
+
+  public static NoopMetricsSystemConfiguration getInstance() {
+    return INSTANCE;
+  }
+
+  private NoopMetricsSystemConfiguration() {}
+
+  @Override public Void get() {
+    return null;
+  }
+}
+
+// End NoopMetricsSystemConfiguration.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopMetricsSystemFactory.java
----------------------------------------------------------------------
diff --git a/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopMetricsSystemFactory.java b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopMetricsSystemFactory.java
new file mode 100644
index 0000000..c15f978
--- /dev/null
+++ b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopMetricsSystemFactory.java
@@ -0,0 +1,35 @@
+/*
+ * 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.calcite.avatica.metrics.noop;
+
+import org.apache.calcite.avatica.metrics.MetricsSystemConfiguration;
+import org.apache.calcite.avatica.metrics.MetricsSystemFactory;
+
+/**
+ * A {@link MetricsSystemFactory} for the {@link NoopMetricsSystem}.
+ *
+ * No service file is provided for this implementation. It is the fallback implementation if
+ * no implementation or more than one implementation is found on the classpath.
+ */
+public class NoopMetricsSystemFactory implements MetricsSystemFactory {
+
+  @Override public NoopMetricsSystem create(MetricsSystemConfiguration<?> config) {
+    return NoopMetricsSystem.getInstance();
+  }
+}
+
+// End NoopMetricsSystemFactory.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopTimer.java
----------------------------------------------------------------------
diff --git a/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopTimer.java b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopTimer.java
new file mode 100644
index 0000000..879da64
--- /dev/null
+++ b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopTimer.java
@@ -0,0 +1,41 @@
+/*
+ * 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.calcite.avatica.metrics.noop;
+
+import org.apache.calcite.avatica.metrics.Timer;
+import org.apache.calcite.avatica.metrics.Timer.Context;
+
+/**
+ * {@link Timer} which does nothing.
+ */
+public class NoopTimer implements Timer {
+
+  @Override public Context start() {
+    return new NoopContext();
+  }
+
+  /**
+   * {@link Context} which does nothing.
+   */
+  public class NoopContext implements Context {
+
+    @Override public void close() {}
+
+  }
+}
+
+// End NoopTimer.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/package-info.java
----------------------------------------------------------------------
diff --git a/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/package-info.java b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/package-info.java
new file mode 100644
index 0000000..826a655
--- /dev/null
+++ b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/package-info.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.
+ */
+
+/**
+ * No-operation implementation for the Avatica Metrics framework.
+ */
+@PackageMarker
+package org.apache.calcite.avatica.metrics.noop;
+
+import org.apache.calcite.avatica.metrics.PackageMarker;
+
+// End package-info.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/package-info.java
----------------------------------------------------------------------
diff --git a/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/package-info.java b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/package-info.java
new file mode 100644
index 0000000..efed28c
--- /dev/null
+++ b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+/**
+ * Metrics for the Avatica framework.
+ */
+@PackageMarker
+package org.apache.calcite.avatica.metrics;
+
+// End package-info.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics/src/test/java/org/apache/calcite/avatica/metrics/MetricsSystemLoaderTest.java
----------------------------------------------------------------------
diff --git a/avatica-metrics/src/test/java/org/apache/calcite/avatica/metrics/MetricsSystemLoaderTest.java b/avatica-metrics/src/test/java/org/apache/calcite/avatica/metrics/MetricsSystemLoaderTest.java
new file mode 100644
index 0000000..1c405ee
--- /dev/null
+++ b/avatica-metrics/src/test/java/org/apache/calcite/avatica/metrics/MetricsSystemLoaderTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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.calcite.avatica.metrics;
+
+import org.apache.calcite.avatica.metrics.noop.NoopMetricsSystem;
+import org.apache.calcite.avatica.metrics.noop.NoopMetricsSystemConfiguration;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Test class for {@link MetricsSystemLoader}.
+ */
+public class MetricsSystemLoaderTest {
+
+  @Test public void testSingleInstance() {
+    final List<MetricsSystemFactory> factories =
+        Collections.<MetricsSystemFactory>singletonList(new MarkedNoopMetricsSystemFactory());
+    MetricsSystemLoader loader = Mockito.mock(MetricsSystemLoader.class);
+
+    Mockito.when(loader.getFactories()).thenReturn(factories);
+    Mockito.when(loader._load(Mockito.any(MetricsSystemConfiguration.class))).thenCallRealMethod();
+
+    // One MetricsSystemFactory should return the MetricsSystem it creates
+    MetricsSystem system = loader._load(NoopMetricsSystemConfiguration.getInstance());
+    assertEquals(MarkedMetricsSystem.INSTANCE, system);
+  }
+
+  @Test public void testMultipleInstances() {
+    // The type of the factories doesn't matter (we can send duplicates for testing purposes)
+    final List<MetricsSystemFactory> factories =
+        Arrays.<MetricsSystemFactory>asList(new MarkedNoopMetricsSystemFactory(),
+            new MarkedNoopMetricsSystemFactory());
+    MetricsSystemLoader loader = Mockito.mock(MetricsSystemLoader.class);
+
+    Mockito.when(loader.getFactories()).thenReturn(factories);
+    Mockito.when(loader._load(Mockito.any(MetricsSystemConfiguration.class))).thenCallRealMethod();
+
+    // We had two factories loaded, therefore we'll fall back to the NoopMetricsSystem
+    MetricsSystem system = loader._load(NoopMetricsSystemConfiguration.getInstance());
+    assertEquals(NoopMetricsSystem.getInstance(), system);
+  }
+
+  @Test public void testNoInstances() {
+    // The type of the factories doesn't matter (we can send duplicates for testing purposes)
+    final List<MetricsSystemFactory> factories = Collections.emptyList();
+    MetricsSystemLoader loader = Mockito.mock(MetricsSystemLoader.class);
+
+    Mockito.when(loader.getFactories()).thenReturn(factories);
+    Mockito.when(loader._load(Mockito.any(MetricsSystemConfiguration.class))).thenCallRealMethod();
+
+    // We had no factories loaded, therefore we'll fall back to the NoopMetricsSystem
+    MetricsSystem system = loader._load(NoopMetricsSystemConfiguration.getInstance());
+    assertEquals(NoopMetricsSystem.getInstance(), system);
+  }
+
+  /**
+   * A test factory implementation which can return a recognized MetricsSystem implementation.
+   */
+  private static class MarkedNoopMetricsSystemFactory implements MetricsSystemFactory {
+    public MarkedMetricsSystem create(MetricsSystemConfiguration<?> config) {
+      return MarkedMetricsSystem.INSTANCE;
+    }
+  }
+
+  /**
+   * A metrics system implementation that is identifiable for testing.
+   */
+  private static class MarkedMetricsSystem implements MetricsSystem {
+    private static final MarkedMetricsSystem INSTANCE = new MarkedMetricsSystem();
+
+    private MarkedMetricsSystem() {}
+
+    @Override public Timer getTimer(String name) {
+      return null;
+    }
+
+    @Override public Histogram getHistogram(String name) {
+      return null;
+    }
+
+    @Override public Meter getMeter(String name) {
+      return null;
+    }
+
+    @Override public Counter getCounter(String name) {
+      return null;
+    }
+
+    @Override public <T> void register(String name, Gauge<T> gauge) {}
+  }
+}
+
+// End MetricsSystemLoaderTest.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics/src/test/java/org/apache/calcite/avatica/metrics/noop/NoopMetricsSystemFactoryTest.java
----------------------------------------------------------------------
diff --git a/avatica-metrics/src/test/java/org/apache/calcite/avatica/metrics/noop/NoopMetricsSystemFactoryTest.java b/avatica-metrics/src/test/java/org/apache/calcite/avatica/metrics/noop/NoopMetricsSystemFactoryTest.java
new file mode 100644
index 0000000..3060b2f
--- /dev/null
+++ b/avatica-metrics/src/test/java/org/apache/calcite/avatica/metrics/noop/NoopMetricsSystemFactoryTest.java
@@ -0,0 +1,37 @@
+/*
+ * 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.calcite.avatica.metrics.noop;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test class for {@link NoopMetricsSystemFactory}.
+ */
+public class NoopMetricsSystemFactoryTest {
+
+  @Test public void testSingleton() {
+    NoopMetricsSystemFactory factory = new NoopMetricsSystemFactory();
+    NoopMetricsSystemConfiguration config = NoopMetricsSystemConfiguration.getInstance();
+    assertTrue("The factory should only return one NoopMetricsSystem instance",
+        factory.create(config) == factory.create(config));
+  }
+
+}
+
+// End NoopMetricsSystemFactoryTest.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics/src/test/java/org/apache/calcite/avatica/metrics/noop/NoopMetricsSystemTest.java
----------------------------------------------------------------------
diff --git a/avatica-metrics/src/test/java/org/apache/calcite/avatica/metrics/noop/NoopMetricsSystemTest.java b/avatica-metrics/src/test/java/org/apache/calcite/avatica/metrics/noop/NoopMetricsSystemTest.java
new file mode 100644
index 0000000..cda453c
--- /dev/null
+++ b/avatica-metrics/src/test/java/org/apache/calcite/avatica/metrics/noop/NoopMetricsSystemTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.calcite.avatica.metrics.noop;
+
+import org.apache.calcite.avatica.metrics.Counter;
+import org.apache.calcite.avatica.metrics.Gauge;
+import org.apache.calcite.avatica.metrics.Histogram;
+import org.apache.calcite.avatica.metrics.Meter;
+import org.apache.calcite.avatica.metrics.MetricsSystem;
+import org.apache.calcite.avatica.metrics.Timer;
+import org.apache.calcite.avatica.metrics.Timer.Context;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests for {@link NoopMetricsSystem}.
+ */
+public class NoopMetricsSystemTest {
+
+  @Test public void testNoNulls() {
+    // The NOOP implementation should act as a real implementation, no "nulls" allowed.
+    MetricsSystem metrics = NoopMetricsSystem.getInstance();
+
+    Counter counter = metrics.getCounter("counter");
+    counter.decrement();
+    counter.increment();
+    counter.decrement(1L);
+    counter.increment(1L);
+
+    Histogram histogram = metrics.getHistogram("histogram");
+    histogram.update(1);
+    histogram.update(1L);
+
+    Timer timer = metrics.getTimer("timer");
+    Context context = timer.start();
+    context.close();
+
+    Meter meter = metrics.getMeter("meter");
+    meter.mark();
+    meter.mark(5L);
+
+    metrics.register("gauge", new Gauge<Long>() {
+      @Override public Long getValue() {
+        return 42L;
+      }
+    });
+  }
+
+  @Test public void testSingleton() {
+    assertTrue("Should be a singleton",
+        NoopMetricsSystem.getInstance() == NoopMetricsSystem.getInstance());
+  }
+}
+
+// End NoopMetricsSystemTest.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/avatica-metrics/src/test/resources/log4j.properties b/avatica-metrics/src/test/resources/log4j.properties
new file mode 100644
index 0000000..834e2db
--- /dev/null
+++ b/avatica-metrics/src/test/resources/log4j.properties
@@ -0,0 +1,24 @@
+# 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.
+
+# Root logger is configured at INFO and is sent to A1
+log4j.rootLogger=INFO, A1
+
+# A1 goes to the console
+log4j.appender.A1=org.apache.log4j.ConsoleAppender
+
+# Set the pattern for each log message
+log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+log4j.appender.A1.layout.ConversionPattern=%d [%t] %-5p - %m%n

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-server/pom.xml
----------------------------------------------------------------------
diff --git a/avatica-server/pom.xml b/avatica-server/pom.xml
index 2386243..9a896f5 100644
--- a/avatica-server/pom.xml
+++ b/avatica-server/pom.xml
@@ -25,7 +25,6 @@ limitations under the License.
 
   <artifactId>calcite-avatica-server</artifactId>
   <packaging>jar</packaging>
-  <version>1.7.0-SNAPSHOT</version>
   <name>Calcite Avatica Server</name>
   <description>JDBC server.</description>
 
@@ -108,6 +107,34 @@ limitations under the License.
   </dependencies>
 
   <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.eclipse.m2e</groupId>
+          <artifactId>lifecycle-mapping</artifactId>
+          <version>1.0.0</version>
+          <configuration>
+            <lifecycleMappingMetadata>
+              <pluginExecutions>
+                <pluginExecution>
+                  <pluginExecutionFilter>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-checkstyle-plugin</artifactId>
+                    <versionRange>[2.12.1,)</versionRange>
+                    <goals>
+                      <goal>check</goal>
+                    </goals>
+                  </pluginExecutionFilter>
+                  <action>
+                    <ignore />
+                  </action>
+                </pluginExecution>
+              </pluginExecutions>
+            </lifecycleMappingMetadata>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
     <plugins>
       <!-- Parent module has the same plugin and does the work of
            generating -sources.jar for each project. But without the
@@ -143,6 +170,7 @@ limitations under the License.
               <failOnWarning>true</failOnWarning>
               <!-- ignore "unused but declared" warnings -->
               <ignoredUnusedDeclaredDependencies>
+                <ignoredUnusedDeclaredDependency>io.dropwizard.metrics:metrics-core</ignoredUnusedDeclaredDependency>
                 <ignoredUnusedDeclaredDependency>net.hydromatic:scott-data-hsqldb</ignoredUnusedDeclaredDependency>
                 <ignoredUnusedDeclaredDependency>org.hsqldb:hsqldb</ignoredUnusedDeclaredDependency>
                 <ignoredUnusedDeclaredDependency>org.slf4j:slf4j-api</ignoredUnusedDeclaredDependency>

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java b/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
index 8cac9f8..becb19d 100644
--- a/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
@@ -28,6 +28,9 @@ import org.apache.calcite.avatica.NoSuchConnectionException;
 import org.apache.calcite.avatica.NoSuchStatementException;
 import org.apache.calcite.avatica.QueryState;
 import org.apache.calcite.avatica.SqlType;
+import org.apache.calcite.avatica.metrics.Gauge;
+import org.apache.calcite.avatica.metrics.MetricsSystem;
+import org.apache.calcite.avatica.metrics.noop.NoopMetricsSystem;
 import org.apache.calcite.avatica.remote.TypedValue;
 
 import com.google.common.cache.Cache;
@@ -38,6 +41,8 @@ import com.google.common.cache.RemovalNotification;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.apache.calcite.avatica.remote.MetricsHelper.concat;
+
 import java.lang.reflect.InvocationTargetException;
 import java.sql.Connection;
 import java.sql.DatabaseMetaData;
@@ -55,6 +60,7 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Properties;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -86,6 +92,7 @@ public class JdbcMeta implements Meta {
   private final Properties info;
   private final Cache<String, Connection> connectionCache;
   private final Cache<Integer, StatementInfo> statementCache;
+  private final MetricsSystem metrics;
 
   /**
    * Creates a JdbcMeta.
@@ -116,6 +123,10 @@ public class JdbcMeta implements Meta {
     });
   }
 
+  public JdbcMeta(String url, Properties info) throws SQLException {
+    this(url, info, NoopMetricsSystem.getInstance());
+  }
+
   /**
    * Creates a JdbcMeta.
    *
@@ -125,9 +136,11 @@ public class JdbcMeta implements Meta {
    * connection arguments; normally at least a "user" and
    * "password" property should be included
    */
-  public JdbcMeta(String url, Properties info) throws SQLException {
+  public JdbcMeta(String url, Properties info, MetricsSystem metrics)
+      throws SQLException {
     this.url = url;
     this.info = info;
+    this.metrics = Objects.requireNonNull(metrics);
 
     int concurrencyLevel = Integer.parseInt(
         info.getProperty(ConnectionCacheSettings.CONCURRENCY_LEVEL.key(),
@@ -177,6 +190,19 @@ public class JdbcMeta implements Meta {
         .build();
 
     LOG.debug("instantiated statement cache: {}", statementCache.stats());
+
+    // Register some metrics
+    this.metrics.register(concat(JdbcMeta.class, "ConnectionCacheSize"), new Gauge<Long>() {
+      @Override public Long getValue() {
+        return connectionCache.size();
+      }
+    });
+
+    this.metrics.register(concat(JdbcMeta.class, "StatementCacheSize"), new Gauge<Long>() {
+      @Override public Long getValue() {
+        return statementCache.size();
+      }
+    });
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaJsonHandler.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaJsonHandler.java b/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaJsonHandler.java
index 250c1d5..703a2c3 100644
--- a/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaJsonHandler.java
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaJsonHandler.java
@@ -17,6 +17,10 @@
 package org.apache.calcite.avatica.server;
 
 import org.apache.calcite.avatica.AvaticaUtils;
+import org.apache.calcite.avatica.metrics.MetricsSystem;
+import org.apache.calcite.avatica.metrics.Timer;
+import org.apache.calcite.avatica.metrics.Timer.Context;
+import org.apache.calcite.avatica.metrics.noop.NoopMetricsSystem;
 import org.apache.calcite.avatica.remote.Handler.HandlerResponse;
 import org.apache.calcite.avatica.remote.JsonHandler;
 import org.apache.calcite.avatica.remote.Service;
@@ -28,6 +32,8 @@ import org.eclipse.jetty.server.handler.AbstractHandler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.apache.calcite.avatica.remote.MetricsHelper.concat;
+
 import java.io.IOException;
 import java.util.Objects;
 
@@ -39,41 +45,56 @@ import javax.servlet.http.HttpServletResponse;
 /**
  * Jetty handler that executes Avatica JSON request-responses.
  */
-public class AvaticaJsonHandler extends AbstractHandler implements AvaticaHandler {
+public class AvaticaJsonHandler extends AbstractHandler implements MetricsAwareAvaticaHandler {
   private static final Logger LOG = LoggerFactory.getLogger(AvaticaJsonHandler.class);
 
   final Service service;
   final JsonHandler jsonHandler;
 
+  final MetricsSystem metrics;
+  final Timer requestTimer;
+
   public AvaticaJsonHandler(Service service) {
+    this(service, NoopMetricsSystem.getInstance());
+  }
+
+  public AvaticaJsonHandler(Service service, MetricsSystem metrics) {
     this.service = Objects.requireNonNull(service);
-    this.jsonHandler = new JsonHandler(service);
+    this.metrics = Objects.requireNonNull(metrics);
+    // Avatica doesn't have a Guava dependency
+    this.jsonHandler = new JsonHandler(service, this.metrics);
+
+    // Metrics
+    this.requestTimer = this.metrics.getTimer(
+        concat(AvaticaJsonHandler.class, MetricsAwareAvaticaHandler.REQUEST_TIMER_NAME));
   }
 
   public void handle(String target, Request baseRequest,
       HttpServletRequest request, HttpServletResponse response)
       throws IOException, ServletException {
-    response.setContentType("application/json;charset=utf-8");
-    response.setStatus(HttpServletResponse.SC_OK);
-    if (request.getMethod().equals("POST")) {
-      // First look for a request in the header, then look in the body.
-      // The latter allows very large requests without hitting HTTP 413.
-      String rawRequest = request.getHeader("request");
-      if (rawRequest == null) {
-        try (ServletInputStream inputStream = request.getInputStream()) {
-          rawRequest = AvaticaUtils.readFully(inputStream);
+    try (final Context ctx = requestTimer.start()) {
+      response.setContentType("application/json;charset=utf-8");
+      response.setStatus(HttpServletResponse.SC_OK);
+      if (request.getMethod().equals("POST")) {
+        // First look for a request in the header, then look in the body.
+        // The latter allows very large requests without hitting HTTP 413.
+        String rawRequest = request.getHeader("request");
+        if (rawRequest == null) {
+          try (ServletInputStream inputStream = request.getInputStream()) {
+            rawRequest = AvaticaUtils.readFully(inputStream);
+          }
         }
+        final String jsonRequest =
+            new String(rawRequest.getBytes("ISO-8859-1"), "UTF-8");
+        LOG.trace("request: {}", jsonRequest);
+
+        final HandlerResponse<String> jsonResponse = jsonHandler.apply(jsonRequest);
+        LOG.trace("response: {}", jsonResponse);
+        baseRequest.setHandled(true);
+        // Set the status code and write out the response.
+        response.setStatus(jsonResponse.getStatusCode());
+        response.getWriter().println(jsonResponse.getResponse());
       }
-      final String jsonRequest =
-          new String(rawRequest.getBytes("ISO-8859-1"), "UTF-8");
-      LOG.trace("request: {}", jsonRequest);
-
-      final HandlerResponse<String> jsonResponse = jsonHandler.apply(jsonRequest);
-      LOG.trace("response: {}", jsonResponse);
-      baseRequest.setHandled(true);
-      // Set the status code and write out the response.
-      response.setStatus(jsonResponse.getStatusCode());
-      response.getWriter().println(jsonResponse.getResponse());
     }
   }
 
@@ -83,6 +104,10 @@ public class AvaticaJsonHandler extends AbstractHandler implements AvaticaHandle
     // Also add it to the handler to include with exceptions
     jsonHandler.setRpcMetadata(metadata);
   }
+
+  @Override public MetricsSystem getMetrics() {
+    return metrics;
+  }
 }
 
 // End AvaticaJsonHandler.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaProtobufHandler.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaProtobufHandler.java b/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaProtobufHandler.java
index e44de00..aeebad7 100644
--- a/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaProtobufHandler.java
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/server/AvaticaProtobufHandler.java
@@ -17,7 +17,12 @@
 package org.apache.calcite.avatica.server;
 
 import org.apache.calcite.avatica.AvaticaUtils;
+import org.apache.calcite.avatica.metrics.MetricsSystem;
+import org.apache.calcite.avatica.metrics.Timer;
+import org.apache.calcite.avatica.metrics.Timer.Context;
+import org.apache.calcite.avatica.metrics.noop.NoopMetricsSystem;
 import org.apache.calcite.avatica.remote.Handler.HandlerResponse;
+import org.apache.calcite.avatica.remote.MetricsHelper;
 import org.apache.calcite.avatica.remote.ProtobufHandler;
 import org.apache.calcite.avatica.remote.ProtobufTranslation;
 import org.apache.calcite.avatica.remote.ProtobufTranslationImpl;
@@ -41,35 +46,48 @@ import javax.servlet.http.HttpServletResponse;
 /**
  * Jetty handler that executes Avatica JSON request-responses.
  */
-public class AvaticaProtobufHandler extends AbstractHandler implements AvaticaHandler {
+public class AvaticaProtobufHandler extends AbstractHandler implements MetricsAwareAvaticaHandler {
   private static final Logger LOG = LoggerFactory.getLogger(AvaticaJsonHandler.class);
 
   private final Service service;
   private final ProtobufHandler pbHandler;
   private final ProtobufTranslation protobufTranslation;
+  private final MetricsSystem metrics;
+  private final Timer requestTimer;
 
   public AvaticaProtobufHandler(Service service) {
+    this(service, NoopMetricsSystem.getInstance());
+  }
+
+  public AvaticaProtobufHandler(Service service, MetricsSystem metrics) {
     this.protobufTranslation = new ProtobufTranslationImpl();
     this.service = Objects.requireNonNull(service);
-    this.pbHandler = new ProtobufHandler(service, protobufTranslation);
+    this.metrics = Objects.requireNonNull(metrics);
+    this.pbHandler = new ProtobufHandler(service, protobufTranslation, metrics);
+
+    this.requestTimer = this.metrics.getTimer(
+        MetricsHelper.concat(AvaticaProtobufHandler.class,
+            MetricsAwareAvaticaHandler.REQUEST_TIMER_NAME));
   }
 
   public void handle(String target, Request baseRequest,
       HttpServletRequest request, HttpServletResponse response)
       throws IOException, ServletException {
-    response.setContentType("application/octet-stream;charset=utf-8");
-    response.setStatus(HttpServletResponse.SC_OK);
-    if (request.getMethod().equals("POST")) {
-      byte[] requestBytes;
-      try (ServletInputStream inputStream = request.getInputStream()) {
-        requestBytes = AvaticaUtils.readFullyToBytes(inputStream);
-      }
+    try (final Context ctx = this.requestTimer.start()) {
+      response.setContentType("application/octet-stream;charset=utf-8");
+      response.setStatus(HttpServletResponse.SC_OK);
+      if (request.getMethod().equals("POST")) {
+        byte[] requestBytes;
+        try (ServletInputStream inputStream = request.getInputStream()) {
+          requestBytes = AvaticaUtils.readFullyToBytes(inputStream);
+        }
 
-      HandlerResponse<byte[]> handlerResponse = pbHandler.apply(requestBytes);
+        HandlerResponse<byte[]> handlerResponse = pbHandler.apply(requestBytes);
 
-      baseRequest.setHandled(true);
-      response.setStatus(handlerResponse.getStatusCode());
-      response.getOutputStream().write(handlerResponse.getResponse());
+        baseRequest.setHandled(true);
+        response.setStatus(handlerResponse.getStatusCode());
+        response.getOutputStream().write(handlerResponse.getResponse());
+      }
     }
   }
 
@@ -79,6 +97,11 @@ public class AvaticaProtobufHandler extends AbstractHandler implements AvaticaHa
     // Also add it to the handler to include with exceptions
     pbHandler.setRpcMetadata(metadata);
   }
+
+  @Override public MetricsSystem getMetrics() {
+    return this.metrics;
+  }
+
 }
 
 // End AvaticaProtobufHandler.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-server/src/main/java/org/apache/calcite/avatica/server/DelegatingAvaticaHandler.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/server/DelegatingAvaticaHandler.java b/avatica-server/src/main/java/org/apache/calcite/avatica/server/DelegatingAvaticaHandler.java
index 223fba7..a574985 100644
--- a/avatica-server/src/main/java/org/apache/calcite/avatica/server/DelegatingAvaticaHandler.java
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/server/DelegatingAvaticaHandler.java
@@ -37,6 +37,9 @@ import javax.servlet.http.HttpServletResponse;
  *
  * <p>This implementation provides a no-op implementation for
  * {@link #setServerRpcMetadata(org.apache.calcite.avatica.remote.Service.RpcMetadataResponse)}.
+ *
+ * Does not implement {@link MetricsAwareAvaticaHandler} as this implementation is only presented
+ * for backwards compatibility.
  */
 public class DelegatingAvaticaHandler implements AvaticaHandler {
   private static final Logger LOG = LoggerFactory.getLogger(DelegatingAvaticaHandler.class);

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-server/src/main/java/org/apache/calcite/avatica/server/HandlerFactory.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/server/HandlerFactory.java b/avatica-server/src/main/java/org/apache/calcite/avatica/server/HandlerFactory.java
index 724626d..b1fcb40 100644
--- a/avatica-server/src/main/java/org/apache/calcite/avatica/server/HandlerFactory.java
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/server/HandlerFactory.java
@@ -16,33 +16,100 @@
  */
 package org.apache.calcite.avatica.server;
 
+import org.apache.calcite.avatica.metrics.MetricsSystem;
+import org.apache.calcite.avatica.metrics.MetricsSystemConfiguration;
+import org.apache.calcite.avatica.metrics.MetricsSystemFactory;
+import org.apache.calcite.avatica.metrics.MetricsSystemLoader;
+import org.apache.calcite.avatica.metrics.noop.NoopMetricsSystem;
+import org.apache.calcite.avatica.metrics.noop.NoopMetricsSystemConfiguration;
 import org.apache.calcite.avatica.remote.Driver;
 import org.apache.calcite.avatica.remote.Service;
 
 import org.eclipse.jetty.server.Handler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.ServiceLoader;
 
 /**
  * Factory that instantiates the desired implementation, typically differing on the method
  * used to serialize messages, for use in the Avatica server.
  */
 public class HandlerFactory {
+  private static final Logger LOG = LoggerFactory.getLogger(HandlerFactory.class);
 
   /**
-   * The desired implementation for the given serialization method.
+   * Constructs the desired implementation for the given serialization method with metrics.
    *
-   * @param serialization The desired message serialization
+   * @param service The underlying {@link Service}.
+   * @param serialization The desired message serialization.
+   * @return The {@link Handler}.
    */
   public Handler getHandler(Service service, Driver.Serialization serialization) {
+    return getHandler(service, serialization, NoopMetricsSystemConfiguration.getInstance());
+  }
+
+  /**
+   * Constructs the desired implementation for the given serialization method with metrics.
+   *
+   * @param service The underlying {@link Service}.
+   * @param serialization The desired message serialization.
+   * @param metricsConfig Configuration for the {@link MetricsSystem}.
+   * @return The {@link Handler}.
+   */
+  public Handler getHandler(Service service, Driver.Serialization serialization,
+      MetricsSystemConfiguration<?> metricsConfig) {
+    MetricsSystem metrics = MetricsSystemLoader.load(Objects.requireNonNull(metricsConfig));
+
     switch (serialization) {
     case JSON:
-      return new AvaticaJsonHandler(service);
+      return new AvaticaJsonHandler(service, metrics);
     case PROTOBUF:
-      return new AvaticaProtobufHandler(service);
+      return new AvaticaProtobufHandler(service, metrics);
     default:
       throw new IllegalArgumentException("Unknown Avatica handler for " + serialization.name());
     }
   }
 
+  /**
+   * Load a {@link MetricsSystem} using ServiceLoader to create a {@link MetricsSystemFactory}.
+   *
+   * @param config State to pass to the factory for initialization.
+   * @return A {@link MetricsSystem} instance.
+   */
+  MetricsSystem loadMetricsSystem(MetricsSystemConfiguration<?> config) {
+    ServiceLoader<MetricsSystemFactory> loader = ServiceLoader.load(MetricsSystemFactory.class);
+    List<MetricsSystemFactory> availableFactories = new ArrayList<>();
+    for (MetricsSystemFactory factory : loader) {
+      availableFactories.add(factory);
+    }
+
+    if (1 == availableFactories.size()) {
+      // One and only one instance -- what we want
+      MetricsSystemFactory factory = availableFactories.get(0);
+      LOG.info("Loaded MetricsSystem {}", factory.getClass());
+      return factory.create(config);
+    } else if (availableFactories.isEmpty()) {
+      // None-provided default to no metrics
+      LOG.info("No metrics implementation available on classpath. Using No-op implementation");
+      return NoopMetricsSystem.getInstance();
+    } else {
+      // Tell the user they're doing something wrong, and choose the first impl.
+      StringBuilder sb = new StringBuilder();
+      for (MetricsSystemFactory factory : availableFactories) {
+        if (sb.length() > 0) {
+          sb.append(", ");
+        }
+        sb.append(factory.getClass());
+      }
+      LOG.warn("Found multiple MetricsSystemFactory implementations: {}."
+          + " Using No-op implementation", sb);
+      return NoopMetricsSystem.getInstance();
+    }
+  }
 }
 
 // End HandlerFactory.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-server/src/main/java/org/apache/calcite/avatica/server/MetricsAwareAvaticaHandler.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/server/MetricsAwareAvaticaHandler.java b/avatica-server/src/main/java/org/apache/calcite/avatica/server/MetricsAwareAvaticaHandler.java
new file mode 100644
index 0000000..0914dbd
--- /dev/null
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/server/MetricsAwareAvaticaHandler.java
@@ -0,0 +1,43 @@
+/*
+ * 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.calcite.avatica.server;
+
+import org.apache.calcite.avatica.metrics.MetricsSystem;
+
+/**
+ * An {@link AvaticaHandler} that is capable of collecting metrics.
+ */
+public interface MetricsAwareAvaticaHandler extends AvaticaHandler {
+
+  /**
+   * General prefix for all metrics in a handler.
+   */
+  String HANDLER_PREFIX = "Handler.";
+
+  /**
+   * Name for timing requests from users
+   */
+  String REQUEST_TIMER_NAME = HANDLER_PREFIX + "RequestTimings";
+
+  /**
+   * @return An instance of the {@link MetricsSystem} for this AvaticaHandler.
+   */
+  MetricsSystem getMetrics();
+
+}
+
+// End MetricsAwareAvaticaHandler.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica/pom.xml
----------------------------------------------------------------------
diff --git a/avatica/pom.xml b/avatica/pom.xml
index 7e229ea..cf7d875 100644
--- a/avatica/pom.xml
+++ b/avatica/pom.xml
@@ -25,7 +25,6 @@ limitations under the License.
 
   <artifactId>calcite-avatica</artifactId>
   <packaging>jar</packaging>
-  <version>1.7.0-SNAPSHOT</version>
   <name>Calcite Avatica</name>
   <description>JDBC driver framework.</description>
 
@@ -37,6 +36,10 @@ limitations under the License.
     <!-- Make sure that there are no dependencies on other calcite modules,
          or on libraries other than Jackson. -->
     <dependency>
+      <groupId>org.apache.calcite</groupId>
+      <artifactId>calcite-avatica-metrics</artifactId>
+    </dependency>
+    <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
       <artifactId>jackson-core</artifactId>
     </dependency>
@@ -79,6 +82,34 @@ limitations under the License.
   </dependencies>
 
   <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.eclipse.m2e</groupId>
+          <artifactId>lifecycle-mapping</artifactId>
+          <version>1.0.0</version>
+          <configuration>
+            <lifecycleMappingMetadata>
+              <pluginExecutions>
+                <pluginExecution>
+                  <pluginExecutionFilter>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-checkstyle-plugin</artifactId>
+                    <versionRange>[2.12.1,)</versionRange>
+                    <goals>
+                      <goal>check</goal>
+                    </goals>
+                  </pluginExecutionFilter>
+                  <action>
+                    <ignore />
+                  </action>
+                </pluginExecution>
+              </pluginExecutions>
+            </lifecycleMappingMetadata>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
     <plugins>
       <plugin>
         <artifactId>maven-dependency-plugin</artifactId>

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica/src/main/java/org/apache/calcite/avatica/remote/Handler.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/Handler.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/Handler.java
index e3ad07f..30d026c 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/Handler.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/Handler.java
@@ -28,6 +28,7 @@ import java.util.Objects;
 public interface Handler<T> {
   int HTTP_OK = 200;
   int HTTP_INTERNAL_SERVER_ERROR = 500;
+  String HANDLER_SERIALIZATION_METRICS_NAME = "Handler.Serialization";
 
   /**
    * Struct that encapsulates the context of the result of a request to Avatica.

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonHandler.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonHandler.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonHandler.java
index 5afc760..fd57078 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonHandler.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/JsonHandler.java
@@ -16,6 +16,9 @@
  */
 package org.apache.calcite.avatica.remote;
 
+import org.apache.calcite.avatica.metrics.MetricsSystem;
+import org.apache.calcite.avatica.metrics.Timer;
+import org.apache.calcite.avatica.metrics.Timer.Context;
 import org.apache.calcite.avatica.remote.Service.Request;
 import org.apache.calcite.avatica.remote.Service.Response;
 
@@ -35,8 +38,14 @@ public class JsonHandler extends AbstractHandler<String> {
 
   protected static final ObjectMapper MAPPER = JsonService.MAPPER;
 
-  public JsonHandler(Service service) {
+  final MetricsSystem metrics;
+  final Timer serializationTimer;
+
+  public JsonHandler(Service service, MetricsSystem metrics) {
     super(service);
+    this.metrics = metrics;
+    this.serializationTimer = this.metrics.getTimer(
+        MetricsHelper.concat(JsonHandler.class, HANDLER_SERIALIZATION_METRICS_NAME));
   }
 
   public HandlerResponse<String> apply(String jsonRequest) {
@@ -44,7 +53,9 @@ public class JsonHandler extends AbstractHandler<String> {
   }
 
   @Override Request decode(String request) throws IOException {
-    return MAPPER.readValue(request, Service.Request.class);
+    try (final Context ctx = serializationTimer.start()) {
+      return MAPPER.readValue(request, Service.Request.class);
+    }
   }
 
   /**
@@ -54,9 +65,11 @@ public class JsonHandler extends AbstractHandler<String> {
    * @return A JSON string.
    */
   @Override String encode(Response response) throws IOException {
-    final StringWriter w = new StringWriter();
-    MAPPER.writeValue(w, response);
-    return w.toString();
+    try (final Context ctx = serializationTimer.start()) {
+      final StringWriter w = new StringWriter();
+      MAPPER.writeValue(w, response);
+      return w.toString();
+    }
   }
 }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica/src/main/java/org/apache/calcite/avatica/remote/MetricsHelper.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/MetricsHelper.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/MetricsHelper.java
new file mode 100644
index 0000000..2561b29
--- /dev/null
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/MetricsHelper.java
@@ -0,0 +1,36 @@
+/*
+ * 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.calcite.avatica.remote;
+
+/**
+ * A utility class to encapsulate common logic in use of metrics implementation.
+ */
+public class MetricsHelper {
+
+  private static final String PERIOD = ".";
+
+  private MetricsHelper() {}
+
+  public static String concat(Class<?> clz, String name) {
+    StringBuilder sb = new StringBuilder();
+    sb.append(clz.getName());
+    return sb.append(PERIOD).append(name).toString();
+  }
+
+}
+
+// End MetricsHelper.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica/src/main/java/org/apache/calcite/avatica/remote/ProtobufHandler.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/ProtobufHandler.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/ProtobufHandler.java
index d77b52d..89e380e 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/remote/ProtobufHandler.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/remote/ProtobufHandler.java
@@ -16,6 +16,9 @@
  */
 package org.apache.calcite.avatica.remote;
 
+import org.apache.calcite.avatica.metrics.MetricsSystem;
+import org.apache.calcite.avatica.metrics.Timer;
+import org.apache.calcite.avatica.metrics.Timer.Context;
 import org.apache.calcite.avatica.remote.Service.Response;
 
 import java.io.IOException;
@@ -28,10 +31,15 @@ import java.io.IOException;
 public class ProtobufHandler extends AbstractHandler<byte[]> {
 
   private final ProtobufTranslation translation;
+  private final MetricsSystem metrics;
+  private final Timer serializationTimer;
 
-  public ProtobufHandler(Service service, ProtobufTranslation translation) {
+  public ProtobufHandler(Service service, ProtobufTranslation translation, MetricsSystem metrics) {
     super(service);
     this.translation = translation;
+    this.metrics = metrics;
+    this.serializationTimer = this.metrics.getTimer(
+        MetricsHelper.concat(ProtobufHandler.class, HANDLER_SERIALIZATION_METRICS_NAME));
   }
 
   @Override public HandlerResponse<byte[]> apply(byte[] requestBytes) {
@@ -39,11 +47,15 @@ public class ProtobufHandler extends AbstractHandler<byte[]> {
   }
 
   @Override Service.Request decode(byte[] serializedRequest) throws IOException {
-    return translation.parseRequest(serializedRequest);
+    try (final Context ctx = serializationTimer.start()) {
+      return translation.parseRequest(serializedRequest);
+    }
   }
 
   @Override byte[] encode(Response response) throws IOException {
-    return translation.serializeResponse(response);
+    try (final Context ctx = serializationTimer.start()) {
+      return translation.serializeResponse(response);
+    }
   }
 }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica/src/test/java/org/apache/calcite/avatica/metrics/MetricsHelperTest.java
----------------------------------------------------------------------
diff --git a/avatica/src/test/java/org/apache/calcite/avatica/metrics/MetricsHelperTest.java b/avatica/src/test/java/org/apache/calcite/avatica/metrics/MetricsHelperTest.java
new file mode 100644
index 0000000..c85312d
--- /dev/null
+++ b/avatica/src/test/java/org/apache/calcite/avatica/metrics/MetricsHelperTest.java
@@ -0,0 +1,42 @@
+/*
+ * 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.calcite.avatica.metrics;
+
+import org.apache.calcite.avatica.remote.MetricsHelper;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Test class for {@link MetricsHelper}.
+ */
+public class MetricsHelperTest {
+
+  @Test(expected = NullPointerException.class) public void testNullConcat() {
+    MetricsHelper.concat(null, "foo");
+  }
+
+  @Test public void testConcat() {
+    String suffix = "suffix";
+    String finalName = getClass().getName() + "." + suffix;
+    assertEquals(finalName, MetricsHelper.concat(getClass(), suffix));
+  }
+
+}
+
+// End MetricsHelperTest.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica/src/test/java/org/apache/calcite/avatica/remote/ProtobufHandlerTest.java
----------------------------------------------------------------------
diff --git a/avatica/src/test/java/org/apache/calcite/avatica/remote/ProtobufHandlerTest.java b/avatica/src/test/java/org/apache/calcite/avatica/remote/ProtobufHandlerTest.java
index a10c7dc..e7c442c 100644
--- a/avatica/src/test/java/org/apache/calcite/avatica/remote/ProtobufHandlerTest.java
+++ b/avatica/src/test/java/org/apache/calcite/avatica/remote/ProtobufHandlerTest.java
@@ -18,6 +18,7 @@ package org.apache.calcite.avatica.remote;
 
 import org.apache.calcite.avatica.Meta;
 import org.apache.calcite.avatica.Meta.Frame;
+import org.apache.calcite.avatica.metrics.noop.NoopMetricsSystem;
 import org.apache.calcite.avatica.proto.Common;
 import org.apache.calcite.avatica.proto.Common.ColumnValue;
 import org.apache.calcite.avatica.proto.Requests;
@@ -58,7 +59,7 @@ public class ProtobufHandlerTest {
     translation = Mockito.mock(ProtobufTranslation.class);
 
     // Real objects
-    handler = new ProtobufHandler(service, translation);
+    handler = new ProtobufHandler(service, translation, NoopMetricsSystem.getInstance());
   }
 
   @Test

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica/src/test/java/org/apache/calcite/avatica/test/JsonHandlerTest.java
----------------------------------------------------------------------
diff --git a/avatica/src/test/java/org/apache/calcite/avatica/test/JsonHandlerTest.java b/avatica/src/test/java/org/apache/calcite/avatica/test/JsonHandlerTest.java
index 4445126..57cf60a 100644
--- a/avatica/src/test/java/org/apache/calcite/avatica/test/JsonHandlerTest.java
+++ b/avatica/src/test/java/org/apache/calcite/avatica/test/JsonHandlerTest.java
@@ -20,6 +20,7 @@ import org.apache.calcite.avatica.AvaticaParameter;
 import org.apache.calcite.avatica.ColumnMetaData;
 import org.apache.calcite.avatica.Meta;
 import org.apache.calcite.avatica.Meta.CursorFactory;
+import org.apache.calcite.avatica.metrics.noop.NoopMetricsSystem;
 import org.apache.calcite.avatica.remote.JsonHandler;
 import org.apache.calcite.avatica.remote.JsonService;
 import org.apache.calcite.avatica.remote.LocalJsonService;
@@ -167,7 +168,7 @@ public class JsonHandlerTest {
     final List<TypedValue> expectedParameterValues = new ArrayList<>();
     final Service service = new ParameterValuesCheckingService(expectedParameterValues);
     final JsonService jsonService = new LocalJsonService(service);
-    final JsonHandler jsonHandler = new JsonHandler(jsonService);
+    final JsonHandler jsonHandler = new JsonHandler(jsonService, NoopMetricsSystem.getInstance());
 
     final List<TypedValue> parameterValues = Arrays.asList(
         TypedValue.create("NUMBER", new BigDecimal("123")),

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/dropwizard-metrics2/pom.xml
----------------------------------------------------------------------
diff --git a/dropwizard-metrics2/pom.xml b/dropwizard-metrics2/pom.xml
new file mode 100644
index 0000000..bcb7033
--- /dev/null
+++ b/dropwizard-metrics2/pom.xml
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.calcite</groupId>
+    <artifactId>calcite</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>calcite-dropwizard-hadoop-metrics2</artifactId>
+  <packaging>jar</packaging>
+  <name>Calcite Dropwizard Reporter for Hadoop Metrics2</name>
+  <description>A Dropwizard Metrics reporter which also acts as a Hadoop Metrics2 MetricsSource.</description>
+
+  <properties>
+    <top.dir>${project.basedir}/..</top.dir>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>io.dropwizard.metrics</groupId>
+      <artifactId>metrics-core</artifactId>
+      <version>${dropwizard-metrics3.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hadoop</groupId>
+      <artifactId>hadoop-common</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-log4j12</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.eclipse.m2e</groupId>
+          <artifactId>lifecycle-mapping</artifactId>
+          <version>1.0.0</version>
+          <configuration>
+            <lifecycleMappingMetadata>
+              <pluginExecutions>
+                <pluginExecution>
+                  <pluginExecutionFilter>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-checkstyle-plugin</artifactId>
+                    <versionRange>[2.12.1,)</versionRange>
+                    <goals>
+                      <goal>check</goal>
+                    </goals>
+                  </pluginExecutionFilter>
+                  <action>
+                    <ignore />
+                  </action>
+                </pluginExecution>
+              </pluginExecutions>
+            </lifecycleMappingMetadata>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+    <plugins>
+      <plugin>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>analyze</id>
+            <goals>
+              <goal>analyze-only</goal>
+            </goals>
+            <configuration>
+              <failOnWarning>true</failOnWarning>
+              <!-- ignore "unused but declared" warnings -->
+              <ignoredUnusedDeclaredDependencies>
+                <ignoredUnusedDeclaredDependency>org.slf4j:slf4j-log4j12</ignoredUnusedDeclaredDependency>
+              </ignoredUnusedDeclaredDependencies>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <!-- Parent module has the same plugin and does the work of
+           generating -sources.jar for each project. But without the
+           plugin declared here, IDEs don't know the sources are
+           available. -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-source-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>attach-sources</id>
+            <phase>verify</phase>
+            <goals>
+              <goal>jar-no-fork</goal>
+              <goal>test-jar-no-fork</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <artifactId>maven-remote-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>non-root-resources</id>
+            <goals>
+              <goal>process</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/dropwizard-metrics2/src/main/java/org/apache/calcite/dropwizard/metrics/hadoop/HadoopMetrics2Reporter.java
----------------------------------------------------------------------
diff --git a/dropwizard-metrics2/src/main/java/org/apache/calcite/dropwizard/metrics/hadoop/HadoopMetrics2Reporter.java b/dropwizard-metrics2/src/main/java/org/apache/calcite/dropwizard/metrics/hadoop/HadoopMetrics2Reporter.java
new file mode 100644
index 0000000..89a49eb
--- /dev/null
+++ b/dropwizard-metrics2/src/main/java/org/apache/calcite/dropwizard/metrics/hadoop/HadoopMetrics2Reporter.java
@@ -0,0 +1,451 @@
+/*
+ * 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.calcite.dropwizard.metrics.hadoop;
+
+import org.apache.hadoop.metrics2.MetricsCollector;
+import org.apache.hadoop.metrics2.MetricsInfo;
+import org.apache.hadoop.metrics2.MetricsRecordBuilder;
+import org.apache.hadoop.metrics2.MetricsSource;
+import org.apache.hadoop.metrics2.MetricsSystem;
+import org.apache.hadoop.metrics2.lib.Interns;
+import org.apache.hadoop.metrics2.lib.MetricsRegistry;
+
+import com.codahale.metrics.Counter;
+import com.codahale.metrics.Gauge;
+import com.codahale.metrics.Histogram;
+import com.codahale.metrics.Meter;
+import com.codahale.metrics.MetricFilter;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.ScheduledReporter;
+import com.codahale.metrics.Snapshot;
+import com.codahale.metrics.Timer;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Iterator;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.SortedMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Dropwizard-Metrics {@link com.codahale.metrics.Reporter} which also acts as a Hadoop Metrics2
+ * {@link MetricsSource}. Configure it like other Reporters.
+ *
+ * <pre>
+ * final HadoopMetrics2Reporter metrics2Reporter = HadoopMetrics2Reporter.forRegistry(metrics)
+ *     .build(DefaultMetricsSystem.initialize("Phoenix"), // The application-level name
+ *            "QueryServer", // Component name
+ *            "Phoenix Query Server", // Component description
+ *            "General"); // Name for each metric record
+ * metrics2Reporter.start(30, TimeUnit.SECONDS);
+ * </pre>
+ */
+public class HadoopMetrics2Reporter extends ScheduledReporter implements MetricsSource {
+  private static final Logger LOG = LoggerFactory.getLogger(HadoopMetrics2Reporter.class);
+  private static final String EMPTY_STRING = "";
+
+  public static final MetricsInfo RATE_UNIT_LABEL =
+      Interns.info("rate_unit", "The unit of measure for rate metrics");
+  public static final MetricsInfo DURATION_UNIT_LABEL =
+      Interns.info("duration_unit", "The unit of measure of duration metrics");
+
+  /**
+   * Returns a new {@link Builder} for {@link HadoopMetrics2Reporter}.
+   *
+   * @param registry the registry to report
+   * @return a {@link Builder} instance for a {@link HadoopMetrics2Reporter}
+   */
+  public static Builder forRegistry(MetricRegistry registry) {
+    return new Builder(registry);
+  }
+
+  /**
+   * A builder to create {@link HadoopMetrics2Reporter} instances.
+   */
+  public static class Builder {
+    private final MetricRegistry registry;
+    private MetricFilter filter;
+    private TimeUnit rateUnit;
+    private TimeUnit durationUnit;
+    private String recordContext;
+
+    private Builder(MetricRegistry registry) {
+      this.registry = registry;
+      this.filter = MetricFilter.ALL;
+      this.rateUnit = TimeUnit.SECONDS;
+      this.durationUnit = TimeUnit.MILLISECONDS;
+    }
+
+    /**
+     * Convert rates to the given time unit. Defaults to {@link TimeUnit#SECONDS}.
+     *
+     * @param rateUnit a unit of time
+     * @return {@code this}
+     */
+    public Builder convertRatesTo(TimeUnit rateUnit) {
+      this.rateUnit = Objects.requireNonNull(rateUnit);
+      return this;
+    }
+
+    /**
+     * Convert durations to the given time unit. Defaults to {@link TimeUnit#MILLISECONDS}.
+     *
+     * @param durationUnit a unit of time
+     * @return {@code this}
+     */
+    public Builder convertDurationsTo(TimeUnit durationUnit) {
+      this.durationUnit = Objects.requireNonNull(durationUnit);
+      return this;
+    }
+
+    /**
+     * Only report metrics which match the given filter. Defaults to {@link MetricFilter#ALL}.
+     *
+     * @param filter a {@link MetricFilter}
+     * @return {@code this}
+     */
+    public Builder filter(MetricFilter filter) {
+      this.filter = Objects.requireNonNull(filter);
+      return this;
+    }
+
+    /**
+     * A "context" name that will be added as a tag on each emitted metric record. Defaults to
+     * no "context" attribute on each record.
+     *
+     * @param recordContext The "context" tag
+     * @return {@code this}
+     */
+    public Builder recordContext(String recordContext) {
+      this.recordContext = Objects.requireNonNull(recordContext);
+      return this;
+    }
+
+    /**
+     * Builds a {@link HadoopMetrics2Reporter} with the given properties, making metrics available
+     * to the Hadoop Metrics2 framework (any configured {@link MetricsSource}s.
+     *
+     * @param metrics2System The Hadoop Metrics2 system instance.
+     * @param jmxContext The JMX "path", e.g. {@code "MyServer,sub=Requests"}.
+     * @param description A description these metrics.
+     * @param recordName A suffix included on each record to identify it.
+     *
+     * @return a {@link HadoopMetrics2Reporter}
+     */
+    public HadoopMetrics2Reporter build(MetricsSystem metrics2System, String jmxContext,
+        String description, String recordName) {
+      return new HadoopMetrics2Reporter(registry,
+          rateUnit,
+          durationUnit,
+          filter,
+          metrics2System,
+          Objects.requireNonNull(jmxContext),
+          description,
+          recordName,
+          recordContext);
+    }
+  }
+
+  private final MetricsRegistry metrics2Registry;
+  private final MetricsSystem metrics2System;
+  private final String recordName;
+  private final String context;
+
+  @SuppressWarnings("rawtypes")
+  private final ConcurrentLinkedQueue<Entry<String, Gauge>> dropwizardGauges;
+  private final ConcurrentLinkedQueue<Entry<String, Counter>> dropwizardCounters;
+  private final ConcurrentLinkedQueue<Entry<String, Histogram>> dropwizardHistograms;
+  private final ConcurrentLinkedQueue<Entry<String, Meter>> dropwizardMeters;
+  private final ConcurrentLinkedQueue<Entry<String, Timer>> dropwizardTimers;
+
+  private HadoopMetrics2Reporter(MetricRegistry registry, TimeUnit rateUnit, TimeUnit durationUnit,
+      MetricFilter filter, MetricsSystem metrics2System, String jmxContext, String description,
+      String recordName, String context) {
+    super(registry, "hadoop-metrics2-reporter", filter, rateUnit, durationUnit);
+    this.metrics2Registry = new MetricsRegistry(Interns.info(jmxContext, description));
+    this.metrics2System = metrics2System;
+    this.recordName = recordName;
+    this.context = context;
+
+    this.dropwizardGauges = new ConcurrentLinkedQueue<>();
+    this.dropwizardCounters = new ConcurrentLinkedQueue<>();
+    this.dropwizardHistograms = new ConcurrentLinkedQueue<>();
+    this.dropwizardMeters = new ConcurrentLinkedQueue<>();
+    this.dropwizardTimers = new ConcurrentLinkedQueue<>();
+
+    // Register this source with the Metrics2 system.
+    // Make sure this is the last thing done as getMetrics() can be called at any time after.
+    this.metrics2System.register(Objects.requireNonNull(jmxContext),
+        Objects.requireNonNull(description), this);
+  }
+
+  @Override public void getMetrics(MetricsCollector collector, boolean all) {
+    MetricsRecordBuilder builder = collector.addRecord(recordName);
+    if (null != context) {
+      builder.setContext(context);
+    }
+
+    snapshotAllMetrics(builder);
+
+    metrics2Registry.snapshot(builder, all);
+  }
+
+  /**
+   * Consumes the current metrics collected by dropwizard and adds them to the {@code builder}.
+   *
+   * @param builder A record builder
+   */
+  void snapshotAllMetrics(MetricsRecordBuilder builder) {
+    // Pass through the gauges
+    @SuppressWarnings("rawtypes")
+    Iterator<Entry<String, Gauge>> gaugeIterator = dropwizardGauges.iterator();
+    while (gaugeIterator.hasNext()) {
+      @SuppressWarnings("rawtypes")
+      Entry<String, Gauge> gauge = gaugeIterator.next();
+      final MetricsInfo info = Interns.info(gauge.getKey(), EMPTY_STRING);
+      final Object o = gauge.getValue().getValue();
+
+      // Figure out which gauge types metrics2 supports and call the right method
+      if (o instanceof Integer) {
+        builder.addGauge(info, (int) o);
+      } else if (o instanceof Long) {
+        builder.addGauge(info, (long) o);
+      } else if (o instanceof Float) {
+        builder.addGauge(info, (float) o);
+      } else if (o instanceof Double) {
+        builder.addGauge(info, (double) o);
+      } else {
+        LOG.info("Ignoring Gauge ({}) with unhandled type: {}", gauge.getKey(), o.getClass());
+      }
+
+      gaugeIterator.remove();
+    }
+
+    // Pass through the counters
+    Iterator<Entry<String, Counter>> counterIterator = dropwizardCounters.iterator();
+    while (counterIterator.hasNext()) {
+      Entry<String, Counter> counter = counterIterator.next();
+      MetricsInfo info = Interns.info(counter.getKey(), EMPTY_STRING);
+      LOG.info("Adding counter {} {}", info, counter.getValue().getCount());
+      builder.addCounter(info, counter.getValue().getCount());
+      counterIterator.remove();
+    }
+
+    // Pass through the histograms
+    Iterator<Entry<String, Histogram>> histogramIterator = dropwizardHistograms.iterator();
+    while (histogramIterator.hasNext()) {
+      final Entry<String, Histogram> entry = histogramIterator.next();
+      final String name = entry.getKey();
+      final Histogram histogram = entry.getValue();
+
+      addSnapshot(builder, name, EMPTY_STRING, histogram.getSnapshot(), histogram.getCount());
+
+      histogramIterator.remove();
+    }
+
+    // Pass through the meter values
+    Iterator<Entry<String, Meter>> meterIterator = dropwizardMeters.iterator();
+    while (meterIterator.hasNext()) {
+      final Entry<String, Meter> meterEntry = meterIterator.next();
+      final String name = meterEntry.getKey();
+      final Meter meter = meterEntry.getValue();
+
+      addMeter(builder, name, EMPTY_STRING, meter.getCount(), meter.getMeanRate(),
+          meter.getOneMinuteRate(), meter.getFiveMinuteRate(), meter.getFifteenMinuteRate());
+
+      meterIterator.remove();
+    }
+
+    // Pass through the timers (meter + histogram)
+    Iterator<Entry<String, Timer>> timerIterator = dropwizardTimers.iterator();
+    while (timerIterator.hasNext()) {
+      final Entry<String, Timer> timerEntry = timerIterator.next();
+      final String name = timerEntry.getKey();
+      final Timer timer = timerEntry.getValue();
+      final Snapshot snapshot = timer.getSnapshot();
+
+      // Add the meter info (mean rate and rate over time windows)
+      addMeter(builder, name, EMPTY_STRING, timer.getCount(), timer.getMeanRate(),
+          timer.getOneMinuteRate(), timer.getFiveMinuteRate(), timer.getFifteenMinuteRate());
+
+      // Count was already added via the meter
+      addSnapshot(builder, name, EMPTY_STRING, snapshot);
+
+      timerIterator.remove();
+    }
+
+    // Add in metadata about what the units the reported metrics are displayed using.
+    builder.tag(RATE_UNIT_LABEL, getRateUnit());
+    builder.tag(DURATION_UNIT_LABEL, getDurationUnit());
+  }
+
+  /**
+   * Add Dropwizard-Metrics rate information to a Hadoop-Metrics2 record builder, converting the
+   * rates to the appropriate unit.
+   *
+   * @param builder A Hadoop-Metrics2 record builder.
+   * @param name A base name for this record.
+   * @param desc A description for the record.
+   * @param count The number of measured events.
+   * @param meanRate The average measured rate.
+   * @param oneMinuteRate The measured rate over the past minute.
+   * @param fiveMinuteRate The measured rate over the past five minutes
+   * @param fifteenMinuteRate The measured rate over the past fifteen minutes.
+   */
+  private void addMeter(MetricsRecordBuilder builder, String name, String desc, long count,
+      double meanRate, double oneMinuteRate, double fiveMinuteRate, double fifteenMinuteRate) {
+    builder.addGauge(Interns.info(name + "_count", EMPTY_STRING), count);
+    builder.addGauge(Interns.info(name + "_mean_rate", EMPTY_STRING), convertRate(meanRate));
+    builder.addGauge(Interns.info(name + "_1min_rate", EMPTY_STRING), convertRate(oneMinuteRate));
+    builder.addGauge(Interns.info(name + "_5min_rate", EMPTY_STRING), convertRate(fiveMinuteRate));
+    builder.addGauge(Interns.info(name + "_15min_rate", EMPTY_STRING),
+        convertRate(fifteenMinuteRate));
+  }
+
+  /**
+   * Add Dropwizard-Metrics value-distribution data to a Hadoop-Metrics2 record building, converting
+   * the durations to the appropriate unit.
+   *
+   * @param builder A Hadoop-Metrics2 record builder.
+   * @param name A base name for this record.
+   * @param desc A description for this record.
+   * @param snapshot The distribution of measured values.
+   * @param count The number of values which were measured.
+   */
+  private void addSnapshot(MetricsRecordBuilder builder, String name, String desc,
+      Snapshot snapshot, long count) {
+    builder.addGauge(Interns.info(name + "_count", desc), count);
+    addSnapshot(builder, name, desc, snapshot);
+  }
+
+  /**
+   * Add Dropwizard-Metrics value-distribution data to a Hadoop-Metrics2 record building, converting
+   * the durations to the appropriate unit.
+   *
+   * @param builder A Hadoop-Metrics2 record builder.
+   * @param name A base name for this record.
+   * @param desc A description for this record.
+   * @param snapshot The distribution of measured values.
+   */
+  private void addSnapshot(MetricsRecordBuilder builder, String name, String desc,
+      Snapshot snapshot) {
+    builder.addGauge(Interns.info(name + "_mean", desc), convertDuration(snapshot.getMean()));
+    builder.addGauge(Interns.info(name + "_min", desc), convertDuration(snapshot.getMin()));
+    builder.addGauge(Interns.info(name + "_max", desc), convertDuration(snapshot.getMax()));
+    builder.addGauge(Interns.info(name + "_median", desc), convertDuration(snapshot.getMedian()));
+    builder.addGauge(Interns.info(name + "_stddev", desc), convertDuration(snapshot.getStdDev()));
+
+    builder.addGauge(Interns.info(name + "_75thpercentile", desc),
+        convertDuration(snapshot.get75thPercentile()));
+    builder.addGauge(Interns.info(name + "_95thpercentile", desc),
+        convertDuration(snapshot.get95thPercentile()));
+    builder.addGauge(Interns.info(name + "_98thpercentile", desc),
+        convertDuration(snapshot.get98thPercentile()));
+    builder.addGauge(Interns.info(name + "_99thpercentile", desc),
+        convertDuration(snapshot.get99thPercentile()));
+    builder.addGauge(Interns.info(name + "_999thpercentile", desc),
+        convertDuration(snapshot.get999thPercentile()));
+  }
+
+  @SuppressWarnings("rawtypes")
+  @Override public void report(SortedMap<String, Gauge> gauges, SortedMap<String, Counter> counters,
+      SortedMap<String, Histogram> histograms, SortedMap<String, Meter> meters,
+      SortedMap<String, Timer> timers) {
+    for (Entry<String, Gauge> gauge : gauges.entrySet()) {
+      dropwizardGauges.add(gauge);
+    }
+
+    for (Entry<String, Counter> counter : counters.entrySet()) {
+      dropwizardCounters.add(counter);
+    }
+
+    for (Entry<String, Histogram> histogram : histograms.entrySet()) {
+      dropwizardHistograms.add(histogram);
+    }
+
+    for (Entry<String, Meter> meter : meters.entrySet()) {
+      dropwizardMeters.add(meter);
+    }
+
+    for (Entry<String, Timer> timer : timers.entrySet()) {
+      dropwizardTimers.add(timer);
+    }
+  }
+
+  @Override protected String getRateUnit() {
+    // Make it "events per rate_unit" to be accurate.
+    return "events/" + super.getRateUnit();
+  }
+
+  @Override protected String getDurationUnit() {
+    // Make it visible to the tests
+    return super.getDurationUnit();
+  }
+
+  @Override protected double convertDuration(double duration) {
+    // Make it visible to the tests
+    return super.convertDuration(duration);
+  }
+
+  @Override protected double convertRate(double rate) {
+    // Make it visible to the tests
+    return super.convertRate(rate);
+  }
+
+  // Getters visible for testing
+
+  MetricsRegistry getMetrics2Registry() {
+    return metrics2Registry;
+  }
+
+  MetricsSystem getMetrics2System() {
+    return metrics2System;
+  }
+
+  String getRecordName() {
+    return recordName;
+  }
+
+  String getContext() {
+    return context;
+  }
+
+  @SuppressWarnings("rawtypes") ConcurrentLinkedQueue<Entry<String, Gauge>> getDropwizardGauges() {
+    return dropwizardGauges;
+  }
+
+  ConcurrentLinkedQueue<Entry<String, Counter>> getDropwizardCounters() {
+    return dropwizardCounters;
+  }
+
+  ConcurrentLinkedQueue<Entry<String, Histogram>> getDropwizardHistograms() {
+    return dropwizardHistograms;
+  }
+
+  ConcurrentLinkedQueue<Entry<String, Meter>> getDropwizardMeters() {
+    return dropwizardMeters;
+  }
+
+  ConcurrentLinkedQueue<Entry<String, Timer>> getDropwizardTimers() {
+    return dropwizardTimers;
+  }
+}
+
+// End HadoopMetrics2Reporter.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/dropwizard-metrics2/src/main/java/org/apache/calcite/dropwizard/metrics/hadoop/PackageMarker.java
----------------------------------------------------------------------
diff --git a/dropwizard-metrics2/src/main/java/org/apache/calcite/dropwizard/metrics/hadoop/PackageMarker.java b/dropwizard-metrics2/src/main/java/org/apache/calcite/dropwizard/metrics/hadoop/PackageMarker.java
new file mode 100644
index 0000000..40a9b4f
--- /dev/null
+++ b/dropwizard-metrics2/src/main/java/org/apache/calcite/dropwizard/metrics/hadoop/PackageMarker.java
@@ -0,0 +1,37 @@
+/*
+ * 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.calcite.dropwizard.metrics.hadoop;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This is a dummy annotation that forces javac to produce output for
+ * otherwise empty package-info.java.
+ *
+ * <p>The result is maven-compiler-plugin can properly identify the scope of
+ * changed files
+ *
+ * <p>See more details in
+ * <a href="https://jira.codehaus.org/browse/MCOMPILER-205">
+ *   maven-compiler-plugin: incremental compilation broken</a>
+ */
+@Retention(RetentionPolicy.SOURCE)
+public @interface PackageMarker {
+}
+
+// End PackageMarker.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/dropwizard-metrics2/src/main/java/org/apache/calcite/dropwizard/metrics/hadoop/package-info.java
----------------------------------------------------------------------
diff --git a/dropwizard-metrics2/src/main/java/org/apache/calcite/dropwizard/metrics/hadoop/package-info.java b/dropwizard-metrics2/src/main/java/org/apache/calcite/dropwizard/metrics/hadoop/package-info.java
new file mode 100644
index 0000000..a842ff9
--- /dev/null
+++ b/dropwizard-metrics2/src/main/java/org/apache/calcite/dropwizard/metrics/hadoop/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+/**
+ * Hadoop Metrics2 MetricsSource for Dropwizard-Metrics.
+ */
+@PackageMarker
+package org.apache.calcite.dropwizard.metrics.hadoop;
+
+// End package-info.java


[3/3] calcite git commit: [CALCITE-642] Add an avatica-metrics API

Posted by el...@apache.org.
[CALCITE-642] Add an avatica-metrics API

Avatica-metrics is a simple API, based on what
is provided by dropwizard-metrics, and a no-op
implementation of that API. One implementation
of this API is provided using dropwizard-metrics
3.1.2. ServiceLoader is used to dynamically load
one, and only one, implementation of the metrics API.

This provides some basic instrumentation inside of Avatica
to expose interesting metrics, limited only to the server
process (although the client does have the dependency
available). No explicit metrics "sinks" are configured,
where the metrics go is an exercise for the user.

Metrics instrumentation presently includes:

* Coarse Jetty request timings
* Serialization (JSON/Protobuf) timings
* Connection and Statement cache gauges

This also includes a new module, calcite-dropwizard-hadoop-metrics2,
which acts as a bridge between dropwizard-metrics and Hadoop Metrics2.
This has no bearing on Avatica or Calcite on its own, but is a useful
tool to integrate metrics exposed by Avatica/Calcite into other metrics
stores which Dropwizard-metrics doesn't natively support (namely, Ambari).

Closes apache/calcite#189


Project: http://git-wip-us.apache.org/repos/asf/calcite/repo
Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/7e5710fc
Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/7e5710fc
Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/7e5710fc

Branch: refs/heads/master
Commit: 7e5710fc7459728a667659ea2b66895812ef839f
Parents: 7ce2e62
Author: Josh Elser <el...@apache.org>
Authored: Thu Jan 21 19:13:48 2016 -0500
Committer: Josh Elser <el...@apache.org>
Committed: Thu Feb 4 13:33:08 2016 -0500

----------------------------------------------------------------------
 avatica-metrics-dropwizardmetrics3/pom.xml      | 119 +++++
 .../metrics/dropwizard3/DropwizardCounter.java  |  51 +++
 .../metrics/dropwizard3/DropwizardGauge.java    |  39 ++
 .../dropwizard3/DropwizardHistogram.java        |  43 ++
 .../metrics/dropwizard3/DropwizardMeter.java    |  43 ++
 .../dropwizard3/DropwizardMetricsSystem.java    |  62 +++
 .../DropwizardMetricsSystemConfiguration.java   |  42 ++
 .../DropwizardMetricsSystemFactory.java         |  42 ++
 .../metrics/dropwizard3/DropwizardTimer.java    |  54 +++
 .../metrics/dropwizard3/package-info.java       |  26 ++
 ...calcite.avatica.metrics.MetricsSystemFactory |   2 +
 .../dropwizard3/DropwizardCounterTest.java      |  61 +++
 .../dropwizard3/DropwizardGaugeTest.java        |  60 +++
 .../dropwizard3/DropwizardHistogramTest.java    |  49 ++
 .../dropwizard3/DropwizardMeterTest.java        |  50 ++
 .../DropwizardMetricsSystemFactoryTest.java     |  54 +++
 .../DropwizardMetricsSystemTest.java            | 161 +++++++
 .../dropwizard3/DropwizardTimerTest.java        |  56 +++
 avatica-metrics/pom.xml                         | 138 ++++++
 .../apache/calcite/avatica/metrics/Counter.java |  49 ++
 .../apache/calcite/avatica/metrics/Gauge.java   |  30 ++
 .../calcite/avatica/metrics/Histogram.java      |  40 ++
 .../apache/calcite/avatica/metrics/Meter.java   |  38 ++
 .../apache/calcite/avatica/metrics/Metric.java  |  26 ++
 .../calcite/avatica/metrics/MetricsSystem.java  |  68 +++
 .../metrics/MetricsSystemConfiguration.java     |  33 ++
 .../avatica/metrics/MetricsSystemFactory.java   |  32 ++
 .../avatica/metrics/MetricsSystemLoader.java    |  87 ++++
 .../calcite/avatica/metrics/PackageMarker.java  |  37 ++
 .../apache/calcite/avatica/metrics/Timer.java   |  37 ++
 .../avatica/metrics/noop/NoopCounter.java       |  36 ++
 .../avatica/metrics/noop/NoopHistogram.java     |  32 ++
 .../calcite/avatica/metrics/noop/NoopMeter.java |  32 ++
 .../avatica/metrics/noop/NoopMetricsSystem.java |  69 +++
 .../noop/NoopMetricsSystemConfiguration.java    |  40 ++
 .../metrics/noop/NoopMetricsSystemFactory.java  |  35 ++
 .../calcite/avatica/metrics/noop/NoopTimer.java |  41 ++
 .../avatica/metrics/noop/package-info.java      |  26 ++
 .../calcite/avatica/metrics/package-info.java   |  24 +
 .../metrics/MetricsSystemLoaderTest.java        | 114 +++++
 .../noop/NoopMetricsSystemFactoryTest.java      |  37 ++
 .../metrics/noop/NoopMetricsSystemTest.java     |  71 +++
 .../src/test/resources/log4j.properties         |  24 +
 avatica-server/pom.xml                          |  30 +-
 .../apache/calcite/avatica/jdbc/JdbcMeta.java   |  28 +-
 .../avatica/server/AvaticaJsonHandler.java      |  67 ++-
 .../avatica/server/AvaticaProtobufHandler.java  |  49 +-
 .../server/DelegatingAvaticaHandler.java        |   3 +
 .../calcite/avatica/server/HandlerFactory.java  |  75 ++-
 .../server/MetricsAwareAvaticaHandler.java      |  43 ++
 avatica/pom.xml                                 |  33 +-
 .../apache/calcite/avatica/remote/Handler.java  |   1 +
 .../calcite/avatica/remote/JsonHandler.java     |  23 +-
 .../calcite/avatica/remote/MetricsHelper.java   |  36 ++
 .../calcite/avatica/remote/ProtobufHandler.java |  18 +-
 .../avatica/metrics/MetricsHelperTest.java      |  42 ++
 .../avatica/remote/ProtobufHandlerTest.java     |   3 +-
 .../calcite/avatica/test/JsonHandlerTest.java   |   3 +-
 dropwizard-metrics2/pom.xml                     | 145 ++++++
 .../metrics/hadoop/HadoopMetrics2Reporter.java  | 451 +++++++++++++++++++
 .../metrics/hadoop/PackageMarker.java           |  37 ++
 .../dropwizard/metrics/hadoop/package-info.java |  24 +
 .../hadoop/HadoopMetrics2ReporterTest.java      | 334 ++++++++++++++
 pom.xml                                         |  27 +-
 64 files changed, 3625 insertions(+), 57 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics-dropwizardmetrics3/pom.xml
----------------------------------------------------------------------
diff --git a/avatica-metrics-dropwizardmetrics3/pom.xml b/avatica-metrics-dropwizardmetrics3/pom.xml
new file mode 100644
index 0000000..f0e6fc1
--- /dev/null
+++ b/avatica-metrics-dropwizardmetrics3/pom.xml
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.calcite</groupId>
+    <artifactId>calcite</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>calcite-avatica-metrics-dropwizardmetrics3</artifactId>
+  <packaging>jar</packaging>
+  <name>Calcite Avatica Dropwizard Metrics 3</name>
+  <description>An implementation of Avatica Metrics using Dropwizard Metrics.</description>
+
+  <properties>
+    <top.dir>${project.basedir}/..</top.dir>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.calcite</groupId>
+      <artifactId>calcite-avatica-metrics</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.dropwizard.metrics</groupId>
+      <artifactId>metrics-core</artifactId>
+      <!-- Avoid specifying version in dependencyManagement in support of other avatica-metrics impls -->
+      <version>${dropwizard-metrics3.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.eclipse.m2e</groupId>
+          <artifactId>lifecycle-mapping</artifactId>
+          <version>1.0.0</version>
+          <configuration>
+            <lifecycleMappingMetadata>
+              <pluginExecutions>
+                <pluginExecution>
+                  <pluginExecutionFilter>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-checkstyle-plugin</artifactId>
+                    <versionRange>[2.12.1,)</versionRange>
+                    <goals>
+                      <goal>check</goal>
+                    </goals>
+                  </pluginExecutionFilter>
+                  <action>
+                    <ignore />
+                  </action>
+                </pluginExecution>
+              </pluginExecutions>
+            </lifecycleMappingMetadata>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+    <plugins>
+      <!-- Parent module has the same plugin and does the work of
+           generating -sources.jar for each project. But without the
+           plugin declared here, IDEs don't know the sources are
+           available. -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-source-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>attach-sources</id>
+            <phase>verify</phase>
+            <goals>
+              <goal>jar-no-fork</goal>
+              <goal>test-jar-no-fork</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <artifactId>maven-remote-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>non-root-resources</id>
+            <goals>
+              <goal>process</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardCounter.java
----------------------------------------------------------------------
diff --git a/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardCounter.java b/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardCounter.java
new file mode 100644
index 0000000..4204ebf
--- /dev/null
+++ b/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardCounter.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.calcite.avatica.metrics.dropwizard3;
+
+import com.codahale.metrics.Counter;
+
+import java.util.Objects;
+
+/**
+ * Dropwizard Metrics implementation of {@link org.apache.calcite.avatica.metrics.Counter}.
+ */
+public class DropwizardCounter implements org.apache.calcite.avatica.metrics.Counter {
+
+  private final Counter counter;
+
+  public DropwizardCounter(Counter counter) {
+    this.counter = Objects.requireNonNull(counter);
+  }
+
+  @Override public void increment() {
+    this.counter.inc();
+  }
+
+  @Override public void increment(long n) {
+    this.counter.inc(n);
+  }
+
+  @Override public void decrement() {
+    this.counter.dec();
+  }
+
+  @Override public void decrement(long n) {
+    this.counter.dec(n);
+  }
+}
+
+// End DropwizardCounter.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardGauge.java
----------------------------------------------------------------------
diff --git a/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardGauge.java b/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardGauge.java
new file mode 100644
index 0000000..5f4b776
--- /dev/null
+++ b/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardGauge.java
@@ -0,0 +1,39 @@
+/*
+ * 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.calcite.avatica.metrics.dropwizard3;
+
+import com.codahale.metrics.Gauge;
+
+/**
+ * Dropwizard Metrics implementation of {@link org.apache.calcite.avatica.metrics.Gauge}.
+ *
+ * @param <T> The value the gauge returns.
+ */
+public class DropwizardGauge<T> implements Gauge<T> {
+
+  private final org.apache.calcite.avatica.metrics.Gauge<T> gauge;
+
+  public DropwizardGauge(org.apache.calcite.avatica.metrics.Gauge<T> gauge) {
+    this.gauge = gauge;
+  }
+
+  @Override public T getValue() {
+    return gauge.getValue();
+  }
+}
+
+// End DropwizardGauge.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardHistogram.java
----------------------------------------------------------------------
diff --git a/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardHistogram.java b/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardHistogram.java
new file mode 100644
index 0000000..266f130
--- /dev/null
+++ b/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardHistogram.java
@@ -0,0 +1,43 @@
+/*
+ * 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.calcite.avatica.metrics.dropwizard3;
+
+import com.codahale.metrics.Histogram;
+
+import java.util.Objects;
+
+/**
+ * Dropwizard metrics implementation of {@link org.apache.calcite.avatica.metrics.Histogram}.
+ */
+public class DropwizardHistogram implements org.apache.calcite.avatica.metrics.Histogram {
+
+  private final Histogram histogram;
+
+  public DropwizardHistogram(Histogram histogram) {
+    this.histogram = Objects.requireNonNull(histogram);
+  }
+
+  @Override public void update(int value) {
+    histogram.update(value);
+  }
+
+  @Override public void update(long value) {
+    histogram.update(value);
+  }
+}
+
+// End DropwizardHistogram.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMeter.java
----------------------------------------------------------------------
diff --git a/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMeter.java b/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMeter.java
new file mode 100644
index 0000000..ab8fafc
--- /dev/null
+++ b/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMeter.java
@@ -0,0 +1,43 @@
+/*
+ * 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.calcite.avatica.metrics.dropwizard3;
+
+import com.codahale.metrics.Meter;
+
+import java.util.Objects;
+
+/**
+ * Dropwizard metrics implementation of {@link org.apache.calcite.avatica.metrics.Meter}.
+ */
+public class DropwizardMeter implements org.apache.calcite.avatica.metrics.Meter {
+
+  private final Meter meter;
+
+  public DropwizardMeter(Meter meter) {
+    this.meter = Objects.requireNonNull(meter);
+  }
+
+  @Override public void mark() {
+    this.meter.mark();
+  }
+
+  @Override public void mark(long count) {
+    this.meter.mark(count);
+  }
+}
+
+// End DropwizardMeter.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMetricsSystem.java
----------------------------------------------------------------------
diff --git a/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMetricsSystem.java b/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMetricsSystem.java
new file mode 100644
index 0000000..6aa71b9
--- /dev/null
+++ b/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMetricsSystem.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.calcite.avatica.metrics.dropwizard3;
+
+import org.apache.calcite.avatica.metrics.Counter;
+import org.apache.calcite.avatica.metrics.Gauge;
+import org.apache.calcite.avatica.metrics.Histogram;
+import org.apache.calcite.avatica.metrics.Meter;
+import org.apache.calcite.avatica.metrics.MetricsSystem;
+import org.apache.calcite.avatica.metrics.Timer;
+
+import com.codahale.metrics.MetricRegistry;
+
+import java.util.Objects;
+
+/**
+ * Dropwizard Metrics implementation of {@link MetricsSystem}.
+ */
+public class DropwizardMetricsSystem implements MetricsSystem {
+
+  private final MetricRegistry registry;
+
+  public DropwizardMetricsSystem(MetricRegistry registry) {
+    this.registry = Objects.requireNonNull(registry);
+  }
+
+  @Override public Timer getTimer(String name) {
+    return new DropwizardTimer(registry.timer(name));
+  }
+
+  @Override public Histogram getHistogram(String name) {
+    return new DropwizardHistogram(registry.histogram(name));
+  }
+
+  @Override public Meter getMeter(String name) {
+    return new DropwizardMeter(registry.meter(name));
+  }
+
+  @Override public Counter getCounter(String name) {
+    return new DropwizardCounter(registry.counter(name));
+  }
+
+  @Override public <T> void register(String name, Gauge<T> gauge) {
+    registry.register(name, new DropwizardGauge<T>(gauge));
+  }
+}
+
+// End DropwizardMetricsSystem.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMetricsSystemConfiguration.java
----------------------------------------------------------------------
diff --git a/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMetricsSystemConfiguration.java b/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMetricsSystemConfiguration.java
new file mode 100644
index 0000000..f4c9234
--- /dev/null
+++ b/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMetricsSystemConfiguration.java
@@ -0,0 +1,42 @@
+/*
+ * 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.calcite.avatica.metrics.dropwizard3;
+
+import org.apache.calcite.avatica.metrics.MetricsSystemConfiguration;
+
+import com.codahale.metrics.MetricRegistry;
+
+import java.util.Objects;
+
+/**
+ * A container which provides a {@link MetricRegistry} to a {@link DropwizardMetricsSystem}.
+ */
+public class DropwizardMetricsSystemConfiguration implements
+    MetricsSystemConfiguration<MetricRegistry> {
+
+  private final MetricRegistry registry;
+
+  public DropwizardMetricsSystemConfiguration(MetricRegistry registry) {
+    this.registry = Objects.requireNonNull(registry);
+  }
+
+  @Override public MetricRegistry get() {
+    return registry;
+  }
+}
+
+// End DropwizardMetricsSystemConfiguration.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMetricsSystemFactory.java
----------------------------------------------------------------------
diff --git a/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMetricsSystemFactory.java b/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMetricsSystemFactory.java
new file mode 100644
index 0000000..1480db6
--- /dev/null
+++ b/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMetricsSystemFactory.java
@@ -0,0 +1,42 @@
+/*
+ * 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.calcite.avatica.metrics.dropwizard3;
+
+import org.apache.calcite.avatica.metrics.MetricsSystemConfiguration;
+import org.apache.calcite.avatica.metrics.MetricsSystemFactory;
+
+/**
+ * A {@link MetricsSystemFactory} for {@link DropwizardMetricsSystem}.
+ */
+public class DropwizardMetricsSystemFactory implements MetricsSystemFactory {
+
+  @Override public DropwizardMetricsSystem create(MetricsSystemConfiguration<?> config) {
+    // Verify we got configuration this factory can use
+    if (config instanceof DropwizardMetricsSystemConfiguration) {
+      DropwizardMetricsSystemConfiguration typedConfig =
+          (DropwizardMetricsSystemConfiguration) config;
+
+      return new DropwizardMetricsSystem(typedConfig.get());
+    }
+
+    throw new IllegalStateException("Expected instance of "
+        + DropwizardMetricsSystemConfiguration.class.getName() + " but got "
+        + (null == config ? "null" : config.getClass().getName()));
+  }
+}
+
+// End DropwizardMetricsSystemFactory.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardTimer.java
----------------------------------------------------------------------
diff --git a/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardTimer.java b/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardTimer.java
new file mode 100644
index 0000000..850f9a6
--- /dev/null
+++ b/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardTimer.java
@@ -0,0 +1,54 @@
+/*
+ * 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.calcite.avatica.metrics.dropwizard3;
+
+import com.codahale.metrics.Timer;
+
+import java.util.Objects;
+
+/**
+ * Dropwizard Metrics implementation of {@link org.apache.calcite.avatica.metrics.Timer}.
+ */
+public class DropwizardTimer implements org.apache.calcite.avatica.metrics.Timer {
+
+  private final Timer timer;
+
+  public DropwizardTimer(Timer timer) {
+    this.timer = Objects.requireNonNull(timer);
+  }
+
+  @Override public DropwizardContext start() {
+    return new DropwizardContext(timer.time());
+  }
+
+  /**
+   * Dropwizard Metrics implementation of {@link org.apache.calcite.avatica.metrics.Timer.Context}
+   */
+  public class DropwizardContext implements org.apache.calcite.avatica.metrics.Timer.Context {
+    private final com.codahale.metrics.Timer.Context context;
+
+    public DropwizardContext(com.codahale.metrics.Timer.Context context) {
+      this.context = Objects.requireNonNull(context);
+    }
+
+    @Override public void close() {
+      this.context.stop();
+    }
+  }
+}
+
+// End DropwizardTimer.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/package-info.java
----------------------------------------------------------------------
diff --git a/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/package-info.java b/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/package-info.java
new file mode 100644
index 0000000..f88df93
--- /dev/null
+++ b/avatica-metrics-dropwizardmetrics3/src/main/java/org/apache/calcite/avatica/metrics/dropwizard3/package-info.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.
+ */
+
+/**
+ * Dropwizard-Metrics (v3) implementation of the Avatica Metrics framework.
+ */
+@PackageMarker
+package org.apache.calcite.avatica.metrics.dropwizard3;
+
+import org.apache.calcite.avatica.metrics.PackageMarker;
+
+// End package-info.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics-dropwizardmetrics3/src/main/resources/META-INF/services/org.apache.calcite.avatica.metrics.MetricsSystemFactory
----------------------------------------------------------------------
diff --git a/avatica-metrics-dropwizardmetrics3/src/main/resources/META-INF/services/org.apache.calcite.avatica.metrics.MetricsSystemFactory b/avatica-metrics-dropwizardmetrics3/src/main/resources/META-INF/services/org.apache.calcite.avatica.metrics.MetricsSystemFactory
new file mode 100644
index 0000000..25b64a8
--- /dev/null
+++ b/avatica-metrics-dropwizardmetrics3/src/main/resources/META-INF/services/org.apache.calcite.avatica.metrics.MetricsSystemFactory
@@ -0,0 +1,2 @@
+org.apache.calcite.avatica.metrics.dropwizard3.DropwizardMetricsSystemFactory
+

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardCounterTest.java
----------------------------------------------------------------------
diff --git a/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardCounterTest.java b/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardCounterTest.java
new file mode 100644
index 0000000..b037196
--- /dev/null
+++ b/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardCounterTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.calcite.avatica.metrics.dropwizard3;
+
+import com.codahale.metrics.Counter;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Test class for {@link DropwizardCounter}.
+ */
+public class DropwizardCounterTest {
+
+  private Counter counter;
+
+  @Before public void setup() {
+    this.counter = new Counter();
+  }
+
+  @Test public void testCounting() {
+    DropwizardCounter dwCounter = new DropwizardCounter(counter);
+
+    dwCounter.increment();
+    assertEquals(1L, counter.getCount());
+    dwCounter.increment();
+    assertEquals(2L, counter.getCount());
+    dwCounter.increment(2L);
+    assertEquals(4L, counter.getCount());
+    dwCounter.increment(-1L);
+    assertEquals(3L, counter.getCount());
+
+    dwCounter.decrement();
+    assertEquals(2L, counter.getCount());
+    dwCounter.decrement();
+    assertEquals(1L, counter.getCount());
+    dwCounter.decrement(4L);
+    assertEquals(-3L, counter.getCount());
+    dwCounter.decrement(-3L);
+    assertEquals(0L, counter.getCount());
+  }
+
+}
+
+// End DropwizardCounterTest.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardGaugeTest.java
----------------------------------------------------------------------
diff --git a/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardGaugeTest.java b/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardGaugeTest.java
new file mode 100644
index 0000000..ed78a58
--- /dev/null
+++ b/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardGaugeTest.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.calcite.avatica.metrics.dropwizard3;
+
+import org.apache.calcite.avatica.metrics.Gauge;
+
+import org.junit.Test;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Test class for {@link DropwizardGauge}.
+ */
+public class DropwizardGaugeTest {
+
+  @Test public void test() {
+    SimpleGauge gauge = new SimpleGauge();
+    DropwizardGauge<Long> dwGauge = new DropwizardGauge<>(gauge);
+
+    assertEquals(gauge.getValue(), dwGauge.getValue());
+
+    gauge.setValue(1000L);
+
+    assertEquals(gauge.getValue(), dwGauge.getValue());
+  }
+
+  /**
+   * Gauge implementation with a setter.
+   */
+  private static class SimpleGauge implements Gauge<Long> {
+
+    private final AtomicLong value = new AtomicLong(0L);
+
+    @Override public Long getValue() {
+      return this.value.get();
+    }
+
+    public void setValue(long value) {
+      this.value.set(value);
+    }
+  }
+}
+
+// End DropwizardGaugeTest.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardHistogramTest.java
----------------------------------------------------------------------
diff --git a/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardHistogramTest.java b/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardHistogramTest.java
new file mode 100644
index 0000000..25ec5c0
--- /dev/null
+++ b/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardHistogramTest.java
@@ -0,0 +1,49 @@
+/*
+ * 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.calcite.avatica.metrics.dropwizard3;
+
+import com.codahale.metrics.Histogram;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+/**
+ * Test class for {@link DropwizardHistogram}.
+ */
+public class DropwizardHistogramTest {
+
+  private Histogram histogram;
+
+  @Before public void setup() {
+    this.histogram = Mockito.mock(Histogram.class);
+  }
+
+  @Test public void test() {
+    DropwizardHistogram dwHistogram = new DropwizardHistogram(histogram);
+
+    dwHistogram.update(10);
+
+    dwHistogram.update(100L);
+
+    Mockito.verify(histogram).update(10);
+    Mockito.verify(histogram).update(100L);
+  }
+
+}
+
+// End DropwizardHistogramTest.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMeterTest.java
----------------------------------------------------------------------
diff --git a/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMeterTest.java b/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMeterTest.java
new file mode 100644
index 0000000..c76c7e0
--- /dev/null
+++ b/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMeterTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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.calcite.avatica.metrics.dropwizard3;
+
+import com.codahale.metrics.Meter;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+/**
+ * Test class for {@link DropwizardMeter}.
+ */
+public class DropwizardMeterTest {
+
+  private Meter meter;
+
+  @Before public void setup() {
+    this.meter = Mockito.mock(Meter.class);
+  }
+
+  @Test public void test() {
+    DropwizardMeter dwMeter = new DropwizardMeter(this.meter);
+
+    dwMeter.mark();
+    dwMeter.mark(10L);
+    dwMeter.mark();
+    dwMeter.mark();
+
+    Mockito.verify(meter, Mockito.times(3)).mark();
+    Mockito.verify(meter).mark(10L);
+  }
+
+}
+
+// End DropwizardMeterTest.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMetricsSystemFactoryTest.java
----------------------------------------------------------------------
diff --git a/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMetricsSystemFactoryTest.java b/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMetricsSystemFactoryTest.java
new file mode 100644
index 0000000..332c6e0
--- /dev/null
+++ b/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMetricsSystemFactoryTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.calcite.avatica.metrics.dropwizard3;
+
+import org.apache.calcite.avatica.metrics.noop.NoopMetricsSystemConfiguration;
+
+import com.codahale.metrics.MetricRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Test class for {@link DropwizardMetricsSystemFactory}.
+ */
+public class DropwizardMetricsSystemFactoryTest {
+
+  private DropwizardMetricsSystemFactory factory;
+
+  @Before public void setup() {
+    factory = new DropwizardMetricsSystemFactory();
+  }
+
+  @Test(expected = IllegalStateException.class) public void testNullConfigurationFails() {
+    factory.create(null);
+  }
+
+  @Test(expected = IllegalStateException.class) public void testUnhandledConfigurationType() {
+    factory.create(NoopMetricsSystemConfiguration.getInstance());
+  }
+
+  @Test public void testHandledConfigurationType() {
+    DropwizardMetricsSystem metrics =
+        factory.create(new DropwizardMetricsSystemConfiguration(new MetricRegistry()));
+    assertNotNull("Expected DropwizardMetricsSystem to be non-null", metrics);
+  }
+}
+
+// End DropwizardMetricsSystemFactoryTest.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMetricsSystemTest.java
----------------------------------------------------------------------
diff --git a/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMetricsSystemTest.java b/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMetricsSystemTest.java
new file mode 100644
index 0000000..7eeec3b
--- /dev/null
+++ b/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardMetricsSystemTest.java
@@ -0,0 +1,161 @@
+/*
+ * 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.calcite.avatica.metrics.dropwizard3;
+
+import org.apache.calcite.avatica.metrics.Counter;
+import org.apache.calcite.avatica.metrics.Gauge;
+import org.apache.calcite.avatica.metrics.Histogram;
+import org.apache.calcite.avatica.metrics.Meter;
+import org.apache.calcite.avatica.metrics.Timer;
+import org.apache.calcite.avatica.metrics.Timer.Context;
+
+import com.codahale.metrics.MetricRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests for {@link DropwizardMetricsSystem}.
+ */
+public class DropwizardMetricsSystemTest {
+
+  private MetricRegistry mockRegistry;
+  private DropwizardMetricsSystem metrics;
+
+  @Before public void setup() {
+    mockRegistry = mock(MetricRegistry.class);
+    metrics = new DropwizardMetricsSystem(mockRegistry);
+  }
+
+  @Test public void testGauge() {
+    final long gaugeValue = 42L;
+    final String name = "gauge";
+    metrics.register(name, new Gauge<Long>() {
+      @Override public Long getValue() {
+        return gaugeValue;
+      }
+    });
+
+    verify(mockRegistry, times(1)).register(eq(name), any(com.codahale.metrics.Gauge.class));
+  }
+
+  @Test public void testMeter() {
+    final String name = "meter";
+    final com.codahale.metrics.Meter mockMeter = mock(com.codahale.metrics.Meter.class);
+
+    when(mockRegistry.meter(name)).thenReturn(mockMeter);
+
+    Meter meter = metrics.getMeter(name);
+
+    final long count = 5;
+    meter.mark(count);
+
+    verify(mockMeter, times(1)).mark(count);
+
+    meter.mark();
+
+    verify(mockMeter, times(1)).mark();
+  }
+
+  @Test public void testHistogram() {
+    final String name = "histogram";
+    final com.codahale.metrics.Histogram mockHistogram = mock(com.codahale.metrics.Histogram.class);
+
+    when(mockRegistry.histogram(name)).thenReturn(mockHistogram);
+
+    Histogram histogram = metrics.getHistogram(name);
+
+    long[] long_values = new long[] {1L, 5L, 15L, 30L, 60L};
+    for (long value : long_values) {
+      histogram.update(value);
+    }
+
+    for (long value : long_values) {
+      verify(mockHistogram).update(value);
+    }
+
+    int[] int_values = new int[] {2, 6, 16, 31, 61};
+    for (int value : int_values) {
+      histogram.update(value);
+    }
+
+    for (int value : int_values) {
+      verify(mockHistogram).update(value);
+    }
+  }
+
+  @Test public void testCounter() {
+    final String name = "counter";
+    final com.codahale.metrics.Counter mockCounter = mock(com.codahale.metrics.Counter.class);
+
+    when(mockRegistry.counter(name)).thenReturn(mockCounter);
+
+    Counter counter = metrics.getCounter(name);
+
+    long[] updates = new long[] {1L, 5L, -2L, 4L, -8L, 0};
+    for (long update : updates) {
+      if (update < 0) {
+        counter.decrement(Math.abs(update));
+      } else {
+        counter.increment(update);
+      }
+    }
+
+    for (long update : updates) {
+      if (update < 0) {
+        verify(mockCounter).dec(Math.abs(update));
+      } else {
+        verify(mockCounter).inc(update);
+      }
+    }
+
+    int numSingleUpdates = 3;
+    for (int i = 0; i < numSingleUpdates; i++) {
+      counter.increment();
+      counter.decrement();
+    }
+
+    verify(mockCounter, times(numSingleUpdates)).inc();
+    verify(mockCounter, times(numSingleUpdates)).dec();
+  }
+
+  @Test public void testTimer() {
+    final String name = "timer";
+    final com.codahale.metrics.Timer mockTimer = mock(com.codahale.metrics.Timer.class);
+    final com.codahale.metrics.Timer.Context mockContext =
+        mock(com.codahale.metrics.Timer.Context.class);
+
+    when(mockRegistry.timer(name)).thenReturn(mockTimer);
+    when(mockTimer.time()).thenReturn(mockContext);
+
+    Timer timer = metrics.getTimer(name);
+    Context context = timer.start();
+    context.close();
+
+    verify(mockTimer).time();
+    verify(mockContext).stop();
+  }
+}
+
+// End DropwizardMetricsSystemTest.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardTimerTest.java
----------------------------------------------------------------------
diff --git a/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardTimerTest.java b/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardTimerTest.java
new file mode 100644
index 0000000..536d935
--- /dev/null
+++ b/avatica-metrics-dropwizardmetrics3/src/test/java/org/apache/calcite/avatica/metrics/dropwizard3/DropwizardTimerTest.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.calcite.avatica.metrics.dropwizard3;
+
+import org.apache.calcite.avatica.metrics.dropwizard3.DropwizardTimer.DropwizardContext;
+
+import com.codahale.metrics.Timer;
+import com.codahale.metrics.Timer.Context;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+/**
+ * Test class for {@link DropwizardTimer}
+ */
+public class DropwizardTimerTest {
+
+  private Timer timer;
+  private Context context;
+
+  @Before public void setup() {
+    this.timer = Mockito.mock(Timer.class);
+    this.context = Mockito.mock(Context.class);
+  }
+
+  @Test public void test() {
+    DropwizardTimer dwTimer = new DropwizardTimer(timer);
+
+    Mockito.when(timer.time()).thenReturn(context);
+
+    DropwizardContext dwContext = dwTimer.start();
+
+    dwContext.close();
+
+    Mockito.verify(timer).time();
+    Mockito.verify(context).stop();
+  }
+
+}
+
+// End DropwizardTimerTest.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics/pom.xml
----------------------------------------------------------------------
diff --git a/avatica-metrics/pom.xml b/avatica-metrics/pom.xml
new file mode 100644
index 0000000..cb7da6e
--- /dev/null
+++ b/avatica-metrics/pom.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.calcite</groupId>
+    <artifactId>calcite</artifactId>
+    <version>1.7.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>calcite-avatica-metrics</artifactId>
+  <packaging>jar</packaging>
+  <name>Calcite Avatica Metrics</name>
+  <description>A library designed to abstract away any required dependency on a metrics library</description>
+
+  <properties>
+    <top.dir>${project.basedir}/..</top.dir>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-log4j12</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.eclipse.m2e</groupId>
+          <artifactId>lifecycle-mapping</artifactId>
+          <version>1.0.0</version>
+          <configuration>
+            <lifecycleMappingMetadata>
+              <pluginExecutions>
+                <pluginExecution>
+                  <pluginExecutionFilter>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-checkstyle-plugin</artifactId>
+                    <versionRange>[2.12.1,)</versionRange>
+                    <goals>
+                      <goal>check</goal>
+                    </goals>
+                  </pluginExecutionFilter>
+                  <action>
+                    <ignore />
+                  </action>
+                </pluginExecution>
+              </pluginExecutions>
+            </lifecycleMappingMetadata>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <!-- configurations do not cascade, so all of the definition from
+             ../pom.xml:build:plugin-management:plugins:plugin must be repeated in child poms -->
+        <executions>
+          <execution>
+            <id>analyze</id>
+            <goals>
+              <goal>analyze-only</goal>
+            </goals>
+            <configuration>
+              <failOnWarning>true</failOnWarning>
+              <!-- ignore "unused but declared" warnings -->
+              <ignoredUnusedDeclaredDependencies>
+                <ignoredUnusedDeclaredDependency>org.slf4j:slf4j-log4j12</ignoredUnusedDeclaredDependency>
+              </ignoredUnusedDeclaredDependencies>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <!-- Parent module has the same plugin and does the work of
+           generating -sources.jar for each project. But without the
+           plugin declared here, IDEs don't know the sources are
+           available. -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-source-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>attach-sources</id>
+            <phase>verify</phase>
+            <goals>
+              <goal>jar-no-fork</goal>
+              <goal>test-jar-no-fork</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <artifactId>maven-remote-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>non-root-resources</id>
+            <goals>
+              <goal>process</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/Counter.java
----------------------------------------------------------------------
diff --git a/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/Counter.java b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/Counter.java
new file mode 100644
index 0000000..87aec1b
--- /dev/null
+++ b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/Counter.java
@@ -0,0 +1,49 @@
+/*
+ * 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.calcite.avatica.metrics;
+
+/**
+ * A mutable number.
+ */
+public interface Counter {
+
+  /**
+   * Increment {@code this} by 1.
+   */
+  void increment();
+
+  /**
+   * Increment {@code this} by {@code n}.
+   *
+   * @param n The amount to increment.
+   */
+  void increment(long n);
+
+  /**
+   * Decrement {@code this} by 1.
+   */
+  void decrement();
+
+  /**
+   * Decrement {@code this} by {@code n}.
+   *
+   * @param n The amount to decrement.
+   */
+  void decrement(long n);
+}
+
+// End Counter.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/Gauge.java
----------------------------------------------------------------------
diff --git a/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/Gauge.java b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/Gauge.java
new file mode 100644
index 0000000..6313a9a
--- /dev/null
+++ b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/Gauge.java
@@ -0,0 +1,30 @@
+/*
+ * 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.calcite.avatica.metrics;
+
+/**
+ * A metrics which measures a discrete value.
+ *
+ * @param <T> The value of the Gauge.
+ */
+public interface Gauge<T> extends Metric {
+
+  T getValue();
+
+}
+
+// End Gauge.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/Histogram.java
----------------------------------------------------------------------
diff --git a/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/Histogram.java b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/Histogram.java
new file mode 100644
index 0000000..633af78
--- /dev/null
+++ b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/Histogram.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.calcite.avatica.metrics;
+
+/**
+ * A metric which measures the distribution of values.
+ */
+public interface Histogram extends Metric {
+
+  /**
+   * Adds a new value to the distribution.
+   *
+   * @param value The value to add
+   */
+  void update(int value);
+
+  /**
+   * Adds a new value to the distribution.
+   *
+   * @param value The value to add
+   */
+  void update(long value);
+
+}
+
+// End Histogram.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/Meter.java
----------------------------------------------------------------------
diff --git a/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/Meter.java b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/Meter.java
new file mode 100644
index 0000000..b27f023
--- /dev/null
+++ b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/Meter.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.calcite.avatica.metrics;
+
+/**
+ * A metric which measure the rate at which some operation is invoked.
+ */
+public interface Meter extends Metric {
+
+  /**
+   * Records one occurrence.
+   */
+  void mark();
+
+  /**
+   * Records {@code events} occurrences.
+   *
+   * @param events Number of occurrences to record.
+   */
+  void mark(long events);
+
+}
+
+// End Meter.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/Metric.java
----------------------------------------------------------------------
diff --git a/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/Metric.java b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/Metric.java
new file mode 100644
index 0000000..fe133da
--- /dev/null
+++ b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/Metric.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.calcite.avatica.metrics;
+
+/**
+ * Parent interface for all metrics.
+ */
+public interface Metric {
+
+}
+
+// End Metric.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/MetricsSystem.java
----------------------------------------------------------------------
diff --git a/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/MetricsSystem.java b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/MetricsSystem.java
new file mode 100644
index 0000000..0d1cb4b
--- /dev/null
+++ b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/MetricsSystem.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.calcite.avatica.metrics;
+
+/**
+ * General purpose factory for creating various metrics. Modeled off of the Dropwizard Metrics API.
+ */
+public interface MetricsSystem {
+
+  /**
+   * Get or construct a {@link Timer} used to measure durations and report rates.
+   *
+   * @param name The name of the Timer.
+   * @return An instance of {@link Timer}.
+   */
+  Timer getTimer(String name);
+
+  /**
+   * Get or construct a {@link Histogram} used to measure a distribution of values.
+   *
+   * @param name The name of the Histogram.
+   * @return An instance of {@link Histogram}.
+   */
+  Histogram getHistogram(String name);
+
+  /**
+   * Get or construct a {@link Meter} used to measure durations and report distributions (a
+   * combination of a {@link Timer} and a {@link Histogram}.
+   *
+   * @param name The name of the Meter.
+   * @return An instance of {@link Meter}.
+   */
+  Meter getMeter(String name);
+
+  /**
+   * Get or construct a {@link Counter} used to track a mutable number.
+   *
+   * @param name The name of the Counter
+   * @return An instance of {@link Counter}.
+   */
+  Counter getCounter(String name);
+
+  /**
+   * Register a {@link Gauge}. The Gauge will be invoked at a period defined by the implementation
+   * of {@link MetricsSystem}.
+   *
+   * @param name The name of the Gauge.
+   * @param gauge A callback to compute the current value.
+   */
+  <T> void register(String name, Gauge<T> gauge);
+
+}
+
+// End MetricsSystem.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/MetricsSystemConfiguration.java
----------------------------------------------------------------------
diff --git a/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/MetricsSystemConfiguration.java b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/MetricsSystemConfiguration.java
new file mode 100644
index 0000000..99b6e8c
--- /dev/null
+++ b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/MetricsSystemConfiguration.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.calcite.avatica.metrics;
+
+/**
+ * A container used by a {@link MetricsSystemFactory} to create a {@link MetricsSystem}.
+ *
+ * @param <T> Configuration/State for the {@link MetricsSystem}.
+ */
+public interface MetricsSystemConfiguration<T> {
+
+  /**
+   * @return Some state or configuration to create a {@link MetricsSystem}.
+   */
+  T get();
+
+}
+
+// End MetricsSystemConfiguration.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/MetricsSystemFactory.java
----------------------------------------------------------------------
diff --git a/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/MetricsSystemFactory.java b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/MetricsSystemFactory.java
new file mode 100644
index 0000000..484b230
--- /dev/null
+++ b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/MetricsSystemFactory.java
@@ -0,0 +1,32 @@
+/*
+ * 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.calcite.avatica.metrics;
+
+/**
+ * A factory class for creating instances of {@link MetricsSystem}.
+ */
+public interface MetricsSystemFactory {
+
+  /**
+   * Creates an instance of a {@link MetricsSystem}.
+   *
+   * @return A new {@link MetricsSystem}.
+   */
+  MetricsSystem create(MetricsSystemConfiguration<?> config);
+}
+
+// End MetricsSystemFactory.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/MetricsSystemLoader.java
----------------------------------------------------------------------
diff --git a/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/MetricsSystemLoader.java b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/MetricsSystemLoader.java
new file mode 100644
index 0000000..3a15c5b
--- /dev/null
+++ b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/MetricsSystemLoader.java
@@ -0,0 +1,87 @@
+/*
+ * 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.calcite.avatica.metrics;
+
+import org.apache.calcite.avatica.metrics.noop.NoopMetricsSystem;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.ServiceLoader;
+
+/**
+ * A utility encapsulating use of {@link ServiceLoader} to instantiate a {@link MetricsSystem}.
+ */
+public class MetricsSystemLoader {
+  private static final Logger LOG = LoggerFactory.getLogger(MetricsSystemLoader.class);
+  private static final MetricsSystemLoader INSTANCE = new MetricsSystemLoader();
+
+  private MetricsSystemLoader() {}
+
+  /**
+   * Creates a {@link MetricsSystem} instance using the corresponding {@link MetricsSystemFactory}
+   * available to {@link ServiceLoader} on the classpath. If there is not exactly one instance of
+   * a {@link MetricsSystemFactory}, an instance of {@link NoopMetricsSystem} will be returned.
+   *
+   * @param config State to pass to the {@link MetricsSystemFactory}.
+   * @return A {@link MetricsSystem} implementation.
+   */
+  public static MetricsSystem load(MetricsSystemConfiguration<?> config) {
+    return INSTANCE._load(Objects.requireNonNull(config));
+  }
+
+  MetricsSystem _load(MetricsSystemConfiguration<?> config) {
+    List<MetricsSystemFactory> availableFactories = getFactories();
+
+    if (1 == availableFactories.size()) {
+      // One and only one instance -- what we want/expect
+      MetricsSystemFactory factory = availableFactories.get(0);
+      LOG.info("Loaded MetricsSystem {}", factory.getClass());
+      return factory.create(config);
+    } else if (availableFactories.isEmpty()) {
+      // None-provided default to no metrics
+      LOG.info("No metrics implementation available on classpath. Using No-op implementation");
+      return NoopMetricsSystem.getInstance();
+    } else {
+      // Tell the user they're doing something wrong, and choose the first impl.
+      StringBuilder sb = new StringBuilder();
+      for (MetricsSystemFactory factory : availableFactories) {
+        if (sb.length() > 0) {
+          sb.append(", ");
+        }
+        sb.append(factory.getClass());
+      }
+      LOG.warn("Found multiple MetricsSystemFactory implementations: {}."
+          + " Using No-op implementation", sb);
+      return NoopMetricsSystem.getInstance();
+    }
+  }
+
+  List<MetricsSystemFactory> getFactories() {
+    ServiceLoader<MetricsSystemFactory> loader = ServiceLoader.load(MetricsSystemFactory.class);
+    List<MetricsSystemFactory> availableFactories = new ArrayList<>();
+    for (MetricsSystemFactory factory : loader) {
+      availableFactories.add(factory);
+    }
+    return availableFactories;
+  }
+}
+
+// End MetricsSystemLoader.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/PackageMarker.java
----------------------------------------------------------------------
diff --git a/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/PackageMarker.java b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/PackageMarker.java
new file mode 100644
index 0000000..e627d31
--- /dev/null
+++ b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/PackageMarker.java
@@ -0,0 +1,37 @@
+/*
+ * 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.calcite.avatica.metrics;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This is a dummy annotation that forces javac to produce output for
+ * otherwise empty package-info.java.
+ *
+ * <p>The result is maven-compiler-plugin can properly identify the scope of
+ * changed files
+ *
+ * <p>See more details in
+ * <a href="https://jira.codehaus.org/browse/MCOMPILER-205">
+ *   maven-compiler-plugin: incremental compilation broken</a>
+ */
+@Retention(RetentionPolicy.SOURCE)
+public @interface PackageMarker {
+}
+
+// End PackageMarker.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/Timer.java
----------------------------------------------------------------------
diff --git a/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/Timer.java b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/Timer.java
new file mode 100644
index 0000000..be792cc
--- /dev/null
+++ b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/Timer.java
@@ -0,0 +1,37 @@
+/*
+ * 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.calcite.avatica.metrics;
+
+/**
+ * A metric which encompasses a {@link Histogram} and {@link Meter}.
+ */
+public interface Timer extends Metric {
+
+  Context start();
+
+  /**
+   * A object that tracks an active timing state.
+   */
+  public interface Context extends AutoCloseable {
+    /**
+     * Stops the timer.
+     */
+    void close();
+  }
+}
+
+// End Timer.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopCounter.java
----------------------------------------------------------------------
diff --git a/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopCounter.java b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopCounter.java
new file mode 100644
index 0000000..9ce8476
--- /dev/null
+++ b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopCounter.java
@@ -0,0 +1,36 @@
+/*
+ * 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.calcite.avatica.metrics.noop;
+
+import org.apache.calcite.avatica.metrics.Counter;
+
+/**
+ * {@link Counter} implementation which does nothing.
+ */
+public class NoopCounter implements Counter {
+
+  @Override public void increment() {}
+
+  @Override public void increment(long n) {}
+
+  @Override public void decrement() {}
+
+  @Override public void decrement(long n) {}
+
+}
+
+// End NoopCounter.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopHistogram.java
----------------------------------------------------------------------
diff --git a/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopHistogram.java b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopHistogram.java
new file mode 100644
index 0000000..ee056e9
--- /dev/null
+++ b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopHistogram.java
@@ -0,0 +1,32 @@
+/*
+ * 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.calcite.avatica.metrics.noop;
+
+import org.apache.calcite.avatica.metrics.Histogram;
+
+/**
+ * {@link Histogram} which does nothing.
+ */
+public class NoopHistogram implements Histogram {
+
+  @Override public void update(int value) {}
+
+  @Override public void update(long value) {}
+
+}
+
+// End NoopHistogram.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopMeter.java
----------------------------------------------------------------------
diff --git a/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopMeter.java b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopMeter.java
new file mode 100644
index 0000000..4ad68c9
--- /dev/null
+++ b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopMeter.java
@@ -0,0 +1,32 @@
+/*
+ * 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.calcite.avatica.metrics.noop;
+
+import org.apache.calcite.avatica.metrics.Meter;
+
+/**
+ * {@link Meter} which does nothing.
+ */
+public class NoopMeter implements Meter {
+
+  @Override public void mark() {}
+
+  @Override public void mark(long events) {}
+
+}
+
+// End NoopMeter.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/7e5710fc/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopMetricsSystem.java
----------------------------------------------------------------------
diff --git a/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopMetricsSystem.java b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopMetricsSystem.java
new file mode 100644
index 0000000..12b5af1
--- /dev/null
+++ b/avatica-metrics/src/main/java/org/apache/calcite/avatica/metrics/noop/NoopMetricsSystem.java
@@ -0,0 +1,69 @@
+/*
+ * 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.calcite.avatica.metrics.noop;
+
+import org.apache.calcite.avatica.metrics.Counter;
+import org.apache.calcite.avatica.metrics.Gauge;
+import org.apache.calcite.avatica.metrics.Histogram;
+import org.apache.calcite.avatica.metrics.Meter;
+import org.apache.calcite.avatica.metrics.Metric;
+import org.apache.calcite.avatica.metrics.MetricsSystem;
+import org.apache.calcite.avatica.metrics.Timer;
+
+/**
+ * {@link MetricsSystem} implementation which does nothing. Returns {@link Metric} implementations
+ * which also does nothing (avoiding null instances).
+ */
+public class NoopMetricsSystem implements MetricsSystem {
+
+  private static final NoopMetricsSystem NOOP_METRICS = new NoopMetricsSystem();
+
+  private static final Timer TIMER = new NoopTimer();
+  private static final Histogram HISTOGRAM = new NoopHistogram();
+  private static final Meter METER = new NoopMeter();
+  private static final Counter COUNTER = new NoopCounter();
+
+  /**
+   * @return A {@link NoopMetricsSystem} instance.
+   */
+  public static NoopMetricsSystem getInstance() {
+    return NOOP_METRICS;
+  }
+
+  private NoopMetricsSystem() {}
+
+  @Override public Timer getTimer(String name) {
+    return TIMER;
+  }
+
+  @Override public Histogram getHistogram(String name) {
+    return HISTOGRAM;
+  }
+
+  @Override public Meter getMeter(String name) {
+    return METER;
+  }
+
+  @Override public Counter getCounter(String name) {
+    return COUNTER;
+  }
+
+  @Override public <T> void register(String name, Gauge<T> gauge) {}
+
+}
+
+// End NoopMetricsSystem.java