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);
}
}