bookkeeper-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From eolive...@apache.org
Subject bookkeeper git commit: BOOKKEEPER-1073: Several stats provider related changes.
Date Thu, 01 Jun 2017 06:55:58 GMT
Repository: bookkeeper
Updated Branches:
  refs/heads/master 9bade929d -> fc51f73cb


BOOKKEEPER-1073: Several stats provider related changes.

- add finagle stats provider
- provide the ability to remove gauge and scopes
- update jetty versions for twitter-sciences stats provider

Author: Sijie Guo <sijie@apache.org>

Reviewers: Jia Zhai, Enrico Olivelli

Closes #160 from sijie/add_channel_writer_timer


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

Branch: refs/heads/master
Commit: fc51f73cbc9cdaae9876bc08cafa3e7a80826207
Parents: 9bade92
Author: Sijie Guo <sijie@apache.org>
Authored: Thu Jun 1 08:55:45 2017 +0200
Committer: Enrico Olivelli <eolivelli@apache.org>
Committed: Thu Jun 1 08:55:45 2017 +0200

----------------------------------------------------------------------
 .../bookkeeper/stats/CodahaleStatsLogger.java   |  10 ++
 bookkeeper-stats-providers/pom.xml              |   1 +
 .../bookkeeper/stats/PrometheusStatsLogger.java |  10 ++
 .../twitter-finagle-provider/pom.xml            |  55 ++++++++++
 .../stats/twitter/finagle/CounterImpl.java      |  60 +++++++++++
 .../twitter/finagle/FinagleStatsLoggerImpl.java |  86 ++++++++++++++++
 .../twitter/finagle/FinagleStatsProvider.java   |  47 +++++++++
 .../twitter/finagle/OpStatsLoggerImpl.java      |  76 ++++++++++++++
 .../twitter/ostrich/OpStatsLoggerImpl.java      |  37 +++++--
 .../stats/twitter/ostrich/OstrichProvider.java  |  50 ++++++++-
 .../twitter/ostrich/OstrichStatsLoggerImpl.java |   9 ++
 .../twitter-science-provider/pom.xml            |   4 +-
 .../twitter/science/TwitterStatsLoggerImpl.java |   9 ++
 .../twitter/science/TwitterStatsProvider.java   |  24 ++++-
 .../bookkeeper/stats/CachingStatsLogger.java    | 102 +++++++++++++++++++
 .../bookkeeper/stats/CachingStatsProvider.java  |  55 ++++++++++
 .../bookkeeper/stats/NullStatsLogger.java       |   9 ++
 .../apache/bookkeeper/stats/StatsLogger.java    |  23 ++++-
 pom.xml                                         |   6 +-
 19 files changed, 654 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/bookkeeper/blob/fc51f73c/bookkeeper-stats-providers/codahale-metrics-provider/src/main/java/org/apache/bookkeeper/stats/CodahaleStatsLogger.java
----------------------------------------------------------------------
diff --git a/bookkeeper-stats-providers/codahale-metrics-provider/src/main/java/org/apache/bookkeeper/stats/CodahaleStatsLogger.java
b/bookkeeper-stats-providers/codahale-metrics-provider/src/main/java/org/apache/bookkeeper/stats/CodahaleStatsLogger.java
index 156290b..5da084b 100644
--- a/bookkeeper-stats-providers/codahale-metrics-provider/src/main/java/org/apache/bookkeeper/stats/CodahaleStatsLogger.java
+++ b/bookkeeper-stats-providers/codahale-metrics-provider/src/main/java/org/apache/bookkeeper/stats/CodahaleStatsLogger.java
@@ -87,6 +87,11 @@ public class CodahaleStatsLogger implements StatsLogger {
     }
 
     @Override
+    public <T extends Number> void unregisterGauge(String statName, Gauge<T>
gauge) {
+        // do nothing right now as the Codahale doesn't support conditional removal
+    }
+
+    @Override
     public StatsLogger scope(String scope) {
         String scopeName;
         if (0 == basename.length()) {
@@ -96,4 +101,9 @@ public class CodahaleStatsLogger implements StatsLogger {
         }
         return new CodahaleStatsLogger(metrics, scopeName);
     }
+
+    @Override
+    public void removeScope(String name, StatsLogger statsLogger) {
+        // no-op. the codahale stats logger doesn't have the references for stats logger.
+    }
 }

http://git-wip-us.apache.org/repos/asf/bookkeeper/blob/fc51f73c/bookkeeper-stats-providers/pom.xml
----------------------------------------------------------------------
diff --git a/bookkeeper-stats-providers/pom.xml b/bookkeeper-stats-providers/pom.xml
index d6c58b5..5c1b298 100644
--- a/bookkeeper-stats-providers/pom.xml
+++ b/bookkeeper-stats-providers/pom.xml
@@ -29,6 +29,7 @@
   <packaging>pom</packaging>
   <name>bookkeeper-stats-providers</name>
   <modules>
+    <module>twitter-finagle-provider</module>
     <module>twitter-science-provider</module>
     <module>twitter-ostrich-provider</module>
     <module>codahale-metrics-provider</module>

http://git-wip-us.apache.org/repos/asf/bookkeeper/blob/fc51f73c/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/PrometheusStatsLogger.java
----------------------------------------------------------------------
diff --git a/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/PrometheusStatsLogger.java
b/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/PrometheusStatsLogger.java
index ab15639..e58bf70 100644
--- a/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/PrometheusStatsLogger.java
+++ b/bookkeeper-stats-providers/prometheus-metrics-provider/src/main/java/org/apache/bookkeeper/stats/PrometheusStatsLogger.java
@@ -63,6 +63,16 @@ public class PrometheusStatsLogger implements StatsLogger {
     }
 
     @Override
+    public <T extends Number> void unregisterGauge(String name, Gauge<T> gauge)
{
+        // no-op
+    }
+
+    @Override
+    public void removeScope(String name, StatsLogger statsLogger) {
+        // no-op
+    }
+
+    @Override
     public StatsLogger scope(String name) {
         return new PrometheusStatsLogger(registry, completeName(name));
     }

http://git-wip-us.apache.org/repos/asf/bookkeeper/blob/fc51f73c/bookkeeper-stats-providers/twitter-finagle-provider/pom.xml
----------------------------------------------------------------------
diff --git a/bookkeeper-stats-providers/twitter-finagle-provider/pom.xml b/bookkeeper-stats-providers/twitter-finagle-provider/pom.xml
new file mode 100644
index 0000000..1e0af00
--- /dev/null
+++ b/bookkeeper-stats-providers/twitter-finagle-provider/pom.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0"?>
+<!--
+   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 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <artifactId>bookkeeper</artifactId>
+    <groupId>org.apache.bookkeeper</groupId>
+    <version>4.5.0-SNAPSHOT</version>
+    <relativePath>../..</relativePath>
+  </parent>
+  <groupId>org.apache.bookkeeper.stats</groupId>
+  <artifactId>twitter-finagle-provider</artifactId>
+  <name>Stats provider for Finagle stats</name>
+  <url>http://maven.apache.org</url>
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <project.libdir>${basedir}/lib</project.libdir>
+  </properties>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.bookkeeper.stats</groupId>
+      <artifactId>bookkeeper-stats-api</artifactId>
+      <version>${project.parent.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.twitter</groupId>
+      <artifactId>finagle-core_2.10</artifactId>
+      <version>6.34.0</version>
+    </dependency>
+  </dependencies>
+  <repositories>
+    <repository>
+      <id>twitter</id>
+      <name>Twitter repo</name>
+      <layout>default</layout>
+      <url>http://maven.twttr.com</url>
+    </repository>
+  </repositories>
+</project>

http://git-wip-us.apache.org/repos/asf/bookkeeper/blob/fc51f73c/bookkeeper-stats-providers/twitter-finagle-provider/src/main/java/org/apache/bookkeeper/stats/twitter/finagle/CounterImpl.java
----------------------------------------------------------------------
diff --git a/bookkeeper-stats-providers/twitter-finagle-provider/src/main/java/org/apache/bookkeeper/stats/twitter/finagle/CounterImpl.java
b/bookkeeper-stats-providers/twitter-finagle-provider/src/main/java/org/apache/bookkeeper/stats/twitter/finagle/CounterImpl.java
new file mode 100644
index 0000000..a065323
--- /dev/null
+++ b/bookkeeper-stats-providers/twitter-finagle-provider/src/main/java/org/apache/bookkeeper/stats/twitter/finagle/CounterImpl.java
@@ -0,0 +1,60 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.bookkeeper.stats.twitter.finagle;
+
+import com.twitter.finagle.stats.StatsReceiver;
+import org.apache.bookkeeper.stats.Counter;
+
+/**
+ * Note: this counter doesn't support resetting values or getting the current value.
+ * It also has a limitation in size: max bound is signed integer, not long.
+ */
+class CounterImpl implements Counter {
+    final private com.twitter.finagle.stats.Counter counter;
+
+    public CounterImpl(final String name,
+                       final StatsReceiver stats) {
+        this.counter = stats.counter0(name);
+    }
+
+    @Override
+    public void clear() { /* not supported */ }
+
+    @Override
+    public void inc() {
+        this.counter.incr();
+    }
+
+    @Override
+    public void dec() {
+        this.counter.incr(-1);
+    }
+
+    @Override
+    public void add(final long delta) {
+        if (delta < Integer.MIN_VALUE || delta > Integer.MAX_VALUE) {
+            throw new IllegalArgumentException("This counter doesn't support long values");
+        }
+        this.counter.incr((int) delta);
+    }
+
+    @Override
+    public Long get() {
+        return null; // not supported
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/bookkeeper/blob/fc51f73c/bookkeeper-stats-providers/twitter-finagle-provider/src/main/java/org/apache/bookkeeper/stats/twitter/finagle/FinagleStatsLoggerImpl.java
----------------------------------------------------------------------
diff --git a/bookkeeper-stats-providers/twitter-finagle-provider/src/main/java/org/apache/bookkeeper/stats/twitter/finagle/FinagleStatsLoggerImpl.java
b/bookkeeper-stats-providers/twitter-finagle-provider/src/main/java/org/apache/bookkeeper/stats/twitter/finagle/FinagleStatsLoggerImpl.java
new file mode 100644
index 0000000..cef8d71
--- /dev/null
+++ b/bookkeeper-stats-providers/twitter-finagle-provider/src/main/java/org/apache/bookkeeper/stats/twitter/finagle/FinagleStatsLoggerImpl.java
@@ -0,0 +1,86 @@
+/**
+ * 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.bookkeeper.stats.twitter.finagle;
+
+import com.twitter.finagle.stats.StatsReceiver;
+import com.twitter.util.Function0;
+import org.apache.bookkeeper.stats.Counter;
+import org.apache.bookkeeper.stats.Gauge;
+import org.apache.bookkeeper.stats.OpStatsLogger;
+import org.apache.bookkeeper.stats.StatsLogger;
+import scala.collection.Seq;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+public class FinagleStatsLoggerImpl implements StatsLogger {
+    final private StatsReceiver stats;
+    // keep the references for finagle gauges. they are destroyed when the stats logger is
destroyed.
+    final Map<Gauge, com.twitter.finagle.stats.Gauge> finagleGauges;
+
+    public FinagleStatsLoggerImpl(final StatsReceiver stats) {
+        this.stats = stats;
+        this.finagleGauges = new HashMap<Gauge, com.twitter.finagle.stats.Gauge>();
+    }
+
+    @Override
+    public OpStatsLogger getOpStatsLogger(final String name) {
+        return new OpStatsLoggerImpl(name, this.stats);
+    }
+
+    @Override
+    public Counter getCounter(final String name) {
+        return new CounterImpl(name, this.stats);
+    }
+
+    @Override
+    public <T extends Number> void registerGauge(final String name, final Gauge<T>
gauge) {
+        // This is done to inter-op with Scala Seq
+        final Seq<String> gaugeName = scala.collection.JavaConversions.asScalaBuffer(Arrays.asList(name)).toList();
+        synchronized (finagleGauges) {
+            finagleGauges.put(gauge, this.stats.addGauge(gaugeName, gaugeProvider(gauge)));
+        }
+    }
+
+    @Override
+    public <T extends Number> void unregisterGauge(String name, Gauge<T> gauge)
{
+        synchronized (finagleGauges) {
+            finagleGauges.remove(gauge);
+        }
+    }
+
+    private <T extends Number> Function0<Object> gaugeProvider(final Gauge<T>
gauge) {
+        return new Function0<Object>() {
+            @Override
+            public Object apply() {
+                return gauge.getSample().floatValue();
+            }
+        };
+    }
+
+    @Override
+    public StatsLogger scope(String name) {
+        return new FinagleStatsLoggerImpl(this.stats.scope(name));
+    }
+
+    @Override
+    public void removeScope(String name, StatsLogger statsLogger) {
+        // no-op
+    }
+}

http://git-wip-us.apache.org/repos/asf/bookkeeper/blob/fc51f73c/bookkeeper-stats-providers/twitter-finagle-provider/src/main/java/org/apache/bookkeeper/stats/twitter/finagle/FinagleStatsProvider.java
----------------------------------------------------------------------
diff --git a/bookkeeper-stats-providers/twitter-finagle-provider/src/main/java/org/apache/bookkeeper/stats/twitter/finagle/FinagleStatsProvider.java
b/bookkeeper-stats-providers/twitter-finagle-provider/src/main/java/org/apache/bookkeeper/stats/twitter/finagle/FinagleStatsProvider.java
new file mode 100644
index 0000000..113c257
--- /dev/null
+++ b/bookkeeper-stats-providers/twitter-finagle-provider/src/main/java/org/apache/bookkeeper/stats/twitter/finagle/FinagleStatsProvider.java
@@ -0,0 +1,47 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.bookkeeper.stats.twitter.finagle;
+
+import com.twitter.finagle.stats.StatsReceiver;
+import org.apache.bookkeeper.stats.StatsLogger;
+import org.apache.bookkeeper.stats.StatsProvider;
+import org.apache.commons.configuration.Configuration;
+
+/**
+ * Main entry point to use Finagle stats for Bookkeeper.
+ *
+ * There's no requirement to start or stop it.
+ */
+public class FinagleStatsProvider implements StatsProvider {
+    final private StatsReceiver stats;
+
+    public FinagleStatsProvider(final StatsReceiver stats) {
+        this.stats = stats;
+    }
+
+    @Override
+    public void start(Configuration conf) { /* no-op */ }
+
+    @Override
+    public void stop() { /* no-op */ }
+
+    @Override
+    public StatsLogger getStatsLogger(final String scope) {
+        return new FinagleStatsLoggerImpl(this.stats.scope(scope));
+    }
+}

http://git-wip-us.apache.org/repos/asf/bookkeeper/blob/fc51f73c/bookkeeper-stats-providers/twitter-finagle-provider/src/main/java/org/apache/bookkeeper/stats/twitter/finagle/OpStatsLoggerImpl.java
----------------------------------------------------------------------
diff --git a/bookkeeper-stats-providers/twitter-finagle-provider/src/main/java/org/apache/bookkeeper/stats/twitter/finagle/OpStatsLoggerImpl.java
b/bookkeeper-stats-providers/twitter-finagle-provider/src/main/java/org/apache/bookkeeper/stats/twitter/finagle/OpStatsLoggerImpl.java
new file mode 100644
index 0000000..775c4be
--- /dev/null
+++ b/bookkeeper-stats-providers/twitter-finagle-provider/src/main/java/org/apache/bookkeeper/stats/twitter/finagle/OpStatsLoggerImpl.java
@@ -0,0 +1,76 @@
+/**
+ * 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.bookkeeper.stats.twitter.finagle;
+
+import com.twitter.finagle.stats.Stat;
+import com.twitter.finagle.stats.StatsReceiver;
+import java.util.concurrent.TimeUnit;
+import org.apache.bookkeeper.stats.OpStatsData;
+import org.apache.bookkeeper.stats.OpStatsLogger;
+
+/**
+ * A percentile stat that will delegate to Finagle stats' implementation library
+ * to compute the percentiles.
+ *
+ * Note: metrics will be exposed in form $name/success.p99 for successful events,
+ * and $name/failure.p99 for failed ones.
+ */
+public class OpStatsLoggerImpl implements OpStatsLogger {
+    final private static OpStatsData NULL_OP_STATS = new OpStatsData(0, 0, 0, new long[6]);
+    final private Stat success;
+    final private Stat failure;
+
+    public OpStatsLoggerImpl(final String name, final StatsReceiver stats) {
+        this.success = stats.scope(String.format("%s/success", name)).stat0(name);
+        this.failure = stats.scope(String.format("%s/failure", name)).stat0(name);
+    }
+
+    @Override
+    public void registerFailedEvent(long eventLatency, TimeUnit unit) {
+        this.success.add(unit.toMillis(eventLatency));
+    }
+
+    @Override
+    public void registerSuccessfulEvent(long eventLatency, TimeUnit unit) {
+        this.failure.add(unit.toMillis(eventLatency));
+    }
+
+    @Override
+    public void registerSuccessfulValue(final long value) {
+        this.success.add(value);
+    }
+
+    @Override
+    public void registerFailedValue(final long value) {
+        this.failure.add(value);
+    }
+
+    /**
+     * We don't need to support percentiles as a part of this provider,
+     * since they're part of the Stats implementation library.
+     *
+     * @return dummy null-stats object
+     */
+    @Override
+    public OpStatsData toOpStatsData() {
+        return NULL_OP_STATS;
+    }
+
+    @Override
+    public void clear() { /* not supported */ }
+}

http://git-wip-us.apache.org/repos/asf/bookkeeper/blob/fc51f73c/bookkeeper-stats-providers/twitter-ostrich-provider/src/main/java/org/apache/bookkeeper/stats/twitter/ostrich/OpStatsLoggerImpl.java
----------------------------------------------------------------------
diff --git a/bookkeeper-stats-providers/twitter-ostrich-provider/src/main/java/org/apache/bookkeeper/stats/twitter/ostrich/OpStatsLoggerImpl.java
b/bookkeeper-stats-providers/twitter-ostrich-provider/src/main/java/org/apache/bookkeeper/stats/twitter/ostrich/OpStatsLoggerImpl.java
index 3e8eeb9..d4b8adb 100644
--- a/bookkeeper-stats-providers/twitter-ostrich-provider/src/main/java/org/apache/bookkeeper/stats/twitter/ostrich/OpStatsLoggerImpl.java
+++ b/bookkeeper-stats-providers/twitter-ostrich-provider/src/main/java/org/apache/bookkeeper/stats/twitter/ostrich/OpStatsLoggerImpl.java
@@ -21,8 +21,13 @@ import java.util.concurrent.TimeUnit;
 import org.apache.bookkeeper.stats.OpStatsData;
 import org.apache.bookkeeper.stats.OpStatsLogger;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 class OpStatsLoggerImpl implements OpStatsLogger {
 
+    static final Logger LOG = LoggerFactory.getLogger(OpStatsLoggerImpl.class);
+
     static final double[] PERCENTILES = new double[] {
             0.1, 0.5, 0.9, 0.99, 0.999, 0.9999
     };
@@ -47,26 +52,42 @@ class OpStatsLoggerImpl implements OpStatsLogger {
 
     @Override
     public void registerFailedEvent(long eventLatency, TimeUnit unit) {
-        failureMetric.add((int) unit.toMillis(eventLatency));
-        failureCounter.incr();
+        if (eventLatency < 0) {
+            LOG.debug("{} : tried to register negative failure", scope);
+        } else {
+            failureMetric.add((int) unit.toMillis(eventLatency));
+            failureCounter.incr();
+        }
     }
 
     @Override
     public void registerSuccessfulEvent(long eventLatency, TimeUnit unit) {
-        successMetric.add((int) unit.toMillis(eventLatency));
-        successCounter.incr();
+        if (eventLatency < 0) {
+            LOG.debug("{} : tried to register negative success", scope);
+        } else {
+            successMetric.add((int) unit.toMillis(eventLatency));
+            successCounter.incr();
+        }
     }
 
     @Override
     public void registerSuccessfulValue(long value) {
-        successMetric.add((int) value);
-        successCounter.incr();
+        if (value < 0) {
+            LOG.debug("{} : tried to register negative success", scope);
+        } else {
+            successMetric.add((int) value);
+            successCounter.incr();
+        }
     }
 
     @Override
     public void registerFailedValue(long value) {
-        failureMetric.add((int) value);
-        failureCounter.incr();
+        if (value < 0) {
+            LOG.debug("{} : tried to register negative success", scope);
+        } else {
+            failureMetric.add((int) value);
+            failureCounter.incr();
+        }
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/bookkeeper/blob/fc51f73c/bookkeeper-stats-providers/twitter-ostrich-provider/src/main/java/org/apache/bookkeeper/stats/twitter/ostrich/OstrichProvider.java
----------------------------------------------------------------------
diff --git a/bookkeeper-stats-providers/twitter-ostrich-provider/src/main/java/org/apache/bookkeeper/stats/twitter/ostrich/OstrichProvider.java
b/bookkeeper-stats-providers/twitter-ostrich-provider/src/main/java/org/apache/bookkeeper/stats/twitter/ostrich/OstrichProvider.java
index f0cba13..d4d00d3 100644
--- a/bookkeeper-stats-providers/twitter-ostrich-provider/src/main/java/org/apache/bookkeeper/stats/twitter/ostrich/OstrichProvider.java
+++ b/bookkeeper-stats-providers/twitter-ostrich-provider/src/main/java/org/apache/bookkeeper/stats/twitter/ostrich/OstrichProvider.java
@@ -18,8 +18,10 @@ package org.apache.bookkeeper.stats.twitter.ostrich;
 
 import com.twitter.ostrich.admin.CustomHttpHandler;
 import com.twitter.ostrich.admin.RuntimeEnvironment;
+import com.twitter.ostrich.admin.ServiceTracker;
 import com.twitter.ostrich.admin.StatsFactory;
 import com.twitter.util.Duration;
+import org.apache.bookkeeper.stats.CachingStatsProvider;
 import org.apache.bookkeeper.stats.StatsLogger;
 import org.apache.bookkeeper.stats.StatsProvider;
 import org.apache.commons.configuration.Configuration;
@@ -37,29 +39,62 @@ public class OstrichProvider implements StatsProvider {
 
     protected final static String STATS_EXPORT = "statsExport";
     protected final static String STATS_HTTP_PORT = "statsHttpPort";
+    protected final static String SHOULD_SHUTDOWN_SERVICE_TRACKER = "shouldShutdownServiceTracker";
 
     private com.twitter.ostrich.admin.AdminHttpService statsExporter = null;
+    private final CachingStatsProvider cachingStatsProvider;
+    private boolean shutdownServiceTracker = false;
 
-    private static List<Duration> list(Duration... ts) {
+    private static List<Duration> list(Duration ... ts) {
         List<Duration> result = List$.MODULE$.empty();
         for (int i = ts.length; i > 0; i--) {
-            result = new $colon$colon<Duration>(ts[i-1], result);
+            result = new $colon$colon<>(ts[i-1], result);
         }
         return result;
     }
 
+    private static <T> List<T> emptyList() {
+        return List$.MODULE$.empty();
+    }
+
     private static <K, V> Map<K, V> emptyMap() {
         Map<K, V> result = Map$.MODULE$.empty();
         return result;
     }
 
+    public OstrichProvider() {
+        this("");
+    }
+
+    public OstrichProvider(final String collectionName) {
+        this.cachingStatsProvider = new CachingStatsProvider(new StatsProvider() {
+            @Override
+            public void start(Configuration conf) {
+                // nop
+            }
+
+            @Override
+            public void stop() {
+                // nop
+            }
+
+            @Override
+            public StatsLogger getStatsLogger(String scope) {
+                return new OstrichStatsLoggerImpl(scope,
+                        com.twitter.ostrich.stats.Stats.get(collectionName));
+            }
+        });
+    }
+
     @Override
     public void start(Configuration conf) {
         if (conf.getBoolean(STATS_EXPORT, false)) {
             statsExporter = new com.twitter.ostrich.admin.AdminServiceFactory(
-                    conf.getInt(STATS_HTTP_PORT, 9002), 20, List$.MODULE$.<StatsFactory>empty(),
Some.apply(""), List$.MODULE$.<Regex>empty(),
+                    conf.getInt(STATS_HTTP_PORT, 9002), 20, OstrichProvider.<StatsFactory>emptyList(),
+                    Some.apply(""), OstrichProvider.<Regex>emptyList(),
                     OstrichProvider.<String, CustomHttpHandler>emptyMap(), list(Duration.apply(1,
TimeUnit.MINUTES))
             ).apply(RuntimeEnvironment.apply(this, new String[0]));
+            this.shutdownServiceTracker = conf.getBoolean(SHOULD_SHUTDOWN_SERVICE_TRACKER,
false);
         }
     }
 
@@ -67,11 +102,18 @@ public class OstrichProvider implements StatsProvider {
     public void stop() {
         if (null != statsExporter) {
             statsExporter.shutdown();
+            if (shutdownServiceTracker) {
+                // ostrich admin service registered some threads in service tracker
+                // shutdown doesn't stopped those threads. we need to stop service tracker
+                // to shutdown them. but that potentially has side effects. so adding a flag
+                // to let caller decide.
+                ServiceTracker.shutdown();
+            }
         }
     }
 
     @Override
     public StatsLogger getStatsLogger(String scope) {
-        return new OstrichStatsLoggerImpl(scope, com.twitter.ostrich.stats.Stats.get(""));
+        return cachingStatsProvider.getStatsLogger(scope);
     }
 }

http://git-wip-us.apache.org/repos/asf/bookkeeper/blob/fc51f73c/bookkeeper-stats-providers/twitter-ostrich-provider/src/main/java/org/apache/bookkeeper/stats/twitter/ostrich/OstrichStatsLoggerImpl.java
----------------------------------------------------------------------
diff --git a/bookkeeper-stats-providers/twitter-ostrich-provider/src/main/java/org/apache/bookkeeper/stats/twitter/ostrich/OstrichStatsLoggerImpl.java
b/bookkeeper-stats-providers/twitter-ostrich-provider/src/main/java/org/apache/bookkeeper/stats/twitter/ostrich/OstrichStatsLoggerImpl.java
index 483ba0f..52027fc 100644
--- a/bookkeeper-stats-providers/twitter-ostrich-provider/src/main/java/org/apache/bookkeeper/stats/twitter/ostrich/OstrichStatsLoggerImpl.java
+++ b/bookkeeper-stats-providers/twitter-ostrich-provider/src/main/java/org/apache/bookkeeper/stats/twitter/ostrich/OstrichStatsLoggerImpl.java
@@ -57,6 +57,11 @@ class OstrichStatsLoggerImpl implements StatsLogger {
         ostrichProvider.addGauge(getStatName(statName), gaugeFunc);
     }
 
+    @Override
+    public <T extends Number> void unregisterGauge(String statName, Gauge<T>
gauge) {
+        ostrichProvider.clearGauge(getStatName(statName));
+    }
+
     private String getStatName(String statName) {
         return String.format("%s/%s", scope, statName);
     }
@@ -66,4 +71,8 @@ class OstrichStatsLoggerImpl implements StatsLogger {
         return new OstrichStatsLoggerImpl(getStatName(scope), ostrichProvider);
     }
 
+    @Override
+    public void removeScope(String name, StatsLogger statsLogger) {
+        // no-op
+    }
 }

http://git-wip-us.apache.org/repos/asf/bookkeeper/blob/fc51f73c/bookkeeper-stats-providers/twitter-science-provider/pom.xml
----------------------------------------------------------------------
diff --git a/bookkeeper-stats-providers/twitter-science-provider/pom.xml b/bookkeeper-stats-providers/twitter-science-provider/pom.xml
index e48d98c..96e7303 100644
--- a/bookkeeper-stats-providers/twitter-science-provider/pom.xml
+++ b/bookkeeper-stats-providers/twitter-science-provider/pom.xml
@@ -70,12 +70,12 @@
     <dependency>
       <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-server</artifactId>
-      <version>8.1.4.v20120524</version>
+      <version>9.0.7.v20131107</version>
     </dependency>
     <dependency>
       <groupId>org.eclipse.jetty</groupId>
       <artifactId>jetty-servlet</artifactId>
-      <version>8.1.4.v20120524</version>
+      <version>9.0.7.v20131107</version>
     </dependency>
   </dependencies>
   <repositories>

http://git-wip-us.apache.org/repos/asf/bookkeeper/blob/fc51f73c/bookkeeper-stats-providers/twitter-science-provider/src/main/java/org/apache/bookkeeper/stats/twitter/science/TwitterStatsLoggerImpl.java
----------------------------------------------------------------------
diff --git a/bookkeeper-stats-providers/twitter-science-provider/src/main/java/org/apache/bookkeeper/stats/twitter/science/TwitterStatsLoggerImpl.java
b/bookkeeper-stats-providers/twitter-science-provider/src/main/java/org/apache/bookkeeper/stats/twitter/science/TwitterStatsLoggerImpl.java
index c30c545..cf63ed9 100644
--- a/bookkeeper-stats-providers/twitter-science-provider/src/main/java/org/apache/bookkeeper/stats/twitter/science/TwitterStatsLoggerImpl.java
+++ b/bookkeeper-stats-providers/twitter-science-provider/src/main/java/org/apache/bookkeeper/stats/twitter/science/TwitterStatsLoggerImpl.java
@@ -54,6 +54,11 @@ public class TwitterStatsLoggerImpl implements StatsLogger {
         });
     }
 
+    @Override
+    public <T extends Number> void unregisterGauge(String name, Gauge<T> gauge)
{
+        // no-op
+    }
+
     private String getStatName(String statName) {
         return (name + "_" + statName).toLowerCase();
     }
@@ -69,4 +74,8 @@ public class TwitterStatsLoggerImpl implements StatsLogger {
         return new TwitterStatsLoggerImpl(scopeName);
     }
 
+    @Override
+    public void removeScope(String name, StatsLogger statsLogger) {
+        // no-op
+    }
 }

http://git-wip-us.apache.org/repos/asf/bookkeeper/blob/fc51f73c/bookkeeper-stats-providers/twitter-science-provider/src/main/java/org/apache/bookkeeper/stats/twitter/science/TwitterStatsProvider.java
----------------------------------------------------------------------
diff --git a/bookkeeper-stats-providers/twitter-science-provider/src/main/java/org/apache/bookkeeper/stats/twitter/science/TwitterStatsProvider.java
b/bookkeeper-stats-providers/twitter-science-provider/src/main/java/org/apache/bookkeeper/stats/twitter/science/TwitterStatsProvider.java
index cc6e3f0..68d1ab1 100644
--- a/bookkeeper-stats-providers/twitter-science-provider/src/main/java/org/apache/bookkeeper/stats/twitter/science/TwitterStatsProvider.java
+++ b/bookkeeper-stats-providers/twitter-science-provider/src/main/java/org/apache/bookkeeper/stats/twitter/science/TwitterStatsProvider.java
@@ -16,6 +16,7 @@
  */
 package org.apache.bookkeeper.stats.twitter.science;
 
+import org.apache.bookkeeper.stats.CachingStatsProvider;
 import org.apache.bookkeeper.stats.StatsLogger;
 import org.apache.bookkeeper.stats.StatsProvider;
 import org.apache.commons.configuration.Configuration;
@@ -30,6 +31,27 @@ public class TwitterStatsProvider implements StatsProvider {
     protected final static String STATS_HTTP_PORT = "statsHttpPort";
 
     private HTTPStatsExporter statsExporter = null;
+    private final CachingStatsProvider cachingStatsProvider;
+
+    public TwitterStatsProvider() {
+        this.cachingStatsProvider = new CachingStatsProvider(new StatsProvider() {
+
+            @Override
+            public void start(Configuration conf) {
+                // nop
+            }
+
+            @Override
+            public void stop() {
+                // nop
+            }
+
+            @Override
+            public StatsLogger getStatsLogger(String scope) {
+                return new TwitterStatsLoggerImpl(scope);
+            }
+        });
+    }
 
     @Override
     public void start(Configuration conf) {
@@ -58,6 +80,6 @@ public class TwitterStatsProvider implements StatsProvider {
 
     @Override
     public StatsLogger getStatsLogger(String name) {
-        return new TwitterStatsLoggerImpl(name);
+        return this.cachingStatsProvider.getStatsLogger(name);
     }
 }

http://git-wip-us.apache.org/repos/asf/bookkeeper/blob/fc51f73c/bookkeeper-stats/src/main/java/org/apache/bookkeeper/stats/CachingStatsLogger.java
----------------------------------------------------------------------
diff --git a/bookkeeper-stats/src/main/java/org/apache/bookkeeper/stats/CachingStatsLogger.java
b/bookkeeper-stats/src/main/java/org/apache/bookkeeper/stats/CachingStatsLogger.java
new file mode 100644
index 0000000..ec553d9
--- /dev/null
+++ b/bookkeeper-stats/src/main/java/org/apache/bookkeeper/stats/CachingStatsLogger.java
@@ -0,0 +1,102 @@
+/**
+ * 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.bookkeeper.stats;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+public class CachingStatsLogger implements StatsLogger {
+
+    protected final StatsLogger underlying;
+    protected final ConcurrentMap<String, Counter> counters;
+    protected final ConcurrentMap<String, OpStatsLogger> opStatsLoggers;
+    protected final ConcurrentMap<String, StatsLogger> scopeStatsLoggers;
+
+    public CachingStatsLogger(StatsLogger statsLogger) {
+        this.underlying = statsLogger;
+        this.counters = new ConcurrentHashMap<String, Counter>();
+        this.opStatsLoggers = new ConcurrentHashMap<String, OpStatsLogger>();
+        this.scopeStatsLoggers = new ConcurrentHashMap<String, StatsLogger>();
+    }
+
+    @Override
+    public int hashCode() {
+        return underlying.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof CachingStatsLogger)) {
+            return false;
+        }
+        CachingStatsLogger another = (CachingStatsLogger) obj;
+        return underlying.equals(another.underlying);
+    }
+
+    @Override
+    public String toString() {
+        return underlying.toString();
+    }
+
+    @Override
+    public OpStatsLogger getOpStatsLogger(String name) {
+        OpStatsLogger opStatsLogger = opStatsLoggers.get(name);
+        if (null == opStatsLogger) {
+            OpStatsLogger newOpStatsLogger = underlying.getOpStatsLogger(name);
+            OpStatsLogger oldOpStatsLogger = opStatsLoggers.putIfAbsent(name, newOpStatsLogger);
+            opStatsLogger = (null == oldOpStatsLogger) ? newOpStatsLogger : oldOpStatsLogger;
+        }
+        return opStatsLogger;
+    }
+
+    @Override
+    public Counter getCounter(String name) {
+        Counter counter = counters.get(name);
+        if (null == counter) {
+            Counter newCounter = underlying.getCounter(name);
+            Counter oldCounter = counters.putIfAbsent(name, newCounter);
+            counter = (null == oldCounter) ? newCounter : oldCounter;
+        }
+        return counter;
+    }
+
+    @Override
+    public <T extends Number> void registerGauge(String name, Gauge<T> gauge)
{
+        underlying.registerGauge(name, gauge);
+    }
+
+    @Override
+    public <T extends Number> void unregisterGauge(String name, Gauge<T> gauge)
{
+        underlying.unregisterGauge(name, gauge);
+    }
+
+    @Override
+    public StatsLogger scope(String name) {
+        StatsLogger statsLogger = scopeStatsLoggers.get(name);
+        if (null == statsLogger) {
+            StatsLogger newStatsLogger = new CachingStatsLogger(underlying.scope(name));
+            StatsLogger oldStatsLogger = scopeStatsLoggers.putIfAbsent(name, newStatsLogger);
+            statsLogger = (null == oldStatsLogger) ? newStatsLogger : oldStatsLogger;
+        }
+        return statsLogger;
+    }
+
+    @Override
+    public void removeScope(String name, StatsLogger statsLogger) {
+        scopeStatsLoggers.remove(name, statsLogger);
+    }
+}

http://git-wip-us.apache.org/repos/asf/bookkeeper/blob/fc51f73c/bookkeeper-stats/src/main/java/org/apache/bookkeeper/stats/CachingStatsProvider.java
----------------------------------------------------------------------
diff --git a/bookkeeper-stats/src/main/java/org/apache/bookkeeper/stats/CachingStatsProvider.java
b/bookkeeper-stats/src/main/java/org/apache/bookkeeper/stats/CachingStatsProvider.java
new file mode 100644
index 0000000..609a258
--- /dev/null
+++ b/bookkeeper-stats/src/main/java/org/apache/bookkeeper/stats/CachingStatsProvider.java
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.bookkeeper.stats;
+
+import org.apache.commons.configuration.Configuration;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+public class CachingStatsProvider implements StatsProvider {
+
+    protected final StatsProvider underlying;
+    protected final ConcurrentMap<String, StatsLogger> statsLoggers;
+
+    public CachingStatsProvider(StatsProvider provider) {
+        this.underlying = provider;
+        this.statsLoggers = new ConcurrentHashMap<String, StatsLogger>();
+    }
+
+    @Override
+    public void start(Configuration conf) {
+        this.underlying.start(conf);
+    }
+
+    @Override
+    public void stop() {
+        this.underlying.stop();
+    }
+
+    @Override
+    public StatsLogger getStatsLogger(String scope) {
+        StatsLogger statsLogger = statsLoggers.get(scope);
+        if (null == statsLogger) {
+            StatsLogger newStatsLogger =
+                    new CachingStatsLogger(underlying.getStatsLogger(scope));
+            StatsLogger oldStatsLogger = statsLoggers.putIfAbsent(scope, newStatsLogger);
+            statsLogger = (null == oldStatsLogger) ? newStatsLogger : oldStatsLogger;
+        }
+        return statsLogger;
+    }
+}

http://git-wip-us.apache.org/repos/asf/bookkeeper/blob/fc51f73c/bookkeeper-stats/src/main/java/org/apache/bookkeeper/stats/NullStatsLogger.java
----------------------------------------------------------------------
diff --git a/bookkeeper-stats/src/main/java/org/apache/bookkeeper/stats/NullStatsLogger.java
b/bookkeeper-stats/src/main/java/org/apache/bookkeeper/stats/NullStatsLogger.java
index 3fc1049..10226b2 100644
--- a/bookkeeper-stats/src/main/java/org/apache/bookkeeper/stats/NullStatsLogger.java
+++ b/bookkeeper-stats/src/main/java/org/apache/bookkeeper/stats/NullStatsLogger.java
@@ -101,8 +101,17 @@ public class NullStatsLogger implements StatsLogger {
     }
 
     @Override
+    public <T extends Number> void unregisterGauge(String name, Gauge<T> gauge)
{
+        // nop
+    }
+
+    @Override
     public StatsLogger scope(String name) {
         return this;
     }
 
+    @Override
+    public void removeScope(String name, StatsLogger statsLogger) {
+        // nop
+    }
 }

http://git-wip-us.apache.org/repos/asf/bookkeeper/blob/fc51f73c/bookkeeper-stats/src/main/java/org/apache/bookkeeper/stats/StatsLogger.java
----------------------------------------------------------------------
diff --git a/bookkeeper-stats/src/main/java/org/apache/bookkeeper/stats/StatsLogger.java b/bookkeeper-stats/src/main/java/org/apache/bookkeeper/stats/StatsLogger.java
index f7791e8..7a32eae 100644
--- a/bookkeeper-stats/src/main/java/org/apache/bookkeeper/stats/StatsLogger.java
+++ b/bookkeeper-stats/src/main/java/org/apache/bookkeeper/stats/StatsLogger.java
@@ -36,14 +36,26 @@ public interface StatsLogger {
     public Counter getCounter(String name);
 
     /**
-     * Register given <i>guage</i> as name <i>name</i>.
+     * Register given <i>gauge</i> as name <i>name</i>.
      *
      * @param name
      *          gauge name
+     * @param gauge
+     *          gauge function
      */
     public <T extends Number> void registerGauge(String name, Gauge<T> gauge);
 
     /**
+     * Unregister given <i>gauge</i> from name <i>name</i>.
+     *
+     * @param name
+     *          name of the gauge
+     * @param gauge
+     *          gauge function
+     */
+    public <T extends Number> void unregisterGauge(String name, Gauge<T> gauge);
+
+    /**
      * Provide the stats logger under scope <i>name</i>.
      *
      * @param name
@@ -52,4 +64,13 @@ public interface StatsLogger {
      */
     public StatsLogger scope(String name);
 
+    /**
+     * Remove the given <i>statsLogger</i> for scope <i>name</i>.
+     * It can be no-op if the underlying stats provider doesn't have the ability to remove
scope.
+     *
+     * @param name name of the scope
+     * @param statsLogger the stats logger of this scope.
+     */
+    public void removeScope(String name, StatsLogger statsLogger);
+
 }

http://git-wip-us.apache.org/repos/asf/bookkeeper/blob/fc51f73c/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index e0f09b9..48233c3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -41,13 +41,13 @@
   <properties>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
-    <protobuf.version>2.6.1</protobuf.version>
     <guava.version>20.0</guava.version>
     <netty.version>4.1.10.Final</netty.version>
-    <zookeeper.version>3.5.1-alpha</zookeeper.version>
+    <protobuf.version>2.6.1</protobuf.version>
     <slf4j.version>1.7.25</slf4j.version>
+    <zookeeper.version>3.5.1-alpha</zookeeper.version>
   </properties>
-  <url>http://zookeeper.apache.org/bookkeeper</url>
+  <url>http://bookkeeper.apache.org</url>
   <build>
     <plugins>
       <plugin>


Mime
View raw message