You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by rm...@apache.org on 2013/10/16 11:00:03 UTC

svn commit: r1532693 - in /commons/sandbox/monitoring/trunk: ./ cube/ cube/src/ cube/src/main/ cube/src/main/java/ cube/src/main/java/org/ cube/src/main/java/org/apache/ cube/src/main/java/org/apache/commons/ cube/src/main/java/org/apache/commons/monit...

Author: rmannibucau
Date: Wed Oct 16 09:00:02 2013
New Revision: 1532693

URL: http://svn.apache.org/r1532693
Log:
adding a cube module to push to square cube

Added:
    commons/sandbox/monitoring/trunk/cube/
    commons/sandbox/monitoring/trunk/cube/pom.xml
    commons/sandbox/monitoring/trunk/cube/src/
    commons/sandbox/monitoring/trunk/cube/src/main/
    commons/sandbox/monitoring/trunk/cube/src/main/java/
    commons/sandbox/monitoring/trunk/cube/src/main/java/org/
    commons/sandbox/monitoring/trunk/cube/src/main/java/org/apache/
    commons/sandbox/monitoring/trunk/cube/src/main/java/org/apache/commons/
    commons/sandbox/monitoring/trunk/cube/src/main/java/org/apache/commons/monitoring/
    commons/sandbox/monitoring/trunk/cube/src/main/java/org/apache/commons/monitoring/cube/
    commons/sandbox/monitoring/trunk/cube/src/main/java/org/apache/commons/monitoring/cube/Cube.java
    commons/sandbox/monitoring/trunk/cube/src/main/java/org/apache/commons/monitoring/cube/CubeBuilder.java
    commons/sandbox/monitoring/trunk/cube/src/main/java/org/apache/commons/monitoring/cube/CubeDataStore.java
    commons/sandbox/monitoring/trunk/cube/src/test/
    commons/sandbox/monitoring/trunk/cube/src/test/java/
    commons/sandbox/monitoring/trunk/cube/src/test/java/org/
    commons/sandbox/monitoring/trunk/cube/src/test/java/org/apache/
    commons/sandbox/monitoring/trunk/cube/src/test/java/org/apache/commons/
    commons/sandbox/monitoring/trunk/cube/src/test/java/org/apache/commons/monitoring/
    commons/sandbox/monitoring/trunk/cube/src/test/java/org/apache/commons/monitoring/cube/
    commons/sandbox/monitoring/trunk/cube/src/test/java/org/apache/commons/monitoring/cube/CubeDataStoreTest.java
    commons/sandbox/monitoring/trunk/cube/src/test/java/org/apache/commons/monitoring/cube/CubeServer.java
    commons/sandbox/monitoring/trunk/cube/src/test/java/org/apache/commons/monitoring/cube/gauge/
    commons/sandbox/monitoring/trunk/cube/src/test/java/org/apache/commons/monitoring/cube/gauge/MockGauge.java
    commons/sandbox/monitoring/trunk/cube/src/test/resources/
    commons/sandbox/monitoring/trunk/cube/src/test/resources/META-INF/
    commons/sandbox/monitoring/trunk/cube/src/test/resources/META-INF/services/
    commons/sandbox/monitoring/trunk/cube/src/test/resources/META-INF/services/org.apache.commons.monitoring.gauges.Gauge
    commons/sandbox/monitoring/trunk/cube/src/test/resources/commons-monitoring.properties
      - copied, changed from r1532645, commons/sandbox/monitoring/trunk/graphite/src/test/resources/commons-monitoring.properties
    commons/sandbox/monitoring/trunk/src/site/markdown/cube.md
      - copied, changed from r1532645, commons/sandbox/monitoring/trunk/src/site/markdown/graphite.md
Modified:
    commons/sandbox/monitoring/trunk/pom.xml
    commons/sandbox/monitoring/trunk/src/site/markdown/index.md

Added: commons/sandbox/monitoring/trunk/cube/pom.xml
URL: http://svn.apache.org/viewvc/commons/sandbox/monitoring/trunk/cube/pom.xml?rev=1532693&view=auto
==============================================================================
--- commons/sandbox/monitoring/trunk/cube/pom.xml (added)
+++ commons/sandbox/monitoring/trunk/cube/pom.xml Wed Oct 16 09:00:02 2013
@@ -0,0 +1,50 @@
+<?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">
+  <parent>
+    <artifactId>commons-monitoring-parent</artifactId>
+    <groupId>org.apache.commons.monitoring</groupId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>commons-monitoring-cube</artifactId>
+  <name>Commons Monitoring (Sandbox) :: Cube</name>
+  <description>A DataStore for https://github.com/square/cube</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.commons.monitoring</groupId>
+      <artifactId>commons-monitoring-core</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-codec-http</artifactId>
+      <version>4.0.9.Final</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+</project>

Added: commons/sandbox/monitoring/trunk/cube/src/main/java/org/apache/commons/monitoring/cube/Cube.java
URL: http://svn.apache.org/viewvc/commons/sandbox/monitoring/trunk/cube/src/main/java/org/apache/commons/monitoring/cube/Cube.java?rev=1532693&view=auto
==============================================================================
--- commons/sandbox/monitoring/trunk/cube/src/main/java/org/apache/commons/monitoring/cube/Cube.java (added)
+++ commons/sandbox/monitoring/trunk/cube/src/main/java/org/apache/commons/monitoring/cube/Cube.java Wed Oct 16 09:00:02 2013
@@ -0,0 +1,83 @@
+/*
+ * 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.commons.monitoring.cube;
+
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.URL;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class Cube {
+    private static final Logger LOGGER = Logger.getLogger(Cube.class.getName());
+
+    private static final String POST = "POST";
+    private static final String CONTENT_TYPE = "Content-Type";
+    private static final String CONTENT_LENGTH = "Content-Length";
+    private static final String APPLICATION_JSON = "application/json";
+
+    private final CubeBuilder config;
+    private final Proxy proxy;
+
+    public Cube(final CubeBuilder cubeBuilder) {
+        config = cubeBuilder;
+        if (config.getProxyHost() != null) {
+            proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(config.getProxyHost(), config.getProxyPort()));
+        } else {
+            proxy = Proxy.NO_PROXY;
+        }
+    }
+
+    public void post(final String payload) {
+        try {
+            final URL url = new URL(config.getCollector());
+
+            final HttpURLConnection connection = HttpURLConnection.class.cast(url.openConnection(proxy));
+            connection.setRequestMethod(POST);
+            connection.setRequestProperty(CONTENT_TYPE, APPLICATION_JSON);
+            connection.setRequestProperty(CONTENT_LENGTH, Long.toString(payload.length()));
+            connection.setUseCaches(false);
+            connection.setDoInput(true);
+            connection.setDoOutput(true);
+
+            try {
+                final OutputStream output = connection.getOutputStream();
+                try {
+                    output.write(payload.getBytes());
+                    output.flush();
+
+                    final int status = connection.getResponseCode();
+                    if (status / 100 != 2) {
+                        LOGGER.warning("Pushed data but response code is: " + status);
+                    }
+                } finally {
+                    if (output != null) {
+                        output.close();
+                    }
+                }
+            } finally {
+                if (connection != null) {
+                    connection.disconnect();
+                }
+            }
+        } catch (final Exception e) {
+            LOGGER.log(Level.WARNING, "Can't post data to collector", e);
+        }
+    }
+}

Added: commons/sandbox/monitoring/trunk/cube/src/main/java/org/apache/commons/monitoring/cube/CubeBuilder.java
URL: http://svn.apache.org/viewvc/commons/sandbox/monitoring/trunk/cube/src/main/java/org/apache/commons/monitoring/cube/CubeBuilder.java?rev=1532693&view=auto
==============================================================================
--- commons/sandbox/monitoring/trunk/cube/src/main/java/org/apache/commons/monitoring/cube/CubeBuilder.java (added)
+++ commons/sandbox/monitoring/trunk/cube/src/main/java/org/apache/commons/monitoring/cube/CubeBuilder.java Wed Oct 16 09:00:02 2013
@@ -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.commons.monitoring.cube;
+
+import org.apache.commons.monitoring.configuration.Configuration;
+
+@Configuration.AutoSet
+public class CubeBuilder {
+    private String proxyHost;
+    private int proxyPort;
+    private String collector;
+
+    public Cube build() {
+        return new Cube(this);
+    }
+
+    public String getProxyHost() {
+        return proxyHost;
+    }
+
+    public int getProxyPort() {
+        return proxyPort;
+    }
+
+    public String getCollector() {
+        return collector;
+    }
+
+    @Override
+    public String toString() {
+        return "CubeBuilder{" + collector + '}';
+    }
+}

Added: commons/sandbox/monitoring/trunk/cube/src/main/java/org/apache/commons/monitoring/cube/CubeDataStore.java
URL: http://svn.apache.org/viewvc/commons/sandbox/monitoring/trunk/cube/src/main/java/org/apache/commons/monitoring/cube/CubeDataStore.java?rev=1532693&view=auto
==============================================================================
--- commons/sandbox/monitoring/trunk/cube/src/main/java/org/apache/commons/monitoring/cube/CubeDataStore.java (added)
+++ commons/sandbox/monitoring/trunk/cube/src/main/java/org/apache/commons/monitoring/cube/CubeDataStore.java Wed Oct 16 09:00:02 2013
@@ -0,0 +1,165 @@
+/*
+ * 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.commons.monitoring.cube;
+
+import org.apache.commons.monitoring.Role;
+import org.apache.commons.monitoring.configuration.Configuration;
+import org.apache.commons.monitoring.counters.Counter;
+import org.apache.commons.monitoring.counters.MetricData;
+import org.apache.commons.monitoring.gauges.Gauge;
+import org.apache.commons.monitoring.repositories.Repository;
+import org.apache.commons.monitoring.store.BatchCounterDataStore;
+import org.apache.commons.monitoring.store.GaugeValuesRequest;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+
+public class CubeDataStore extends BatchCounterDataStore {
+    private static final String JSON_BASE = "{" +
+        "\"type\": \"%s\"," +
+        "\"time\": \"%s\"," +
+        "\"data\": %s" +
+        "}";
+
+    private static final String GAUGE_TYPE = "gauge";
+    private static final String COUNTER_TYPE = "counter";
+    private static final String JS_ISO_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
+    private static final String UTC = "UTC";
+
+    private final Cube cube = Configuration.findOrCreateInstance(CubeBuilder.class).build();
+
+    private final BlockingQueue<DateFormat> isoDateFormatters;
+
+    public CubeDataStore() {
+        final int maxConcurrency = 2 * Runtime.getRuntime().availableProcessors();
+        isoDateFormatters = new ArrayBlockingQueue<DateFormat>(maxConcurrency);
+        for (int i = 0; i < maxConcurrency; i++) {
+            isoDateFormatters.add(newIsoDateFormatter());
+        }
+    }
+
+    @Override
+    protected synchronized void pushCountersByBatch(final Repository instance) {
+        final long ts = System.currentTimeMillis();
+        final StringBuilder events = new StringBuilder();
+        for (final Counter counter : instance) {
+            final MapBuilder data = new MapBuilder()
+                .add("name", counter.getKey().getName())
+                .add("role", counter.getKey().getRole().getName());
+
+            for (final MetricData metric : MetricData.values()) {
+                final double value = metric.value(counter);
+                if (!Double.isNaN(value) && !Double.isInfinite(value)) {
+                    data.add(metric.name(), value);
+                }
+            }
+
+            buildEvent(events, COUNTER_TYPE, ts, data.map()).append(',');
+        }
+        if (events.length() > 0) {
+            events.setLength(events.length() - 1);
+            cube.post(finalPayload(events));
+        }
+    }
+
+    @Override
+    public void addToGauge(final Gauge gauge, final long time, final double value) {
+        final Role role = gauge.role();
+
+        cube.post(finalPayload(
+            buildEvent(new StringBuilder(), GAUGE_TYPE, time,
+                new MapBuilder()
+                    .add("value", value)
+                    .add("role", role.getName())
+                    .add("unit", role.getUnit().getName())
+                    .map())));
+    }
+
+    @Override
+    public Map<Long, Double> getGaugeValues(final GaugeValuesRequest gaugeValuesRequest) {
+        return Collections.emptyMap(); // TODO: maybe query cube?
+    }
+
+    private static String finalPayload(final StringBuilder events) {
+        return '[' + events.toString() + ']';
+    }
+
+    private StringBuilder buildEvent(final StringBuilder builder, final String type, final long time, final Map<String, Object> data) {
+        return builder.append(String.format(JSON_BASE, type, isoDate(time), buildData(data)));
+    }
+
+    private String isoDate(final long time) {
+        final Date date = new Date(time);
+
+        DateFormat formatter = null;
+        try {
+            formatter = isoDateFormatters.take();
+            return formatter.format(date);
+        } catch (final InterruptedException e) {
+            return newIsoDateFormatter().format(date);
+        } finally {
+            if (formatter != null) {
+                isoDateFormatters.add(formatter);
+            }
+        }
+    }
+
+    private static String buildData(final Map<String, Object> data) {
+        final StringBuilder builder = new StringBuilder().append("{");
+        for (final Map.Entry<String, Object> entry : data.entrySet()) {
+            builder.append('\"').append(entry.getKey()).append('\"').append(':');
+
+            final Object value = entry.getValue();
+            if (String.class.isInstance(value)) {
+                builder.append('\"').append(value).append('\"');
+            } else {
+                builder.append(value);
+            }
+
+            builder.append(',');
+        }
+        builder.setLength(builder.length() - 1);
+        return builder.append("}").toString();
+    }
+
+    private static DateFormat newIsoDateFormatter() {
+        final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(JS_ISO_FORMAT, Locale.ENGLISH);
+        simpleDateFormat.setTimeZone(TimeZone.getTimeZone(UTC));
+        return simpleDateFormat;
+    }
+
+    private static class MapBuilder {
+        private final Map<String, Object> map = new HashMap<String, Object>();
+
+        public MapBuilder add(final String key, final Object value) {
+            map.put(key, value);
+            return this;
+        }
+
+        public Map<String, Object> map() {
+            return map;
+        }
+    }
+}

Added: commons/sandbox/monitoring/trunk/cube/src/test/java/org/apache/commons/monitoring/cube/CubeDataStoreTest.java
URL: http://svn.apache.org/viewvc/commons/sandbox/monitoring/trunk/cube/src/test/java/org/apache/commons/monitoring/cube/CubeDataStoreTest.java?rev=1532693&view=auto
==============================================================================
--- commons/sandbox/monitoring/trunk/cube/src/test/java/org/apache/commons/monitoring/cube/CubeDataStoreTest.java (added)
+++ commons/sandbox/monitoring/trunk/cube/src/test/java/org/apache/commons/monitoring/cube/CubeDataStoreTest.java Wed Oct 16 09:00:02 2013
@@ -0,0 +1,90 @@
+/*
+ * 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.commons.monitoring.cube;
+
+import org.apache.commons.monitoring.Role;
+import org.apache.commons.monitoring.counters.Counter;
+import org.apache.commons.monitoring.gauges.Gauge;
+import org.apache.commons.monitoring.repositories.Repository;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+public class CubeDataStoreTest {
+    private CubeServer server;
+    private Gauge.LoaderHelper gauges;
+
+    @Before
+    public void startCube() throws IOException {
+        server = new CubeServer("localhost", 1234).start();
+        Repository.INSTANCE.clear();
+        gauges = new Gauge.LoaderHelper(false);
+    }
+
+    @After
+    public void stopCube() {
+        gauges.destroy();
+        Repository.INSTANCE.clear();
+        server.stop();
+    }
+
+    @Test
+    public void store() throws InterruptedException {
+        { // force some counter data
+            final Counter counter = Repository.INSTANCE.getCounter(new Counter.Key(Role.PERFORMANCES, "test"));
+            counter.add(1.4);
+            counter.add(1.6);
+            Thread.sleep(150);
+            counter.add(2.3);
+            counter.add(2.9);
+            Thread.sleep(150);
+        }
+
+        final Collection<String> messages = server.getMessages();
+        final Collection<String> gauges = new ArrayList<String>(4);
+        int counters = 0;
+        String aCounterMessage = null;
+        for (final String m : messages) {
+            if (m.contains("\"type\": \"gauge\"")) {
+                gauges.add(m.replaceAll("\"time\": \"[^\"]*\"", "\"time\": \"-\"")); // remove date to be able to test it easily
+            } else {
+                counters++;
+                aCounterMessage = m;
+            }
+        }
+
+        assertTrue(gauges.contains("[{\"type\": \"gauge\",\"time\": \"-\",\"data\": {\"unit\":\"u\",\"value\":0.0,\"role\":\"mock\"}}]"));
+        assertTrue(gauges.contains("[{\"type\": \"gauge\",\"time\": \"-\",\"data\": {\"unit\":\"u\",\"value\":1.0,\"role\":\"mock\"}}]"));
+        assertTrue(gauges.contains("[{\"type\": \"gauge\",\"time\": \"-\",\"data\": {\"unit\":\"u\",\"value\":2.0,\"role\":\"mock\"}}]"));
+        assertTrue(gauges.contains("[{\"type\": \"gauge\",\"time\": \"-\",\"data\": {\"unit\":\"u\",\"value\":3.0,\"role\":\"mock\"}}]"));
+
+        assertNotNull(aCounterMessage);
+        assertThat(aCounterMessage, containsString("Variance"));
+        assertThat(aCounterMessage, containsString("Value"));
+        assertThat(aCounterMessage, containsString("Hits"));
+        assertThat(aCounterMessage, containsString("Sum"));
+    }
+}

Added: commons/sandbox/monitoring/trunk/cube/src/test/java/org/apache/commons/monitoring/cube/CubeServer.java
URL: http://svn.apache.org/viewvc/commons/sandbox/monitoring/trunk/cube/src/test/java/org/apache/commons/monitoring/cube/CubeServer.java?rev=1532693&view=auto
==============================================================================
--- commons/sandbox/monitoring/trunk/cube/src/test/java/org/apache/commons/monitoring/cube/CubeServer.java (added)
+++ commons/sandbox/monitoring/trunk/cube/src/test/java/org/apache/commons/monitoring/cube/CubeServer.java Wed Oct 16 09:00:02 2013
@@ -0,0 +1,175 @@
+/*
+ * 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.commons.monitoring.cube;
+
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.handler.codec.http.DefaultFullHttpResponse;
+import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.HttpMethod;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.HttpRequestDecoder;
+import io.netty.handler.codec.http.HttpResponse;
+import io.netty.handler.codec.http.HttpResponseEncoder;
+import io.netty.handler.codec.http.HttpResponseStatus;
+import io.netty.handler.codec.http.HttpVersion;
+import io.netty.handler.stream.ChunkedWriteHandler;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class CubeServer {
+    private static final Logger LOGGER = Logger.getLogger(CubeServer.class.getName());
+
+    private final String host;
+    private final int port;
+
+    private NioEventLoopGroup workerGroup;
+    private final Collection<String> messages = new LinkedList<String>();
+
+    public CubeServer(final String host, final int port) {
+        this.host = host;
+        if (port <= 0) { // generate a port
+            this.port = findNextAvailablePort();
+        } else {
+            this.port = port;
+        }
+    }
+
+    public Collection<String> getMessages() {
+        synchronized (messages) {
+            return new ArrayList<String>(messages);
+        }
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    private static int findNextAvailablePort() {
+        ServerSocket serverSocket = null;
+        try {
+            serverSocket = new ServerSocket(0);
+            return serverSocket.getLocalPort();
+        } catch (final IOException e) {
+            LOGGER.log(Level.SEVERE, e.getMessage(), e);
+        } finally {
+            if (serverSocket != null) {
+                try {
+                    serverSocket.close();
+                } catch (final IOException e) {
+                    // no-op
+                }
+            }
+        }
+        return 0;
+    }
+
+    public CubeServer start() {
+        workerGroup = new NioEventLoopGroup(8);
+
+        try {
+            final ServerBootstrap bootstrap = new ServerBootstrap();
+            bootstrap
+                .option(ChannelOption.SO_REUSEADDR, true)
+                .option(ChannelOption.SO_SNDBUF, 1024)
+                .option(ChannelOption.TCP_NODELAY, true)
+                .group(workerGroup)
+                .channel(NioServerSocketChannel.class)
+                .childHandler(new Initializer(messages))
+                .bind(host, port).addListener(new ChannelFutureListener() {
+                @Override
+                public void operationComplete(final ChannelFuture future) throws Exception {
+                    if (!future.isSuccess()) {
+                        LOGGER.severe("Can't start HTTP server");
+                    } else {
+                        LOGGER.info(String.format("Server started on http://%s:%s", host, port));
+                    }
+                }
+            }).sync();
+        } catch (final InterruptedException e) {
+            LOGGER.log(Level.SEVERE, e.getMessage(), e);
+        }
+
+        return this;
+    }
+
+    public void stop() {
+        if (workerGroup != null) {
+            workerGroup.shutdownGracefully();
+            LOGGER.info(String.format("Server http://%s:%s stopped", host, port));
+        }
+    }
+
+    private static class Initializer extends ChannelInitializer<SocketChannel> {
+        private final Collection<String> messages;
+
+        private Initializer(final Collection<String> messages) {
+            this.messages = messages;
+        }
+
+        @Override
+        protected void initChannel(final SocketChannel ch) throws Exception {
+            final ChannelPipeline pipeline = ch.pipeline();
+
+            pipeline
+                .addLast("decoder", new HttpRequestDecoder())
+                .addLast("aggregator", new HttpObjectAggregator(Integer.MAX_VALUE))
+                .addLast("encoder", new HttpResponseEncoder())
+                .addLast("chunked-writer", new ChunkedWriteHandler())
+                .addLast("featured-mock-server", new RequestHandler(messages));
+        }
+    }
+
+    private static class RequestHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
+        private final Collection<String> messages;
+
+        private RequestHandler(final Collection<String> messages) {
+            this.messages = messages;
+        }
+
+        @Override
+        protected void channelRead0(final ChannelHandlerContext ctx, final FullHttpRequest fullHttpRequest) throws Exception {
+            final ChannelFuture future;
+            if (HttpMethod.POST.equals(fullHttpRequest.getMethod())) {
+                synchronized (messages) {
+                    messages.add(new String(fullHttpRequest.content().array()));
+                }
+                final HttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
+                future = ctx.writeAndFlush(response);
+            } else {
+                LOGGER.warning("Received " + fullHttpRequest.getMethod());
+                future = ctx.writeAndFlush(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR));
+            }
+            future.addListener(ChannelFutureListener.CLOSE);
+        }
+    }
+}
\ No newline at end of file

Added: commons/sandbox/monitoring/trunk/cube/src/test/java/org/apache/commons/monitoring/cube/gauge/MockGauge.java
URL: http://svn.apache.org/viewvc/commons/sandbox/monitoring/trunk/cube/src/test/java/org/apache/commons/monitoring/cube/gauge/MockGauge.java?rev=1532693&view=auto
==============================================================================
--- commons/sandbox/monitoring/trunk/cube/src/test/java/org/apache/commons/monitoring/cube/gauge/MockGauge.java (added)
+++ commons/sandbox/monitoring/trunk/cube/src/test/java/org/apache/commons/monitoring/cube/gauge/MockGauge.java Wed Oct 16 09:00:02 2013
@@ -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.commons.monitoring.cube.gauge;
+
+import org.apache.commons.monitoring.Role;
+import org.apache.commons.monitoring.counters.Unit;
+import org.apache.commons.monitoring.gauges.Gauge;
+
+public class MockGauge implements Gauge {
+    public static final Role MOCK = new Role("mock", Unit.UNARY);
+
+    private int count = 0;
+
+    @Override
+    public Role role() {
+        return MOCK;
+    }
+
+    @Override
+    public double value() {
+        return count++;
+    }
+
+    @Override
+    public long period() {
+        return 100;
+    }
+}

Added: commons/sandbox/monitoring/trunk/cube/src/test/resources/META-INF/services/org.apache.commons.monitoring.gauges.Gauge
URL: http://svn.apache.org/viewvc/commons/sandbox/monitoring/trunk/cube/src/test/resources/META-INF/services/org.apache.commons.monitoring.gauges.Gauge?rev=1532693&view=auto
==============================================================================
--- commons/sandbox/monitoring/trunk/cube/src/test/resources/META-INF/services/org.apache.commons.monitoring.gauges.Gauge (added)
+++ commons/sandbox/monitoring/trunk/cube/src/test/resources/META-INF/services/org.apache.commons.monitoring.gauges.Gauge Wed Oct 16 09:00:02 2013
@@ -0,0 +1 @@
+org.apache.commons.monitoring.cube.gauge.MockGauge

Copied: commons/sandbox/monitoring/trunk/cube/src/test/resources/commons-monitoring.properties (from r1532645, commons/sandbox/monitoring/trunk/graphite/src/test/resources/commons-monitoring.properties)
URL: http://svn.apache.org/viewvc/commons/sandbox/monitoring/trunk/cube/src/test/resources/commons-monitoring.properties?p2=commons/sandbox/monitoring/trunk/cube/src/test/resources/commons-monitoring.properties&p1=commons/sandbox/monitoring/trunk/graphite/src/test/resources/commons-monitoring.properties&r1=1532645&r2=1532693&rev=1532693&view=diff
==============================================================================
--- commons/sandbox/monitoring/trunk/graphite/src/test/resources/commons-monitoring.properties (original)
+++ commons/sandbox/monitoring/trunk/cube/src/test/resources/commons-monitoring.properties Wed Oct 16 09:00:02 2013
@@ -14,9 +14,6 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-org.apache.commons.monitoring.store.DataStore = org.apache.commons.monitoring.graphite.GraphiteDataStore
-
-org.apache.commons.monitoring.graphite.period = 100
-
-org.apache.commons.monitoring.graphite.GraphiteBuilder.address = localhost
-org.apache.commons.monitoring.graphite.GraphiteBuilder.port = 1234
+org.apache.commons.monitoring.store.DataStore = org.apache.commons.monitoring.cube.CubeDataStore
+org.apache.commons.monitoring.cube.period = 100
+org.apache.commons.monitoring.cube.CubeBuilder.collector = http://localhost:1234/collector/1.0/event/put

Modified: commons/sandbox/monitoring/trunk/pom.xml
URL: http://svn.apache.org/viewvc/commons/sandbox/monitoring/trunk/pom.xml?rev=1532693&r1=1532692&r2=1532693&view=diff
==============================================================================
--- commons/sandbox/monitoring/trunk/pom.xml (original)
+++ commons/sandbox/monitoring/trunk/pom.xml Wed Oct 16 09:00:02 2013
@@ -56,6 +56,7 @@
     <module>web</module>
     <module>reporting</module>
     <module>graphite</module>
+    <module>cube</module>
   </modules>
 
   <developers>

Copied: commons/sandbox/monitoring/trunk/src/site/markdown/cube.md (from r1532645, commons/sandbox/monitoring/trunk/src/site/markdown/graphite.md)
URL: http://svn.apache.org/viewvc/commons/sandbox/monitoring/trunk/src/site/markdown/cube.md?p2=commons/sandbox/monitoring/trunk/src/site/markdown/cube.md&p1=commons/sandbox/monitoring/trunk/src/site/markdown/graphite.md&r1=1532645&r2=1532693&rev=1532693&view=diff
==============================================================================
--- commons/sandbox/monitoring/trunk/src/site/markdown/graphite.md (original)
+++ commons/sandbox/monitoring/trunk/src/site/markdown/cube.md Wed Oct 16 09:00:02 2013
@@ -16,38 +16,42 @@ KIND, either express or implied.  See th
 specific language governing permissions and limitations
 under the License.
 -->
-# Graphite
+# Cube
 
-Graphite module allows to push counters and gauges to a graphite instance.
+Cube module allows to push counters and gauges to a Square Cube instance (see [Cube github wiki](https://github.com/square/cube/wiki)).
 
 ## Configuration
 
-* `org.apache.commons.monitoring.graphite.GraphiteBuilder.address`: the graphite instance host/IP
-* `org.apache.commons.monitoring.graphite.GraphiteBuilder.port`: the graphite instance port
-* `org.apache.commons.monitoring.graphite.GraphiteBuilder.charset`: the charset to use with this Graphite instance
+org.apache.commons.monitoring.store.DataStore = org.apache.commons.monitoring.cube.CubeDataStore
+org.apache.commons.monitoring.cube.period = 100
+org.apache.commons.monitoring.cube.CubeBuilder.collector = http://localhost:1234/collector/1.0/event/put
+* `org.apache.commons.monitoring.cube.CubeBuilder.collector`: the cube event collector address (`http://xxx:1234/collector/1.0/event/put` for instance)
+* `org.apache.commons.monitoring.cube.CubeBuilder.proxyHost`: optionally a proxy host
+* `org.apache.commons.monitoring.cube.CubeBuilder.proxyPort`: optionally a proxy port
 
 For instance your `commons-monitoring.properties` can look like:
 
 ```
-org.apache.commons.monitoring.graphite.GraphiteBuilder.address = localhost
-org.apache.commons.monitoring.graphite.GraphiteBuilder.port = 1234
+org.apache.commons.monitoring.cube.CubeBuilder.collector = http://localhost:1234/collector/1.0/event/put
 ```
+
 ## DataStore
 
-To push metrics (Gauges + Counters) to Graphite you can use the dedicated `DataStore`: `org.apache.commons.monitoring.graphite.GraphiteDataStore`.
+To push metrics (Gauges + Counters) to Graphite you can use the dedicated `DataStore`: `org.apache.commons.monitoring.cube.CubeDataStore`.
 
 Simply add to `commons-monitoring.properties` the line:
 
 ```
-org.apache.commons.monitoring.store.DataStore = org.apache.commons.monitoring.graphite.GraphiteDataStore
+org.apache.commons.monitoring.store.DataStore = org.apache.commons.monitoring.cube.CubeDataStore
 ```
 
 ### Counters
 
 You can also configure the period used to flush counters values:
 
-* `org.apache.commons.monitoring.graphite.period`: which period to use to push counters data to Graphite (default to 1mn).
+* `org.apache.commons.monitoring.cube.period`: which period to use to push counters data to Graphite (default to 1mn).
+
+## Limitations (ATM)
 
-## Limitations
+When using CubeDataStore you cannot retrieve locally gauges values (you are expected to use Cube for it).
 
-When using GraphiteDataStore you cannot retrieve locally gauges values (you are expected to use Graphite for it).

Modified: commons/sandbox/monitoring/trunk/src/site/markdown/index.md
URL: http://svn.apache.org/viewvc/commons/sandbox/monitoring/trunk/src/site/markdown/index.md?rev=1532693&r1=1532692&r2=1532693&view=diff
==============================================================================
--- commons/sandbox/monitoring/trunk/src/site/markdown/index.md (original)
+++ commons/sandbox/monitoring/trunk/src/site/markdown/index.md Wed Oct 16 09:00:02 2013
@@ -38,4 +38,8 @@ How to start?
 
 [See Web](./web.html)
 
+[See Graphite](./graphite.html)
+
+[See Cube](./cube.html)
+