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:37 UTC
[2/3] calcite git commit: [CALCITE-642] Add an avatica-metrics API
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