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) +