/** * 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.camel.component.hystrix.metrics; import java.util.Queue; import java.util.concurrent.LinkedBlockingQueue; import java.util.stream.Stream; import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsPoller; import org.apache.camel.StaticService; import org.apache.camel.api.management.ManagedAttribute; import org.apache.camel.api.management.ManagedOperation; import org.apache.camel.api.management.ManagedResource; import org.apache.camel.component.hystrix.metrics.servlet.HystrixEventStreamServlet; import org.apache.camel.support.ServiceSupport; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * To gather hystrix metrics and offer the metrics over JMX and Java APIs. * <p/> * If you want to expose the metrics over HTTP then you can use the {@link HystrixEventStreamServlet} servlet which * provides such functionality. */ @ManagedResource(description = "Managed Hystrix EventStreamService") public class HystrixEventStreamService extends ServiceSupport implements StaticService, HystrixMetricsPoller.MetricsAsJsonPollerListener { public static final int METRICS_QUEUE_SIZE = 1000; private static final Logger LOG = LoggerFactory.getLogger(HystrixEventStreamService.class); private int delay = 500; private int queueSize = METRICS_QUEUE_SIZE; private HystrixMetricsPoller poller; // use a queue with a upper limit to avoid storing too many metrics private Queue<String> queue; public int getDelay() { return delay; } /** * Sets the delay in millis how often the poller runs */ public void setDelay(int delay) { this.delay = delay; } public int getQueueSize() { return queueSize; } /** * Sets the queue size for how many metrics collected are stored in-memory in a backlog */ public void setQueueSize(int queueSize) { this.queueSize = queueSize; } /** * Return a stream of the JSon metrics. */ public Stream<String> streamMetrics() { if (queue != null) { return queue.stream(); } else { return null; } } @ManagedOperation(description = "Returns the oldest metrics as JSon format") public String oldestMetricsAsJSon() { if (queue != null) { return queue.peek(); } else { return null; } } @ManagedOperation(description = "Starts the metrics poller") public void startPoller() { poller.start(); } @ManagedOperation(description = "Pauses the metrics poller") public void pausePoller() { poller.pause(); } @ManagedAttribute(description = "Is the metrics poller running") public boolean isPollerRunning() { return poller.isRunning(); } @ManagedAttribute(description = "The delay in millis the poller is running") public int getPollerDelay() { return delay; } @Override protected void doStart() throws Exception { LOG.info("Starting HystrixMetricsPoller with delay: {} and queue size: {}", delay, queueSize); queue = new LinkedBlockingQueue<String>(queueSize); poller = new HystrixMetricsPoller(this, delay); poller.start(); } @Override protected void doStop() throws Exception { if (poller != null) { LOG.info("Shutting down HystrixMetricsPoller"); poller.shutdown(); } } @Override public void handleJsonMetric(String json) { LOG.debug("handleJsonMetric: {}", json); // ensure there is space on the queue by polling until at least single slot is free int drain = queue.size() - queueSize + 1; if (drain > 0) { LOG.debug("Draining queue to make room: {}", drain); for (int i = 0; i < drain; i++) { queue.poll(); } } queue.add(json); } }