/* * Copyright 1999-2018 Alibaba Group Holding Ltd. * * 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.alibaba.csp.sentinel.dashboard.controller; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; import com.alibaba.csp.sentinel.dashboard.domain.Result; import com.alibaba.csp.sentinel.dashboard.repository.metric.MetricsRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.alibaba.csp.sentinel.util.StringUtil; import com.alibaba.csp.sentinel.dashboard.datasource.entity.MetricEntity; import com.alibaba.csp.sentinel.dashboard.domain.vo.MetricVo; /** * @author leyou */ @Controller @RequestMapping(value = "/metric", produces = MediaType.APPLICATION_JSON_VALUE) public class MetricController { private static Logger logger = LoggerFactory.getLogger(MetricController.class); private static final long maxQueryIntervalMs = 1000 * 60 * 60; @Autowired private MetricsRepository metricStore; @ResponseBody @RequestMapping("/queryTopResourceMetric.json") public Result queryTopResourceMetric(final String app, Integer pageIndex, Integer pageSize, Boolean desc, Long startTime, Long endTime, String searchKey) { if (StringUtil.isEmpty(app)) { return Result.ofFail(-1, "app can't be null or empty"); } if (pageIndex == null || pageIndex <= 0) { pageIndex = 1; } if (pageSize == null) { pageSize = 6; } if (pageSize >= 20) { pageSize = 20; } if (desc == null) { desc = true; } if (endTime == null) { endTime = System.currentTimeMillis(); } if (startTime == null) { startTime = endTime - 1000 * 60 * 5; } if (endTime - startTime > maxQueryIntervalMs) { return Result.ofFail(-1, "time intervalMs is too big, must <= 1h"); } List resources = metricStore.listResourcesOfApp(app); logger.debug("queryTopResourceMetric(), resources.size()={}", resources.size()); if (resources == null || resources.isEmpty()) { return Result.ofSuccess(null); } if (!desc) { Collections.reverse(resources); } if (StringUtil.isNotEmpty(searchKey)) { List searched = new ArrayList<>(); for (String resource : resources) { if (resource.contains(searchKey)) { searched.add(resource); } } resources = searched; } int totalPage = (resources.size() + pageSize - 1) / pageSize; List topResource = new ArrayList<>(); if (pageIndex <= totalPage) { topResource = resources.subList((pageIndex - 1) * pageSize, Math.min(pageIndex * pageSize, resources.size())); } final Map> map = new ConcurrentHashMap<>(); logger.debug("topResource={}", topResource); long time = System.currentTimeMillis(); for (final String resource : topResource) { List entities = metricStore.queryByAppAndResourceBetween( app, resource, startTime, endTime); logger.debug("resource={}, entities.size()={}", resource, entities == null ? "null" : entities.size()); List vos = MetricVo.fromMetricEntities(entities, resource); Iterable vosSorted = sortMetricVoAndDistinct(vos); map.put(resource, vosSorted); } logger.debug("queryTopResourceMetric() total query time={} ms", System.currentTimeMillis() - time); Map resultMap = new HashMap<>(16); resultMap.put("totalCount", resources.size()); resultMap.put("totalPage", totalPage); resultMap.put("pageIndex", pageIndex); resultMap.put("pageSize", pageSize); Map> map2 = new LinkedHashMap<>(); // order matters. for (String identity : topResource) { map2.put(identity, map.get(identity)); } resultMap.put("metric", map2); return Result.ofSuccess(resultMap); } @ResponseBody @RequestMapping("/queryByAppAndResource.json") public Result queryByAppAndResource(String app, String identity, Long startTime, Long endTime) { if (StringUtil.isEmpty(app)) { return Result.ofFail(-1, "app can't be null or empty"); } if (StringUtil.isEmpty(identity)) { return Result.ofFail(-1, "identity can't be null or empty"); } if (endTime == null) { endTime = System.currentTimeMillis(); } if (startTime == null) { startTime = endTime - 1000 * 60; } if (endTime - startTime > maxQueryIntervalMs) { return Result.ofFail(-1, "time intervalMs is too big, must <= 1h"); } List entities = metricStore.queryByAppAndResourceBetween( app, identity, startTime, endTime); List vos = MetricVo.fromMetricEntities(entities, identity); return Result.ofSuccess(sortMetricVoAndDistinct(vos)); } private Iterable sortMetricVoAndDistinct(List vos) { if (vos == null) { return null; } Map map = new TreeMap<>(); for (MetricVo vo : vos) { MetricVo oldVo = map.get(vo.getTimestamp()); if (oldVo == null || vo.getGmtCreate() > oldVo.getGmtCreate()) { map.put(vo.getTimestamp(), vo); } } return map.values(); } }