/* * Copyright 2012-2015, the original author or authors. * * Licensed 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 com.flipkart.phantom.runtime.impl.spring.web; import java.io.IOException; import java.io.StringWriter; import java.util.Map; import javax.servlet.http.HttpServletRequest; import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonGenerator; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import com.flipkart.phantom.runtime.impl.hystrix.HystrixMetricsAggregator; import com.flipkart.phantom.task.spi.AbstractHandler; /** * The <code>HystrixMetricsSnapshotController</code> is a controller for providing Hystrix snapshot metrics. * <p/> * Class summary from original source, modified suitably for package name changes: * <p/> * provides Hystrix metrics snapshot of last 10*N seconds as per configuration in * {@link com.flipkart.phantom.runtime.impl.hystrix.HystrixMetricsAggregator#frequency} in json format. * <p/> * Install by: * <p/> * 1) Including runtime-*.jar in your classpath. * <p/> * 2) Adding the following to controller-context.xml: * <pre>{@code * <bean class="com.flipkart.phantom.runtime.impl.spring.web.HystrixMetricsSnapshotController"> * <property name="hystrixMetricsAggregator" ref="hystrixMetricsAggregator"/> * </bean> * } </pre> * * @author Ishwar Kumar * @version 1.0, 15 Jan 2015 */ @Controller public class HystrixMetricsSnapshotController<T extends AbstractHandler> { /** * instance of aggregator which can be a thread based implementation in case of frequency > 1 * or else a stand alone implementation which just returns current metrics from HystrixCommandMetrics */ HystrixMetricsAggregator hystrixMetricsAggregator = null; /** * Controller for providing the last 10*N seconds metrics snapshot * @throws java.io.IOException * @return json response */ @RequestMapping(value = {"/hystrix.snapshot.global"}, method = RequestMethod.GET) public @ResponseBody String handleRequest(ModelMap model, HttpServletRequest request) throws IOException { final JsonFactory jsonFactory = new JsonFactory(); StringWriter responseJsonString = new StringWriter(); JsonGenerator responseJson = jsonFactory.createJsonGenerator(responseJsonString); responseJson.writeStartObject(); /* Get the metrics of last duration from Aggregator */ Map<String, Map<String, Map<String, Long>>> lastOneMinuteMetrics = hystrixMetricsAggregator.getMetricsSnapshotReporter().getMetricsLastDuration(); /* HystrixCommand value is an array of multiple objects; an object for each command */ responseJson.writeObjectFieldStart("HystrixCommand"); if (lastOneMinuteMetrics != null && lastOneMinuteMetrics.get("HystrixCommand") != null) { for (String commandName : lastOneMinuteMetrics.get("HystrixCommand").keySet()) { Map<String, Long> commandMetrics = lastOneMinuteMetrics.get("HystrixCommand").get(commandName); String a[] = commandName.split("\\."); responseJson.writeObjectFieldStart(commandName); responseJson.writeStringField("name", a[1]); responseJson.writeStringField("group", a[0]); responseJson.writeNumberField("errorCount", commandMetrics.get("errorCount")); responseJson.writeNumberField("requestCount", commandMetrics.get("requestCount")); if (commandMetrics.get("requestCount") > 0) responseJson.writeNumberField("errorPercent", 100.0 * commandMetrics.get("errorCount") / commandMetrics.get("requestCount")); else responseJson.writeNumberField("errorPercent", 0.); responseJson.writeNumberField("rollingCountFailure", commandMetrics.get("rollingCountFailure")); responseJson.writeNumberField("rollingCountSemaphoreRejected", commandMetrics.get("rollingCountSemaphoreRejected")); responseJson.writeNumberField("rollingCountShortCircuited", commandMetrics.get("rollingCountShortCircuited")); responseJson.writeNumberField("rollingCountThreadPoolRejected", commandMetrics.get("rollingCountThreadPoolRejected")); responseJson.writeNumberField("rollingCountSuccess", commandMetrics.get("rollingCountSuccess")); responseJson.writeNumberField("rollingCountTimeout", commandMetrics.get("rollingCountTimeout")); responseJson.writeNumberField("latencyTotal_mean", commandMetrics.get("latencyTotal_mean")); responseJson.writeObjectFieldStart("latencyTotal"); responseJson.writeNumberField("0", commandMetrics.get("0")); responseJson.writeNumberField("25", commandMetrics.get("25")); responseJson.writeNumberField("50", commandMetrics.get("50")); responseJson.writeNumberField("75", commandMetrics.get("75")); responseJson.writeNumberField("90", commandMetrics.get("90")); responseJson.writeNumberField("95", commandMetrics.get("95")); responseJson.writeNumberField("99", commandMetrics.get("99")); responseJson.writeNumberField("99.5", commandMetrics.get("99.5")); responseJson.writeNumberField("100", commandMetrics.get("100")); responseJson.writeEndObject(); responseJson.writeEndObject(); } } responseJson.writeEndObject(); responseJson.writeObjectFieldStart("HystrixThreadPool"); /* thread pool metrics: an array of multiple objects; an object for each method */ if (lastOneMinuteMetrics != null && lastOneMinuteMetrics.get("HystrixThreadPool") != null) { for (String commandName : lastOneMinuteMetrics.get("HystrixThreadPool").keySet()) { responseJson.writeObjectFieldStart(commandName); responseJson.writeStringField("name", commandName); responseJson.writeNumberField("currentActiveCount", lastOneMinuteMetrics.get("HystrixThreadPool").get(commandName).get("currentActiveCount")); responseJson.writeNumberField("currentQueueSize", lastOneMinuteMetrics.get("HystrixThreadPool").get(commandName).get("currentQueueSize")); responseJson.writeEndObject(); } } responseJson.writeEndObject(); responseJson.writeEndObject(); responseJson.close(); return responseJsonString.getBuffer().toString() + "\n"; } public void setHystrixMetricsAggregator(HystrixMetricsAggregator hystrixMetricsAggregator) { this.hystrixMetricsAggregator = hystrixMetricsAggregator; } }