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
