增加dashboard
This commit is contained in:
parent
aa997899b4
commit
76d8411139
|
|
@ -0,0 +1,95 @@
|
|||
# 仪表盘组件
|
||||
|
||||
获取所有类型
|
||||
|
||||
/dashboard/defs
|
||||
|
||||
[
|
||||
{
|
||||
"id":"system",
|
||||
"name":"系统",
|
||||
"objects":[
|
||||
{
|
||||
"id":"memory",
|
||||
"name":"内存""
|
||||
},
|
||||
{
|
||||
"id":"cpu",
|
||||
"name":"CPU""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
获取类型支持的指标和维度
|
||||
|
||||
/dashboard/类型/对象/指标
|
||||
|
||||
/dashboard/system/memory/measurements
|
||||
|
||||
[
|
||||
{
|
||||
"id":"max",
|
||||
"name":"最大值",
|
||||
"dimensions":[ //指标支持的维度
|
||||
{"id":"time-interval","name":"历史数据","params":{"properties":[ ... ]}},
|
||||
{"id":"real-time","name":"实时数据","params":{"properties":[ ... ]}}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id":"usage",
|
||||
"name":"已使用"
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
|
||||
POST /dashboard/system/memory/_batch
|
||||
|
||||
[
|
||||
{
|
||||
"measurement":"usage",
|
||||
"dimension":"time-interval",
|
||||
"params":{"interval":"1s"}
|
||||
},
|
||||
{
|
||||
"measurement":"max",
|
||||
"dimension":"time-interval",
|
||||
"params":{"interval":"1s"}
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
{
|
||||
"usage":[
|
||||
{
|
||||
"time":"15:00",
|
||||
"value":1.2
|
||||
},
|
||||
{
|
||||
"time":"16:00",
|
||||
"value":1.3
|
||||
}
|
||||
]
|
||||
,
|
||||
"max":[
|
||||
{
|
||||
"time":"15:00",
|
||||
"value":2
|
||||
},
|
||||
{
|
||||
"time":"16:00",
|
||||
"value":2
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
/dashboard/类型/对象/维度/指标?参数
|
||||
|
||||
GET /dashboard/device/property/temp/realTime?history=10
|
||||
|
||||
{
|
||||
"timestamp":1578914267417,
|
||||
"value":5.6
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>jetlinks-components</artifactId>
|
||||
<groupId>org.jetlinks.community</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>dashboard-components</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jetlinks</groupId>
|
||||
<artifactId>jetlinks-core</artifactId>
|
||||
<version>${jetlinks.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hswebframework</groupId>
|
||||
<artifactId>hsweb-easy-orm-rdb</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package org.jetlinks.community.dashboard;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 通用维度定义
|
||||
*
|
||||
* @author zhouhao
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum CommonDimensionDefinition implements DimensionDefinition {
|
||||
realTime("实时"),
|
||||
history("历史");
|
||||
|
||||
private String name;
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return name();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package org.jetlinks.community.dashboard;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 通用指标定义
|
||||
*
|
||||
* @author zhouhao
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum CommonMeasurementDefinition implements MeasurementDefinition {
|
||||
usage("使用率"),
|
||||
used("已使用"),
|
||||
info("明细"),
|
||||
max("最大值"),
|
||||
min("最小值"),
|
||||
avg("平均值");
|
||||
|
||||
private String name;
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return name();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package org.jetlinks.community.dashboard;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public interface Dashboard {
|
||||
|
||||
DashboardDefinition getDefinition();
|
||||
|
||||
Flux<DashboardObject> getObjects();
|
||||
|
||||
Mono<DashboardObject> getObject(String id);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package org.jetlinks.community.dashboard;
|
||||
|
||||
public interface DashboardDefinition extends Definition {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package org.jetlinks.community.dashboard;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public interface DashboardManager {
|
||||
|
||||
Flux<Dashboard> getDashboards();
|
||||
|
||||
Mono<Dashboard> getDashboard(String id);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package org.jetlinks.community.dashboard;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 仪表对象: CPU,内存
|
||||
*/
|
||||
public interface DashboardObject {
|
||||
|
||||
ObjectDefinition getDefinition();
|
||||
|
||||
Flux<Measurement> getMeasurements();
|
||||
|
||||
Mono<Measurement> getMeasurement(String id);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package org.jetlinks.community.dashboard;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.hswebframework.web.dict.EnumDict;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum DefaultDashboardDefinition implements DashboardDefinition, EnumDict<String> {
|
||||
|
||||
systemMonitor("系统监控")
|
||||
|
||||
;
|
||||
|
||||
private String name;
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package org.jetlinks.community.dashboard;
|
||||
|
||||
public interface Definition {
|
||||
String getId();
|
||||
|
||||
String getName();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package org.jetlinks.community.dashboard;
|
||||
|
||||
public interface DimensionDefinition extends Definition {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package org.jetlinks.community.dashboard;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 度量,指标. 如: 使用率
|
||||
*
|
||||
* @author zhouhao
|
||||
* @since 1.0
|
||||
*/
|
||||
public interface Measurement {
|
||||
|
||||
MeasurementDefinition getDefinition();
|
||||
|
||||
/**
|
||||
* 获取所有指标维度
|
||||
*
|
||||
* @return 维度
|
||||
*/
|
||||
Flux<MeasurementDimension> getDimensions();
|
||||
|
||||
/**
|
||||
* 获取指定ID的维度
|
||||
*
|
||||
* @param id 维度定义ID
|
||||
* @return 指定的维度, 不存在则返回 {@link Mono#empty()}
|
||||
*/
|
||||
Mono<MeasurementDimension> getDimension(String id);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package org.jetlinks.community.dashboard;
|
||||
|
||||
public interface MeasurementDefinition extends Definition {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package org.jetlinks.community.dashboard;
|
||||
|
||||
import org.jetlinks.core.metadata.ConfigMetadata;
|
||||
import org.jetlinks.core.metadata.DataType;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
/**
|
||||
* 指标维度,如: 每小时,服务器1
|
||||
* @author zhouhao
|
||||
*/
|
||||
public interface MeasurementDimension {
|
||||
|
||||
DimensionDefinition getDefinition();
|
||||
|
||||
DataType getValueType();
|
||||
|
||||
ConfigMetadata getParams();
|
||||
|
||||
boolean isRealTime();
|
||||
|
||||
Flux<MeasurementValue> getValue(MeasurementParameter parameter);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package org.jetlinks.community.dashboard;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.hswebframework.ezorm.core.param.QueryParam;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor(staticName = "of")
|
||||
@NoArgsConstructor
|
||||
public class MeasurementParameter {
|
||||
private Map<String,Object> params=new HashMap<>();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package org.jetlinks.community.dashboard;
|
||||
|
||||
public interface MeasurementValue {
|
||||
|
||||
Object getValue();
|
||||
|
||||
String getTimeString();
|
||||
|
||||
long getTimestamp();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package org.jetlinks.community.dashboard;
|
||||
|
||||
public interface ObjectDefinition extends Definition {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package org.jetlinks.community.dashboard;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@AllArgsConstructor(staticName = "of")
|
||||
@NoArgsConstructor
|
||||
public class SimpleMeasurementValue implements MeasurementValue {
|
||||
|
||||
private Object value;
|
||||
|
||||
private String timeString;
|
||||
|
||||
private long timestamp;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
package org.jetlinks.community.dashboard.measurements;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import org.hswebframework.utils.time.DateFormatter;
|
||||
import org.jetlinks.community.dashboard.*;
|
||||
import org.jetlinks.community.dashboard.supports.StaticMeasurement;
|
||||
import org.jetlinks.community.dashboard.supports.StaticMeasurementProvider;
|
||||
import org.jetlinks.core.metadata.ConfigMetadata;
|
||||
import org.jetlinks.core.metadata.DataType;
|
||||
import org.jetlinks.core.metadata.types.DoubleType;
|
||||
import org.jetlinks.core.metadata.unit.UnifyUnit;
|
||||
import org.springframework.stereotype.Component;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.OperatingSystemMXBean;
|
||||
import java.lang.reflect.Method;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import static java.math.BigDecimal.ROUND_HALF_UP;
|
||||
|
||||
/**
|
||||
* 实时CPU 使用率监控
|
||||
* <pre>
|
||||
* /dashboard/systemMonitor/cpu/usage/realTime
|
||||
* </pre>
|
||||
* @author zhouhao
|
||||
*/
|
||||
@Component
|
||||
public class SystemCpuMeasurementProvider
|
||||
extends StaticMeasurementProvider {
|
||||
|
||||
public SystemCpuMeasurementProvider() {
|
||||
super(DefaultDashboardDefinition.systemMonitor, SystemObjectDefinition.cpu);
|
||||
addMeasurement(cpuUseAgeMeasurement);
|
||||
}
|
||||
|
||||
static DataType type = new DoubleType().scale(1).min(0).max(100).unit(UnifyUnit.percent);
|
||||
|
||||
static StaticMeasurement cpuUseAgeMeasurement = new StaticMeasurement(CommonMeasurementDefinition.usage)
|
||||
.addDimension(new CpuRealTimeMeasurementDimension());
|
||||
|
||||
static OperatingSystemMXBean osMxBean = ManagementFactory.getOperatingSystemMXBean();
|
||||
|
||||
static Callable<Double> processCpuUsage;
|
||||
static Callable<Double> systemCpuUsage;
|
||||
|
||||
private static final List<String> OPERATING_SYSTEM_BEAN_CLASS_NAMES = Arrays.asList(
|
||||
"com.sun.management.OperatingSystemMXBean", // HotSpot
|
||||
"com.ibm.lang.management.OperatingSystemMXBean" // J9
|
||||
);
|
||||
|
||||
static {
|
||||
Class<?> mxBeanClass = null;
|
||||
for (String s : OPERATING_SYSTEM_BEAN_CLASS_NAMES) {
|
||||
try {
|
||||
mxBeanClass = Class.forName(s);
|
||||
} catch (Exception ignore) {
|
||||
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (mxBeanClass != null) {
|
||||
Method method = mxBeanClass.getMethod("getProcessCpuLoad");
|
||||
Method system = mxBeanClass.getMethod("getSystemCpuLoad");
|
||||
processCpuUsage = () -> (double) method.invoke(osMxBean);
|
||||
systemCpuUsage = () -> (double) system.invoke(osMxBean);
|
||||
} else {
|
||||
processCpuUsage = () -> 0D;
|
||||
systemCpuUsage = () -> 0D;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
static class CpuRealTimeMeasurementDimension implements MeasurementDimension {
|
||||
|
||||
@Override
|
||||
public DimensionDefinition getDefinition() {
|
||||
return CommonDimensionDefinition.realTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getValueType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigMetadata getParams() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRealTime() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public double getProcessCpu() {
|
||||
return processCpuUsage.call() * 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<MeasurementValue> getValue(MeasurementParameter parameter) {
|
||||
// TODO: 2020/1/15 性能优化
|
||||
return Flux.interval(Duration.ofSeconds(1))
|
||||
.map(t -> SimpleMeasurementValue.of(BigDecimal.valueOf(getProcessCpu()).setScale(1, ROUND_HALF_UP),
|
||||
DateFormatter.toString(new Date(), "HH:mm:ss"),
|
||||
System.currentTimeMillis()))
|
||||
.cast(MeasurementValue.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
package org.jetlinks.community.dashboard.measurements;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hswebframework.utils.time.DateFormatter;
|
||||
import org.jetlinks.community.dashboard.*;
|
||||
import org.jetlinks.community.dashboard.supports.StaticMeasurement;
|
||||
import org.jetlinks.community.dashboard.supports.StaticMeasurementProvider;
|
||||
import org.jetlinks.core.metadata.ConfigMetadata;
|
||||
import org.jetlinks.core.metadata.DataType;
|
||||
import org.jetlinks.core.metadata.SimplePropertyMetadata;
|
||||
import org.jetlinks.core.metadata.types.DoubleType;
|
||||
import org.jetlinks.core.metadata.types.LongType;
|
||||
import org.jetlinks.core.metadata.types.ObjectType;
|
||||
import org.springframework.stereotype.Component;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import java.lang.management.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Duration;
|
||||
import java.util.Date;
|
||||
|
||||
import static java.math.BigDecimal.ROUND_HALF_UP;
|
||||
|
||||
/**
|
||||
* 实时内存使用率监控
|
||||
* <pre>
|
||||
* /dashboard/systemMonitor/memory/info/realTime
|
||||
* </pre>
|
||||
*
|
||||
* @author zhouhao
|
||||
*/
|
||||
@Component
|
||||
public class SystemMemoryMeasurementProvider extends StaticMeasurementProvider {
|
||||
public SystemMemoryMeasurementProvider() {
|
||||
super(DefaultDashboardDefinition.systemMonitor, SystemObjectDefinition.memory);
|
||||
addMeasurement(jvmMemoryInfo);
|
||||
}
|
||||
|
||||
static ObjectType type = new ObjectType();
|
||||
|
||||
static {
|
||||
{
|
||||
SimplePropertyMetadata metadata = new SimplePropertyMetadata();
|
||||
metadata.setId("max");
|
||||
metadata.setName("最大值");
|
||||
metadata.setValueType(new LongType());
|
||||
type.addPropertyMetadata(metadata);
|
||||
}
|
||||
|
||||
{
|
||||
SimplePropertyMetadata metadata = new SimplePropertyMetadata();
|
||||
metadata.setId("used");
|
||||
metadata.setName("已使用");
|
||||
metadata.setValueType(new LongType());
|
||||
type.addPropertyMetadata(metadata);
|
||||
}
|
||||
|
||||
{
|
||||
SimplePropertyMetadata metadata = new SimplePropertyMetadata();
|
||||
metadata.setId("usage");
|
||||
metadata.setName("使用率");
|
||||
metadata.setValueType(new DoubleType());
|
||||
type.addPropertyMetadata(metadata);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static StaticMeasurement jvmMemoryInfo = new StaticMeasurement(CommonMeasurementDefinition.info)
|
||||
.addDimension(new JvmMemoryInfoDimension());
|
||||
|
||||
static class JvmMemoryInfoDimension implements MeasurementDimension {
|
||||
|
||||
MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
|
||||
|
||||
@Override
|
||||
public DimensionDefinition getDefinition() {
|
||||
return CommonDimensionDefinition.realTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getValueType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigMetadata getParams() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRealTime() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<MeasurementValue> getValue(MeasurementParameter parameter) {
|
||||
// TODO: 2020/1/15 性能优化
|
||||
return Flux.interval(Duration.ofSeconds(1))
|
||||
.map(t -> SimpleMeasurementValue.of(MemoryInfo.of(memoryMXBean.getHeapMemoryUsage()),
|
||||
DateFormatter.toString(new Date(), "HH:mm:ss"),
|
||||
System.currentTimeMillis()))
|
||||
.cast(MeasurementValue.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public static class MemoryInfo {
|
||||
private long max;
|
||||
|
||||
private long used;
|
||||
|
||||
private double usage;
|
||||
|
||||
public static MemoryInfo of(MemoryUsage usage) {
|
||||
MemoryInfo info = new MemoryInfo();
|
||||
info.max = (usage.getMax()) / 1000 / 1000;
|
||||
info.used = usage.getUsed() / 1000 / 1000;
|
||||
info.usage = BigDecimal.valueOf(((double) usage.getMax() / usage.getUsed()) / 100D).setScale(2, ROUND_HALF_UP)
|
||||
.doubleValue();
|
||||
return info;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package org.jetlinks.community.dashboard.measurements;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.jetlinks.community.dashboard.ObjectDefinition;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum SystemObjectDefinition implements ObjectDefinition {
|
||||
|
||||
cpu("CPU"),
|
||||
memory("内存");
|
||||
|
||||
private String name;
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return name();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package org.jetlinks.community.dashboard.supports;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.jetlinks.community.dashboard.Dashboard;
|
||||
import org.jetlinks.community.dashboard.DashboardDefinition;
|
||||
import org.jetlinks.community.dashboard.DashboardObject;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
class CompositeDashboard implements Dashboard {
|
||||
|
||||
@Getter
|
||||
private DashboardDefinition definition;
|
||||
|
||||
public CompositeDashboard(DashboardDefinition definition) {
|
||||
this.definition = definition;
|
||||
}
|
||||
|
||||
private Map<String, DashboardObject> staticObjects = new ConcurrentHashMap<>();
|
||||
|
||||
public void addProvider(MeasurementProvider provider) {
|
||||
|
||||
DashboardObject object = staticObjects.computeIfAbsent(provider.getObjectDefinition().getId(), __ -> new CompositeDashboardObject());
|
||||
if(object instanceof CompositeDashboardObject){
|
||||
CompositeDashboardObject compose = ((CompositeDashboardObject) object);
|
||||
compose.addProvider(provider);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void addObject(DashboardObject object) {
|
||||
staticObjects.put(object.getDefinition().getId(), object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<DashboardObject> getObjects() {
|
||||
return Flux.fromIterable(staticObjects.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<DashboardObject> getObject(String id) {
|
||||
return Mono.justOrEmpty(staticObjects.get(id));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package org.jetlinks.community.dashboard.supports;
|
||||
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.jetlinks.community.dashboard.DashboardObject;
|
||||
import org.jetlinks.community.dashboard.Measurement;
|
||||
import org.jetlinks.community.dashboard.ObjectDefinition;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
class CompositeDashboardObject implements DashboardObject {
|
||||
|
||||
private ObjectDefinition definition;
|
||||
|
||||
private List<MeasurementProvider> providers = new CopyOnWriteArrayList<>();
|
||||
|
||||
public void addProvider(MeasurementProvider provider) {
|
||||
if (definition == null) {
|
||||
definition = provider.getObjectDefinition();
|
||||
}
|
||||
providers.add(provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectDefinition getDefinition() {
|
||||
return definition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<Measurement> getMeasurements() {
|
||||
return Flux.fromIterable(providers)
|
||||
.flatMap(MeasurementProvider::getMeasurements);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Measurement> getMeasurement(String id) {
|
||||
return Flux.fromIterable(providers)
|
||||
.flatMap(provider -> provider.getMeasurement(id))
|
||||
.collectList()
|
||||
.filter(CollectionUtils::isNotEmpty)
|
||||
.map(CompositeMeasurement::new);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package org.jetlinks.community.dashboard.supports;
|
||||
|
||||
import org.jetlinks.community.dashboard.MeasurementDimension;
|
||||
import org.jetlinks.community.dashboard.Measurement;
|
||||
import org.jetlinks.community.dashboard.MeasurementDefinition;
|
||||
import org.springframework.util.Assert;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
class CompositeMeasurement implements Measurement {
|
||||
|
||||
private List<Measurement> measurements;
|
||||
|
||||
private Measurement main;
|
||||
|
||||
public CompositeMeasurement(List<Measurement> measurements) {
|
||||
Assert.notEmpty(measurements, "measurements can not be empty");
|
||||
this.measurements = measurements;
|
||||
this.main = measurements.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MeasurementDefinition getDefinition() {
|
||||
return main.getDefinition();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Flux<MeasurementDimension> getDimensions() {
|
||||
return Flux.fromIterable(measurements)
|
||||
.flatMap(Measurement::getDimensions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<MeasurementDimension> getDimension(String id) {
|
||||
return Flux.fromIterable(measurements)
|
||||
.flatMap(measurement -> measurement.getDimension(id))
|
||||
.next();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
package org.jetlinks.community.dashboard.supports;
|
||||
|
||||
import org.jetlinks.community.dashboard.DashboardDefinition;
|
||||
import org.jetlinks.community.dashboard.DashboardManager;
|
||||
import org.jetlinks.community.dashboard.Dashboard;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.stereotype.Component;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Component
|
||||
public class DefaultDashboardManager implements DashboardManager, BeanPostProcessor {
|
||||
|
||||
private Map<String, Dashboard> dashboards = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public Flux<Dashboard> getDashboards() {
|
||||
return Flux.fromIterable(dashboards.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Dashboard> getDashboard(String id) {
|
||||
return Mono.justOrEmpty(dashboards.get(id));
|
||||
}
|
||||
|
||||
|
||||
private void addProvider(MeasurementProvider provider) {
|
||||
|
||||
DashboardDefinition definition = provider.getDashboardDefinition();
|
||||
|
||||
Dashboard dashboard = dashboards.computeIfAbsent(definition.getId(), __ -> new CompositeDashboard(definition));
|
||||
|
||||
if (dashboard instanceof CompositeDashboard) {
|
||||
CompositeDashboard compose = ((CompositeDashboard) dashboard);
|
||||
compose.addProvider(provider);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("unsupported register dashboard object : " + provider);
|
||||
}
|
||||
}
|
||||
|
||||
private void addDashboard(Dashboard dashboard) {
|
||||
dashboards.put(dashboard.getDefinition().getId(), dashboard);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
|
||||
if (bean instanceof MeasurementProvider) {
|
||||
addProvider(((MeasurementProvider) bean));
|
||||
} else if (bean instanceof Dashboard) {
|
||||
addDashboard(((Dashboard) bean));
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package org.jetlinks.community.dashboard.supports;
|
||||
|
||||
import org.jetlinks.community.dashboard.*;
|
||||
import org.jetlinks.community.dashboard.measurements.SystemObjectDefinition;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public interface MeasurementProvider {
|
||||
|
||||
/**
|
||||
* @return 仪表定义
|
||||
* @see DefaultDashboardDefinition
|
||||
*/
|
||||
DashboardDefinition getDashboardDefinition();
|
||||
|
||||
/**
|
||||
* @return 对象定义
|
||||
* @see SystemObjectDefinition
|
||||
*/
|
||||
ObjectDefinition getObjectDefinition();
|
||||
|
||||
/**
|
||||
* @return 全部指标
|
||||
*/
|
||||
Flux<Measurement> getMeasurements();
|
||||
|
||||
/**
|
||||
* @param id 指标ID {@link Measurement#getDefinition()} {@link MeasurementDefinition#getId()}
|
||||
* @return 对应等指标, 不存在则返回 {@link Mono#empty()}
|
||||
* @see MeasurementDefinition
|
||||
*/
|
||||
Mono<Measurement> getMeasurement(String id);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package org.jetlinks.community.dashboard.supports;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.jetlinks.community.dashboard.Measurement;
|
||||
import org.jetlinks.community.dashboard.MeasurementDefinition;
|
||||
import org.jetlinks.community.dashboard.MeasurementDimension;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class StaticMeasurement implements Measurement {
|
||||
|
||||
@Getter
|
||||
private MeasurementDefinition definition;
|
||||
|
||||
|
||||
public StaticMeasurement(MeasurementDefinition definition) {
|
||||
this.definition = definition;
|
||||
}
|
||||
|
||||
private Map<String, MeasurementDimension> dimensions = new ConcurrentHashMap<>();
|
||||
|
||||
public StaticMeasurement addDimension(MeasurementDimension dimension) {
|
||||
|
||||
dimensions.put(dimension.getDefinition().getId(), dimension);
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<MeasurementDimension> getDimensions() {
|
||||
return Flux.fromIterable(dimensions.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<MeasurementDimension> getDimension(String id) {
|
||||
return Mono.justOrEmpty(dimensions.get(id));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package org.jetlinks.community.dashboard.supports;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.jetlinks.community.dashboard.DashboardDefinition;
|
||||
import org.jetlinks.community.dashboard.Measurement;
|
||||
import org.jetlinks.community.dashboard.ObjectDefinition;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public abstract class StaticMeasurementProvider implements MeasurementProvider {
|
||||
|
||||
private Map<String, Measurement> measurements = new ConcurrentHashMap<>();
|
||||
|
||||
@Getter
|
||||
private DashboardDefinition dashboardDefinition;
|
||||
@Getter
|
||||
private ObjectDefinition objectDefinition;
|
||||
|
||||
public StaticMeasurementProvider(DashboardDefinition dashboardDefinition,
|
||||
ObjectDefinition objectDefinition) {
|
||||
this.dashboardDefinition = dashboardDefinition;
|
||||
this.objectDefinition = objectDefinition;
|
||||
}
|
||||
|
||||
protected void addMeasurement(Measurement measurement) {
|
||||
measurements.put(measurement.getDefinition().getId(), measurement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<Measurement> getMeasurements() {
|
||||
return Flux.fromIterable(measurements.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Measurement> getMeasurement(String id) {
|
||||
return Mono.justOrEmpty(measurements.get(id));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
package org.jetlinks.community.dashboard.web;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import org.hswebframework.web.exception.NotFoundException;
|
||||
import org.jetlinks.community.dashboard.DashboardManager;
|
||||
import org.jetlinks.community.dashboard.DashboardObject;
|
||||
import org.jetlinks.community.dashboard.MeasurementParameter;
|
||||
import org.jetlinks.community.dashboard.MeasurementValue;
|
||||
import org.jetlinks.community.dashboard.web.response.DashboardMeasurementResponse;
|
||||
import org.jetlinks.community.dashboard.web.response.MeasurementInfo;
|
||||
import org.jetlinks.community.dashboard.web.request.DashboardMeasurementRequest;
|
||||
import org.jetlinks.community.dashboard.web.response.DashboardInfo;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/dashboard")
|
||||
public class DashboardController {
|
||||
|
||||
private final DashboardManager dashboardManager;
|
||||
|
||||
public DashboardController(DashboardManager dashboardManager) {
|
||||
this.dashboardManager = dashboardManager;
|
||||
}
|
||||
|
||||
@GetMapping("/defs")
|
||||
public Flux<DashboardInfo> getDefinitions() {
|
||||
return dashboardManager
|
||||
.getDashboards()
|
||||
.flatMap(DashboardInfo::of);
|
||||
}
|
||||
|
||||
@GetMapping("/def/{dashboard}/{object}/measurements")
|
||||
public Flux<MeasurementInfo> getMeasurementDefinitions(@PathVariable String dashboard,
|
||||
@PathVariable String object) {
|
||||
return dashboardManager
|
||||
.getDashboard(dashboard)
|
||||
.flatMap(dash -> dash.getObject(object))
|
||||
.flatMapMany(DashboardObject::getMeasurements)
|
||||
.flatMap(MeasurementInfo::of);
|
||||
}
|
||||
|
||||
@GetMapping(value = "/{dashboard}/{object}/{measurement}/{dimension}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||
public Flux<MeasurementValue> getMeasurementValue(@PathVariable String dashboard,
|
||||
@PathVariable String object,
|
||||
@PathVariable String dimension,
|
||||
@PathVariable String measurement,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
return dashboardManager
|
||||
.getDashboard(dashboard)
|
||||
.flatMap(dash -> dash.getObject(object))
|
||||
.flatMap(obj -> obj.getMeasurement(measurement))
|
||||
.flatMap(meas -> meas.getDimension(dimension))
|
||||
.switchIfEmpty(Mono.error(() -> new NotFoundException("不支持的仪表盘")))
|
||||
.flatMapMany(dim -> dim.getValue(MeasurementParameter.of(params)));
|
||||
}
|
||||
|
||||
@GetMapping(value = "/_multi", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||
public Flux<DashboardMeasurementResponse> getMultiMeasurementValue(@RequestParam String requestJson) {
|
||||
return Flux.fromIterable(JSON.parseArray(requestJson, DashboardMeasurementRequest.class))
|
||||
.flatMap(request -> dashboardManager
|
||||
.getDashboard(request.getDashboard())
|
||||
.flatMap(dash -> dash.getObject(request.getObject()))
|
||||
.flatMap(obj -> obj.getMeasurement(request.getMeasurement()))
|
||||
.flatMap(meas -> meas.getDimension(request.getDimension()))
|
||||
.flatMapMany(dim -> dim.getValue(MeasurementParameter.of(request.getParams())))
|
||||
.map(val -> DashboardMeasurementResponse.of(request.getGroup(), val)));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package org.jetlinks.community.dashboard.web.request;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class DashboardMeasurementRequest {
|
||||
|
||||
private String group;
|
||||
|
||||
private String dashboard;
|
||||
|
||||
private String object;
|
||||
|
||||
private String measurement;
|
||||
|
||||
private String dimension;
|
||||
|
||||
private Map<String,Object> params;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package org.jetlinks.community.dashboard.web.response;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.jetlinks.community.dashboard.Dashboard;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class DashboardInfo {
|
||||
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
private List<ObjectInfo> objects;
|
||||
|
||||
public static Mono<DashboardInfo> of(Dashboard dashboard) {
|
||||
return dashboard.getObjects()
|
||||
.map(ObjectInfo::of)
|
||||
.collectList()
|
||||
.map(list -> {
|
||||
DashboardInfo dashboardInfo = new DashboardInfo();
|
||||
dashboardInfo.setId(dashboard.getDefinition().getId());
|
||||
dashboardInfo.setName(dashboard.getDefinition().getName());
|
||||
dashboardInfo.setObjects(list);
|
||||
return dashboardInfo;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package org.jetlinks.community.dashboard.web.response;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.jetlinks.community.dashboard.MeasurementValue;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor(staticName = "of")
|
||||
@NoArgsConstructor
|
||||
public class DashboardMeasurementResponse {
|
||||
|
||||
private String group;
|
||||
|
||||
private MeasurementValue data;
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package org.jetlinks.community.dashboard.web.response;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.jetlinks.core.metadata.ConfigMetadata;
|
||||
import org.jetlinks.core.metadata.DataType;
|
||||
import org.jetlinks.community.dashboard.MeasurementDimension;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class DimensionInfo {
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
private DataType type;
|
||||
|
||||
private ConfigMetadata params;
|
||||
|
||||
public static DimensionInfo of(MeasurementDimension dimension){
|
||||
DimensionInfo dimensionInfo=new DimensionInfo();
|
||||
dimensionInfo.setId(dimension.getDefinition().getId());
|
||||
dimensionInfo.setName(dimension.getDefinition().getName());
|
||||
dimensionInfo.setParams(dimension.getParams());
|
||||
dimensionInfo.setType(dimension.getValueType());
|
||||
|
||||
return dimensionInfo;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package org.jetlinks.community.dashboard.web.response;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.jetlinks.core.metadata.DataType;
|
||||
import org.jetlinks.community.dashboard.Measurement;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class MeasurementInfo {
|
||||
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
private DataType type;
|
||||
|
||||
private List<DimensionInfo> dimensions;
|
||||
|
||||
public static Mono<MeasurementInfo> of(Measurement measurement){
|
||||
return measurement.getDimensions()
|
||||
.map(DimensionInfo::of)
|
||||
.collectList()
|
||||
.map(list->{
|
||||
MeasurementInfo info=new MeasurementInfo();
|
||||
info.setId(measurement.getDefinition().getId());
|
||||
info.setName(measurement.getDefinition().getName());
|
||||
info.setDimensions(list);
|
||||
return info;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package org.jetlinks.community.dashboard.web.response;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.jetlinks.community.dashboard.DashboardObject;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class ObjectInfo {
|
||||
|
||||
private String id;
|
||||
|
||||
private String name;
|
||||
|
||||
|
||||
public static ObjectInfo of(DashboardObject object){
|
||||
ObjectInfo objectInfo=new ObjectInfo();
|
||||
objectInfo.setName(object.getDefinition().getName());
|
||||
objectInfo.setId(object.getDefinition().getId());
|
||||
|
||||
return objectInfo;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -16,6 +16,8 @@
|
|||
<module>gateway-component</module>
|
||||
<module>io-component</module>
|
||||
<module>elasticsearch-component</module>
|
||||
<module>timeseries-components</module>
|
||||
<module>dashboard-components</module>
|
||||
</modules>
|
||||
|
||||
<artifactId>jetlinks-components</artifactId>
|
||||
|
|
|
|||
Loading…
Reference in New Issue