package com.sohu.cache.web.controller; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; import org.apache.commons.lang.time.DateUtils; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import com.alibaba.fastjson.JSONObject; import com.sohu.cache.client.service.AppInstanceClientRelationService; import com.sohu.cache.client.service.ClientReportCostDistriService; import com.sohu.cache.client.service.ClientReportExceptionService; import com.sohu.cache.client.service.ClientReportValueDistriService; import com.sohu.cache.entity.AppClientCostTimeStat; import com.sohu.cache.entity.AppClientCostTimeTotalStat; import com.sohu.cache.entity.AppClientExceptionStat; import com.sohu.cache.entity.AppClientValueDistriSimple; import com.sohu.cache.entity.AppDesc; import com.sohu.cache.entity.AppInstanceClientRelation; import com.sohu.cache.entity.TimeBetween; import com.sohu.cache.stats.instance.InstanceStatsCenter; import com.sohu.cache.web.service.AppService; import com.sohu.cache.web.util.DateUtil; import com.sohu.cache.web.util.Page; import com.sohu.tv.jedis.stat.utils.NumberUtil; /** * 应用客户端统计相关 * * @author leifu * @Time 2014年8月31日 */ @Controller @RequestMapping("/client/show") public class AppClientDataShowController extends BaseController { /** * 客户端耗时服务 */ @Resource(name = "clientReportCostDistriService") private ClientReportCostDistriService clientReportCostDistriService; /** * 客户端异常服务 */ @Resource(name = "clientReportExceptionService") private ClientReportExceptionService clientReportExceptionService; /** * 客户端值分布服务 */ @Resource(name = "clientReportValueDistriService") private ClientReportValueDistriService clientReportValueDistriService; /** * 应用基本服务 */ @Resource(name = "appService") private AppService appService; /** * 实例信息 */ @Resource(name = "instanceStatsCenter") private InstanceStatsCenter instanceStatsCenter; /** * 应用下节点和客户端关系服务 */ @Resource(name = "appInstanceClientRelationService") private AppInstanceClientRelationService appInstanceClientRelationService; /** * 收集数据时间format */ private final static String COLLECT_TIME_FORMAT = "yyyyMMddHHmmss"; /** * 应用客户端统计首页 * * @param appId 应用id */ @RequestMapping("/index") public ModelAndView doIndex(HttpServletRequest request, HttpServletResponse response, Model model) { Long appId = NumberUtils.toLong(request.getParameter("appId")); if (appId == null || appId <= 0) { return new ModelAndView(""); } AppDesc appDesc = appService.getByAppId(appId); model.addAttribute("appId", appId); model.addAttribute("appDesc", appDesc); model.addAttribute("tabTag", request.getParameter("tabTag")); model.addAttribute("type", request.getParameter("type")); model.addAttribute("startDate", request.getParameter("startDate")); model.addAttribute("endDate", request.getParameter("endDate")); model.addAttribute("exceptionStartDate", request.getParameter("exceptionStartDate")); model.addAttribute("exceptionEndDate", request.getParameter("exceptionEndDate")); model.addAttribute("valueDistriStartDate", request.getParameter("valueDistriStartDate")); model.addAttribute("valueDistriEndDate", request.getParameter("valueDistriEndDate")); model.addAttribute("costDistriStartDate", request.getParameter("costDistriStartDate")); model.addAttribute("costDistriEndDate", request.getParameter("costDistriEndDate")); model.addAttribute("clientIp", request.getParameter("clientIp")); model.addAttribute("pageNo", request.getParameter("pageNo")); model.addAttribute("firstCommand", request.getParameter("firstCommand")); model.addAttribute("timeDimensionality", request.getParameter("timeDimensionality")); return new ModelAndView("client/appClientIndex"); } /** * 客户端异常查询 */ @RequestMapping("/exception") public ModelAndView doException(HttpServletRequest request, HttpServletResponse response, Model model) { // 1.1 应用信息 Long appId = NumberUtils.toLong(request.getParameter("appId")); if (appId <= 0) { return new ModelAndView(""); } AppDesc appDesc = appService.getByAppId(appId); model.addAttribute("appDesc", appDesc); // 1.2 异常类型 int type = NumberUtil.toInt(request.getParameter("type")); model.addAttribute("type", type); // 1.3 客户端ip String clientIp = request.getParameter("clientIp"); model.addAttribute("clientIp", clientIp); // 1.4 日期格式转换 TimeBetween timeBetween = new TimeBetween(); try { timeBetween = fillWithClientExceptionTime(request, model); } catch (ParseException e) { logger.error(e.getMessage(), e); } // 2. 分页查询异常 int totalCount = clientReportExceptionService.getAppExceptionCount(appId, timeBetween.getStartTime(), timeBetween.getEndTime(), type, clientIp); int pageNo = NumberUtils.toInt(request.getParameter("pageNo"), 1); int pageSize = NumberUtils.toInt(request.getParameter("pageSize"), 10); Page page = new Page(pageNo,pageSize, totalCount); model.addAttribute("page", page); List<AppClientExceptionStat> appClientExceptionList = clientReportExceptionService.getAppExceptionList(appId, timeBetween.getStartTime(), timeBetween.getEndTime(), type, clientIp, page); model.addAttribute("appClientExceptionList", appClientExceptionList); return new ModelAndView("client/clientException"); } /** * 异常查询日期格式 */ private TimeBetween fillWithClientExceptionTime(HttpServletRequest request, Model model) throws ParseException { final String exceptionDateFormat = "yyyy-MM-dd"; String exceptionStartDateParam = request.getParameter("exceptionStartDate"); String exceptionEndDateParam = request.getParameter("exceptionEndDate"); Date startDate; Date endDate; if (StringUtils.isBlank(exceptionStartDateParam) || StringUtils.isBlank(exceptionEndDateParam)) { // 如果为空默认取昨天和今天 SimpleDateFormat sdf = new SimpleDateFormat(exceptionDateFormat); startDate = sdf.parse(sdf.format(new Date())); endDate = DateUtils.addDays(startDate, 1); exceptionStartDateParam = DateUtil.formatDate(startDate, exceptionDateFormat); exceptionEndDateParam = DateUtil.formatDate(endDate, exceptionDateFormat); } else { endDate = DateUtil.parse(exceptionEndDateParam, exceptionDateFormat); startDate = DateUtil.parse(exceptionStartDateParam, exceptionDateFormat); //限制不能超过7天 if (endDate.getTime() - startDate.getTime() > TimeUnit.DAYS.toMillis(7)) { startDate = DateUtils.addDays(endDate, -7); } } // 前端需要 model.addAttribute("exceptionStartDate", exceptionStartDateParam); model.addAttribute("exceptionEndDate", exceptionEndDateParam); // 查询后台需要 long startTime = NumberUtils.toLong(DateUtil.formatDate(startDate, COLLECT_TIME_FORMAT)); long endTime = NumberUtils.toLong(DateUtil.formatDate(endDate, COLLECT_TIME_FORMAT)); return new TimeBetween(startTime, endTime, startDate, endDate); } /** * 应用客户端耗时统计 */ @RequestMapping("/costDistribute") public ModelAndView doCostDistribute(HttpServletRequest request, HttpServletResponse response, Model model) { // 1.应用信息 Long appId = NumberUtils.toLong(request.getParameter("appId")); if (appId <= 0) { return new ModelAndView(""); } AppDesc appDesc = appService.getByAppId(appId); model.addAttribute("appDesc", appDesc); model.addAttribute("appId", appId); // 2.获取时间区间 TimeBetween timeBetween = new TimeBetween(); try { timeBetween = fillWithCostDateFormat(request, model); } catch (ParseException e) { logger.error(e.getMessage(), e); } long startTime = timeBetween.getStartTime(); long endTime = timeBetween.getEndTime(); Date startDate = timeBetween.getStartDate(); // 3.所有命令和第一个命令 List<String> allCommands = clientReportCostDistriService.getAppDistinctCommand(appId, startTime, endTime); model.addAttribute("allCommands", allCommands); // 4.所有客户端和实例对应关系 List<AppInstanceClientRelation> appInstanceClientRelationList = appInstanceClientRelationService.getAppInstanceClientRelationList(appId, startDate); model.addAttribute("appInstanceClientRelationList", appInstanceClientRelationList); String firstCommand = request.getParameter("firstCommand"); if (StringUtils.isBlank(firstCommand) && CollectionUtils.isNotEmpty(allCommands)) { firstCommand = allCommands.get(0); model.addAttribute("firstCommand", firstCommand); } else { model.addAttribute("firstCommand", firstCommand); } // 5.1 应用下客户端和实例的全局耗时统计列表 List<AppClientCostTimeTotalStat> appChartStatList = clientReportCostDistriService.getAppClientCommandTotalStat(appId, firstCommand, startTime, endTime); Map<String, Object> resultMap = new HashMap<String, Object>(); // 5.2 简化字段 List<Map<String, Object>> app = new ArrayList<Map<String, Object>>(); for (AppClientCostTimeTotalStat appClientCostTimeTotalStat : appChartStatList) { Map<String, Object> map = new HashMap<String, Object>(); map.put("timeStamp", appClientCostTimeTotalStat.getTimeStamp()); map.put("count", appClientCostTimeTotalStat.getTotalCount()); map.put("mean", appClientCostTimeTotalStat.getMean()); map.put("median", appClientCostTimeTotalStat.getMedian()); map.put("max90", appClientCostTimeTotalStat.getNinetyPercentMax()); map.put("max99", appClientCostTimeTotalStat.getNinetyNinePercentMax()); map.put("max100", appClientCostTimeTotalStat.getHundredMax()); map.put("maxInst", appClientCostTimeTotalStat.getMaxInstanceHost() + ":" + appClientCostTimeTotalStat.getMaxInstancePort()); map.put("maxClient", appClientCostTimeTotalStat.getMaxClientIp()); app.add(map); } resultMap.put("app", app); model.addAttribute("appChartStatListJson", JSONObject.toJSONString(resultMap)); return new ModelAndView("client/clientCostDistribute"); } /** * 获取耗时时间区间 * @throws ParseException */ private TimeBetween fillWithCostDateFormat(HttpServletRequest request, Model model) throws ParseException { final String costDistriDateFormat = "yyyy-MM-dd"; String costDistriStartDateParam = request.getParameter("costDistriStartDate"); String costDistriEndDateParam = request.getParameter("costDistriEndDate"); Date startDate; Date endDate; if (StringUtils.isBlank(costDistriStartDateParam) || StringUtils.isBlank(costDistriEndDateParam)) { // 如果为空默认取昨天和今天 SimpleDateFormat sdf = new SimpleDateFormat(costDistriDateFormat); startDate = sdf.parse(sdf.format(new Date())); endDate = DateUtils.addDays(startDate, 1); costDistriStartDateParam = DateUtil.formatDate(startDate, costDistriDateFormat); costDistriEndDateParam = DateUtil.formatDate(endDate, costDistriDateFormat); } else { endDate = DateUtil.parse(costDistriEndDateParam, costDistriDateFormat); startDate = DateUtil.parse(costDistriStartDateParam, costDistriDateFormat); //限制不能超过1天 if (endDate.getTime() - startDate.getTime() > TimeUnit.DAYS.toMillis(1)) { startDate = DateUtils.addDays(endDate, -1); } } // 前端需要 model.addAttribute("costDistriStartDate", costDistriStartDateParam); model.addAttribute("costDistriEndDate", costDistriEndDateParam); // 查询后台需要 long startTime = NumberUtils.toLong(DateUtil.formatDate(startDate, COLLECT_TIME_FORMAT)); long endTime = NumberUtils.toLong(DateUtil.formatDate(endDate, COLLECT_TIME_FORMAT)); return new TimeBetween(startTime, endTime, startDate, endDate); } /** * 获取指定时间内某个命令某个客户端和实例的统计数据 * @param appId */ @RequestMapping("/getAppClientInstanceCommandCost") public ModelAndView doGetAppClientInstanceCommandCost(HttpServletRequest request, HttpServletResponse response, Model model) throws ParseException { final String costDistriDateFormat = "yyyy-MM-dd"; long appId = NumberUtils.toLong(request.getParameter("appId")); //时间转换 String costDistriStartDate = request.getParameter("costDistriStartDate"); String costDistriEndDate = request.getParameter("costDistriEndDate"); Date startDate = DateUtil.parse(costDistriStartDate, costDistriDateFormat); Date endDate = DateUtil.parse(costDistriEndDate, costDistriDateFormat); long startTime = NumberUtils.toLong(DateUtil.formatDate(startDate, COLLECT_TIME_FORMAT)); long endTime = NumberUtils.toLong(DateUtil.formatDate(endDate, COLLECT_TIME_FORMAT)); String firstCommand = request.getParameter("firstCommand"); long instanceId = NumberUtils.toLong(request.getParameter("instanceId")); String clientIp = request.getParameter("clientIp"); //客户端和实例统计 List<AppClientCostTimeStat> clientInstanceChartStatList = clientReportCostDistriService.getAppCommandClientToInstanceStat(appId, firstCommand, instanceId, clientIp, startTime, endTime); //缩减字段 List<Map<String, Object>> clientInstanceStat = new ArrayList<Map<String, Object>>(); for (AppClientCostTimeStat appClientCostTimeStat : clientInstanceChartStatList) { Map<String, Object> map = new HashMap<String, Object>(); map.put("timeStamp", appClientCostTimeStat.getTimeStamp()); map.put("count", appClientCostTimeStat.getCount()); map.put("mean", appClientCostTimeStat.getMean()); map.put("median", appClientCostTimeStat.getMedian()); map.put("max90", appClientCostTimeStat.getNinetyPercentMax()); map.put("max99", appClientCostTimeStat.getNinetyNinePercentMax()); map.put("max100", appClientCostTimeStat.getHundredMax()); clientInstanceStat.add(map); } //生成数据map json Map<String, Object> resultMap = new HashMap<String, Object>(); resultMap.put("clientInstanceStat", clientInstanceStat); sendMessage(response, JSONObject.toJSONString(resultMap)); return null; } /** * 应用客户端值分布相关 */ @RequestMapping("/valueDistribute") public ModelAndView doValueDistribute(HttpServletRequest request, HttpServletResponse response, Model model) throws ParseException { // 1.1 应用信息 Long appId = NumberUtils.toLong(request.getParameter("appId")); if (appId <= 0) { return new ModelAndView(""); } AppDesc appDesc = appService.getByAppId(appId); model.addAttribute("appDesc", appDesc); // 1.2 时间格式转换 TimeBetween timeBetween = new TimeBetween(); try { timeBetween = fillWithValueDistriTime(request, model); } catch (ParseException e) { logger.error(e.getMessage(), e); } long startTime = timeBetween.getStartTime(); long endTime = timeBetween.getEndTime(); //值分布列表 List<AppClientValueDistriSimple> appClientValueDistriSimpleList = clientReportValueDistriService.getAppValueDistriList(appId, startTime, endTime); model.addAttribute("appClientValueDistriSimpleList", appClientValueDistriSimpleList); //值分布json model.addAttribute("appClientValueDistriSimpleListJson", JSONObject.toJSONString(appClientValueDistriSimpleList)); return new ModelAndView("client/clientValueDistribute"); } /** * 值分布日期格式 */ private TimeBetween fillWithValueDistriTime(HttpServletRequest request, Model model) throws ParseException { final String valueDistriDateFormat = "yyyy-MM-dd"; String valueDistriStartDateParam = request.getParameter("valueDistriStartDate"); String valueDistriEndDateParam = request.getParameter("valueDistriEndDate"); Date startDate; Date endDate; if (StringUtils.isBlank(valueDistriStartDateParam) || StringUtils.isBlank(valueDistriEndDateParam)) { // 如果为空默认取昨天和今天 SimpleDateFormat sdf = new SimpleDateFormat(valueDistriDateFormat); startDate = sdf.parse(sdf.format(new Date())); endDate = DateUtils.addDays(startDate, 1); valueDistriStartDateParam = DateUtil.formatDate(startDate, valueDistriDateFormat); valueDistriEndDateParam = DateUtil.formatDate(endDate, valueDistriDateFormat); } else { endDate = DateUtil.parse(valueDistriEndDateParam, valueDistriDateFormat); startDate = DateUtil.parse(valueDistriStartDateParam, valueDistriDateFormat); //限制不能超过1天 if (endDate.getTime() - startDate.getTime() > TimeUnit.DAYS.toMillis(1)) { startDate = DateUtils.addDays(endDate, -1); } } // 前端需要 model.addAttribute("valueDistriStartDate", valueDistriStartDateParam); model.addAttribute("valueDistriEndDate", valueDistriEndDateParam); // 查询后台需要 long startTime = NumberUtils.toLong(DateUtil.formatDate(startDate, COLLECT_TIME_FORMAT)); long endTime = NumberUtils.toLong(DateUtil.formatDate(endDate, COLLECT_TIME_FORMAT)); return new TimeBetween(startTime, endTime, startDate, endDate); } }