/*
|
* 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<MetricEntity> 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<String> 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<String> searched = new ArrayList<>();
|
for (String resource : resources) {
|
if (resource.contains(searchKey)) {
|
searched.add(resource);
|
}
|
}
|
resources = searched;
|
}
|
int totalPage = (resources.size() + pageSize - 1) / pageSize;
|
List<String> topResource = new ArrayList<>();
|
if (pageIndex <= totalPage) {
|
topResource = resources.subList((pageIndex - 1) * pageSize,
|
Math.min(pageIndex * pageSize, resources.size()));
|
}
|
final Map<String, Iterable<MetricVo>> map = new ConcurrentHashMap<>();
|
logger.debug("topResource={}", topResource);
|
long time = System.currentTimeMillis();
|
for (final String resource : topResource) {
|
List<MetricEntity> entities = metricStore.queryByAppAndResourceBetween(
|
app, resource, startTime, endTime);
|
logger.debug("resource={}, entities.size()={}", resource, entities == null ? "null" : entities.size());
|
List<MetricVo> vos = MetricVo.fromMetricEntities(entities, resource);
|
Iterable<MetricVo> vosSorted = sortMetricVoAndDistinct(vos);
|
map.put(resource, vosSorted);
|
}
|
logger.debug("queryTopResourceMetric() total query time={} ms", System.currentTimeMillis() - time);
|
Map<String, Object> resultMap = new HashMap<>(16);
|
resultMap.put("totalCount", resources.size());
|
resultMap.put("totalPage", totalPage);
|
resultMap.put("pageIndex", pageIndex);
|
resultMap.put("pageSize", pageSize);
|
|
Map<String, Iterable<MetricVo>> 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<MetricEntity> entities = metricStore.queryByAppAndResourceBetween(
|
app, identity, startTime, endTime);
|
List<MetricVo> vos = MetricVo.fromMetricEntities(entities, identity);
|
return Result.ofSuccess(sortMetricVoAndDistinct(vos));
|
}
|
|
private Iterable<MetricVo> sortMetricVoAndDistinct(List<MetricVo> vos) {
|
if (vos == null) {
|
return null;
|
}
|
Map<Long, MetricVo> 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();
|
}
|
}
|