mirror of
https://github.com/dromara/hertzbeat.git
synced 2026-09-17 09:40:58 +00:00
[Feature] Supports Bulletin to view all metrics. (#2584)
Signed-off-by: tomsun28 <tomsun28@outlook.com> Co-authored-by: YuLuo <yuluo08290126@gmail.com> Co-authored-by: tomsun28 <tomsun28@outlook.com> Co-authored-by: kerwin612 <kerwin612@qq.com>
This commit is contained in:
co-authored by
YuLuo
tomsun28
kerwin612
parent
5eef247a5b
commit
5d416e855b
@@ -139,14 +139,14 @@ public class Monitor {
|
||||
/**
|
||||
* Record create time
|
||||
*/
|
||||
@Schema(title = "Record create time", example = "1612198922000", accessMode = READ_ONLY)
|
||||
@Schema(title = "Record create time", example = "2024-07-02T20:09:34.903217", accessMode = READ_ONLY)
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
/**
|
||||
* Record the latest modification time (timestamp in milliseconds)
|
||||
*/
|
||||
@Schema(title = "Record modify time", example = "1612198444000", accessMode = READ_ONLY)
|
||||
@Schema(title = "Record modify time", example = "2024-07-02T20:09:34.903217", accessMode = READ_ONLY)
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
|
||||
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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 org.apache.hertzbeat.common.entity.manager.bulletin;
|
||||
|
||||
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_WRITE;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Convert;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.hertzbeat.common.entity.manager.JsonLongListAttributeConverter;
|
||||
import org.apache.hertzbeat.common.entity.manager.JsonTagListAttributeConverter;
|
||||
import org.apache.hertzbeat.common.entity.manager.TagItem;
|
||||
import org.springframework.data.annotation.CreatedBy;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
import org.springframework.data.annotation.LastModifiedBy;
|
||||
import org.springframework.data.annotation.LastModifiedDate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
/**
|
||||
* Bulletin
|
||||
*/
|
||||
@Entity
|
||||
@Data
|
||||
@Schema(description = "Bulletin")
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
@Table(name = "hzb_bulletin")
|
||||
public class Bulletin {
|
||||
|
||||
@Id
|
||||
@Schema(description = "Bulletin ID", example = "1")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "Bulletin Name", example = "Bulletin1", accessMode = READ_WRITE)
|
||||
private String name;
|
||||
|
||||
@Schema(description = "Monitor IDs", example = "1")
|
||||
@Column(name = "monitor_ids", length = 5000)
|
||||
@Convert(converter = JsonLongListAttributeConverter.class)
|
||||
private List<Long> monitorIds;
|
||||
|
||||
@Schema(description = "Monitor Type eg: jvm, tomcat", example = "jvm", accessMode = READ_WRITE)
|
||||
private String app;
|
||||
|
||||
|
||||
@Schema(description = "Monitor Fields")
|
||||
@Column(length = 4096, columnDefinition = "json")
|
||||
private String fields;
|
||||
|
||||
@Schema(description = "Tags(status:success,env:prod)", example = "{name: key1, value: value1}",
|
||||
accessMode = READ_WRITE)
|
||||
@Convert(converter = JsonTagListAttributeConverter.class)
|
||||
@Column(length = 2048)
|
||||
private List<TagItem> tags;
|
||||
|
||||
@Schema(title = "The creator of this record", example = "tom", accessMode = READ_WRITE)
|
||||
@CreatedBy
|
||||
private String creator;
|
||||
|
||||
@Schema(title = "The modifier of this record", example = "tom", accessMode = READ_WRITE)
|
||||
@LastModifiedBy
|
||||
private String modifier;
|
||||
|
||||
@Schema(title = "Record create time", example = "2024-07-02T20:09:34.903217", accessMode = READ_WRITE)
|
||||
@CreatedDate
|
||||
private LocalDateTime gmtCreate;
|
||||
|
||||
@Schema(title = "Record modify time", example = "2024-07-02T20:09:34.903217", accessMode = READ_WRITE)
|
||||
@LastModifiedDate
|
||||
private LocalDateTime gmtUpdate;
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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 org.apache.hertzbeat.common.entity.manager.bulletin;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Bulletin DTO
|
||||
*/
|
||||
@Data
|
||||
public class BulletinDto {
|
||||
|
||||
/**
|
||||
* Bulletin name
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Monitor type eg: jvm, tomcat
|
||||
*/
|
||||
private String app;
|
||||
|
||||
|
||||
/**
|
||||
* Monitor fields
|
||||
*/
|
||||
private Map<String, List<String>> fields;
|
||||
|
||||
/**
|
||||
* Monitor ids
|
||||
*/
|
||||
private List<Long> monitorIds;
|
||||
|
||||
}
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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 org.apache.hertzbeat.common.entity.manager.bulletin;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* Bulletin Metrics Data
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Bulletin Metrics Data")
|
||||
public class BulletinMetricsData {
|
||||
|
||||
/**
|
||||
* Bulletin Name
|
||||
*/
|
||||
@Schema(title = "Bulletin Name")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Content Data
|
||||
*/
|
||||
@Schema(description = "Content Data")
|
||||
private List<Data> content;
|
||||
|
||||
/**
|
||||
* Bulletin Metrics Data
|
||||
*/
|
||||
@lombok.Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public static class Data {
|
||||
|
||||
/**
|
||||
* Monitor Name
|
||||
*/
|
||||
@Schema(title = "Monitor name")
|
||||
private String monitorName;
|
||||
|
||||
/**
|
||||
* Monitor ID
|
||||
*/
|
||||
@Schema(title = "Monitor ID")
|
||||
private Long monitorId;
|
||||
|
||||
/**
|
||||
* Monitor IP
|
||||
*/
|
||||
@Schema(title = "Monitor IP")
|
||||
private String host;
|
||||
|
||||
/**
|
||||
* Monitor Metrics
|
||||
*/
|
||||
@Schema(title = "Monitor Metrics")
|
||||
private List<Metric> metrics;
|
||||
}
|
||||
|
||||
/**
|
||||
* Metrics Data
|
||||
*/
|
||||
@lombok.Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Metrics Data")
|
||||
public static class Metric{
|
||||
|
||||
/**
|
||||
* Metric type
|
||||
*/
|
||||
@Schema(title = "Metric type")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Metric fields
|
||||
*/
|
||||
@Schema(title = "Metric fields")
|
||||
private List<List<Field>> fields;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Metrics field
|
||||
*/
|
||||
@lombok.Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "Metrics field")
|
||||
public static class Field{
|
||||
|
||||
/**
|
||||
* Field name
|
||||
*/
|
||||
@Schema(title = "Field name")
|
||||
private String key;
|
||||
|
||||
/**
|
||||
* Field unit
|
||||
*/
|
||||
@Schema(title = "Field unit")
|
||||
private String unit;
|
||||
|
||||
/**
|
||||
* Field value
|
||||
*/
|
||||
@Schema(title = "Field value")
|
||||
private String value;
|
||||
}
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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 org.apache.hertzbeat.common.entity.manager.bulletin;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.hertzbeat.common.entity.manager.TagItem;
|
||||
|
||||
/**
|
||||
* Bulletin Vo
|
||||
*/
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class BulletinVo {
|
||||
|
||||
/**
|
||||
* Bulletin ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* Bulletin name
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Bulletin metrics
|
||||
*/
|
||||
private List<String> metrics;
|
||||
|
||||
/**
|
||||
* Bulletin tags
|
||||
*/
|
||||
private List<TagItem> tags;
|
||||
|
||||
/**
|
||||
* Bulletin monitor ID
|
||||
*/
|
||||
private List<Long> monitorId;
|
||||
|
||||
/**
|
||||
* Bulletin monitor name
|
||||
*/
|
||||
private String app;
|
||||
|
||||
}
|
||||
@@ -100,11 +100,15 @@ public final class JsonUtil {
|
||||
* @param jsonStr json string
|
||||
* @return true if the string is a json string
|
||||
*/
|
||||
|
||||
|
||||
public static boolean isJsonStr(String jsonStr) {
|
||||
if (!StringUtils.hasText(jsonStr)) {
|
||||
if (jsonStr == null || jsonStr.trim().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
if (!jsonStr.startsWith("{") || !jsonStr.endsWith("}")) {
|
||||
jsonStr = jsonStr.trim();
|
||||
if (!(jsonStr.startsWith("{") && jsonStr.endsWith("}"))
|
||||
&& !(jsonStr.startsWith("[") && jsonStr.endsWith("]"))) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -20,6 +20,7 @@ package org.apache.hertzbeat.common.util;
|
||||
import static org.apache.hertzbeat.common.util.JsonUtil.isJsonStr;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -66,7 +67,7 @@ class JsonUtilTest {
|
||||
assertFalse(isJsonStr(jsonString));
|
||||
|
||||
String jsonStringArrays = "[{\"name\":\"John\"}, {\"name\":\"Doe\"}]";
|
||||
assertFalse(isJsonStr(jsonStringArrays));
|
||||
assertTrue(isJsonStr(jsonStringArrays));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import org.apache.hertzbeat.common.entity.dto.Message;
|
||||
import org.apache.hertzbeat.common.entity.job.Job;
|
||||
import org.apache.hertzbeat.common.entity.manager.ParamDefine;
|
||||
@@ -155,6 +156,35 @@ public class AppController {
|
||||
@Parameter(description = "en: language type",
|
||||
example = "zh-CN")
|
||||
@RequestParam(name = "lang", required = false) String lang) {
|
||||
lang = getLang(lang);
|
||||
List<Hierarchy> appHierarchies = appService.getAllAppHierarchy(lang);
|
||||
return ResponseEntity.ok(Message.success(appHierarchies));
|
||||
}
|
||||
|
||||
@GetMapping(path = "/hierarchy/{app}")
|
||||
@Operation(summary = "Query all monitor metrics level, output in a hierarchical structure", description = "Query all monitor metrics level, output in a hierarchical structure")
|
||||
public ResponseEntity<Message<List<Hierarchy>>> queryAppsHierarchyByApp(
|
||||
@Parameter(description = "en: language type",
|
||||
example = "zh-CN")
|
||||
@RequestParam(name = "lang", required = false) String lang,
|
||||
@Parameter(description = "en: Monitoring type name", example = "api") @PathVariable("app") final String app) {
|
||||
lang = getLang(lang);
|
||||
List<Hierarchy> appHierarchies = appService.getAppHierarchy(app, lang);
|
||||
return ResponseEntity.ok(Message.success(appHierarchies));
|
||||
}
|
||||
|
||||
@GetMapping(path = "/defines")
|
||||
@Operation(summary = "Query all monitor types", description = "Query all monitor types")
|
||||
public ResponseEntity<Message<Map<String, String>>> getAllAppDefines(
|
||||
@Parameter(description = "en: language type",
|
||||
example = "zh-CN")
|
||||
@RequestParam(name = "lang", required = false) String lang) {
|
||||
lang = getLang(lang);
|
||||
Map<String, String> allAppDefines = appService.getI18nApps(lang);
|
||||
return ResponseEntity.ok(Message.success(allAppDefines));
|
||||
}
|
||||
|
||||
private String getLang(@RequestParam(name = "lang", required = false) @Parameter(description = "en: language type", example = "zh-CN") String lang) {
|
||||
if (lang == null || lang.isEmpty()) {
|
||||
lang = "zh-CN";
|
||||
}
|
||||
@@ -165,7 +195,6 @@ public class AppController {
|
||||
} else {
|
||||
lang = "en-US";
|
||||
}
|
||||
List<Hierarchy> appHierarchies = appService.getAllAppHierarchy(lang);
|
||||
return ResponseEntity.ok(Message.success(appHierarchies));
|
||||
return lang;
|
||||
}
|
||||
}
|
||||
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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 org.apache.hertzbeat.manager.controller;
|
||||
|
||||
import static org.apache.hertzbeat.common.constants.CommonConstants.FAIL_CODE;
|
||||
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import jakarta.validation.Valid;
|
||||
import java.util.List;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.common.entity.dto.Message;
|
||||
import org.apache.hertzbeat.common.entity.manager.bulletin.Bulletin;
|
||||
import org.apache.hertzbeat.common.entity.manager.bulletin.BulletinDto;
|
||||
import org.apache.hertzbeat.common.entity.manager.bulletin.BulletinMetricsData;
|
||||
import org.apache.hertzbeat.manager.service.BulletinService;
|
||||
import org.apache.hertzbeat.manager.service.MonitorService;
|
||||
import org.apache.hertzbeat.warehouse.store.realtime.RealTimeDataReader;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* Bulletin Controller
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping(value = "/api/bulletin", produces = {APPLICATION_JSON_VALUE})
|
||||
public class BulletinController {
|
||||
|
||||
@Autowired
|
||||
private BulletinService bulletinService;
|
||||
|
||||
@Autowired
|
||||
private RealTimeDataReader realTimeDataReader;
|
||||
|
||||
@Autowired
|
||||
private MonitorService monitorService;
|
||||
|
||||
/**
|
||||
* add a new bulletin
|
||||
*/
|
||||
@PostMapping
|
||||
public ResponseEntity<Message<Void>> addNewBulletin(@Valid @RequestBody BulletinDto bulletinDto) {
|
||||
try {
|
||||
bulletinService.validate(bulletinDto);
|
||||
bulletinService.addBulletin(bulletinDto);
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity.ok(Message.fail(FAIL_CODE, "Add failed! " + e.getMessage()));
|
||||
}
|
||||
return ResponseEntity.ok(Message.success("Add success!"));
|
||||
}
|
||||
|
||||
/**
|
||||
* edit a exist bulletin
|
||||
*/
|
||||
@PutMapping
|
||||
public ResponseEntity<Message<Void>> editBulletin(@Valid @RequestBody BulletinDto bulletinDto) {
|
||||
try {
|
||||
bulletinService.validate(bulletinDto);
|
||||
bulletinService.editBulletin(bulletinDto);
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity.ok(Message.fail(FAIL_CODE, "Add failed! " + e.getMessage()));
|
||||
}
|
||||
return ResponseEntity.ok(Message.success("Add success!"));
|
||||
}
|
||||
|
||||
/**
|
||||
* edit a exist bulletin
|
||||
*/
|
||||
@GetMapping("/{name}")
|
||||
public ResponseEntity<Message<Bulletin>> getBulletinByName(@Valid @PathVariable String name) {
|
||||
try {
|
||||
return ResponseEntity.ok(Message.success(bulletinService.getBulletinByName(name)));
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity.ok(Message.fail(FAIL_CODE, "Add failed! " + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get All Names
|
||||
*/
|
||||
@Operation(summary = "Get All Bulletin Names", description = "Get All Bulletin Names")
|
||||
@GetMapping("/names")
|
||||
public ResponseEntity<Message<List<String>>> getAllNames() {
|
||||
List<String> names = bulletinService.getAllNames();
|
||||
return ResponseEntity.ok(Message.success(names));
|
||||
}
|
||||
|
||||
/**
|
||||
* delete bulletin by name
|
||||
*/
|
||||
@Operation(summary = "Delete Bulletin by Name", description = "Delete Bulletin by Name")
|
||||
@DeleteMapping
|
||||
public ResponseEntity<Message<Void>> deleteBulletin(
|
||||
@Parameter(description = "Bulletin Name", example = "402372614668544")
|
||||
@RequestParam List<String> names) {
|
||||
try {
|
||||
bulletinService.deleteBulletinByName(names);
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity.ok(Message.fail(FAIL_CODE, "Delete failed!" + e.getMessage()));
|
||||
}
|
||||
return ResponseEntity.ok(Message.success("Delete success!"));
|
||||
}
|
||||
|
||||
@GetMapping("/metrics")
|
||||
@Operation(summary = "Query All Bulletin Real Time Metrics Data", description = "Query All Bulletin real-time metrics data of monitoring indicators")
|
||||
public ResponseEntity<Message<?>> getAllMetricsData(
|
||||
@RequestParam(name = "name") String name,
|
||||
@RequestParam(defaultValue = "0", name = "pageIndex") int pageIndex,
|
||||
@RequestParam(defaultValue = "10", name = "pageSize") int pageSize) {
|
||||
if (!realTimeDataReader.isServerAvailable()) {
|
||||
return ResponseEntity.ok(Message.fail(FAIL_CODE, "real time store not available"));
|
||||
}
|
||||
|
||||
Bulletin bulletin = bulletinService.getBulletinByName(name);
|
||||
|
||||
BulletinMetricsData.BulletinMetricsDataBuilder contentBuilder = BulletinMetricsData.builder()
|
||||
.name(bulletin.getName());
|
||||
BulletinMetricsData data = bulletinService.buildBulletinMetricsData(contentBuilder, bulletin);
|
||||
return ResponseEntity.ok(Message.success(data));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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 org.apache.hertzbeat.manager.dao;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import org.apache.hertzbeat.common.entity.manager.bulletin.Bulletin;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
|
||||
/**
|
||||
* BulletinDao
|
||||
*/
|
||||
public interface BulletinDao extends JpaRepository<Bulletin, Long>, JpaSpecificationExecutor<Bulletin> {
|
||||
/**
|
||||
* Delete Bulletin by name
|
||||
*/
|
||||
void deleteByNameIn(List<String> names);
|
||||
|
||||
/**
|
||||
* Get Bulletin by name
|
||||
*/
|
||||
Bulletin findByName(String name);
|
||||
|
||||
|
||||
}
|
||||
@@ -80,6 +80,14 @@ public interface AppService {
|
||||
*/
|
||||
Map<String, String> getI18nResources(String lang);
|
||||
|
||||
/**
|
||||
* Get the I 18 N resources of the monitoring type
|
||||
*
|
||||
* @param lang Language type
|
||||
* @return I18N Resources
|
||||
*/
|
||||
Map<String, String> getI18nApps(String lang);
|
||||
|
||||
/**
|
||||
* Query all types of monitoring hierarchy
|
||||
*
|
||||
@@ -88,6 +96,15 @@ public interface AppService {
|
||||
*/
|
||||
List<Hierarchy> getAllAppHierarchy(String lang);
|
||||
|
||||
/**
|
||||
* Get the monitoring hierarchy based on the monitoring type
|
||||
*
|
||||
* @param app monitoring type
|
||||
* @param lang language
|
||||
* @return hierarchy information
|
||||
*/
|
||||
List<Hierarchy> getAppHierarchy(String app, String lang);
|
||||
|
||||
/**
|
||||
* Get all app define
|
||||
*
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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 org.apache.hertzbeat.manager.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.apache.hertzbeat.common.entity.manager.bulletin.Bulletin;
|
||||
import org.apache.hertzbeat.common.entity.manager.bulletin.BulletinDto;
|
||||
import org.apache.hertzbeat.common.entity.manager.bulletin.BulletinMetricsData;
|
||||
import org.apache.hertzbeat.common.entity.manager.bulletin.BulletinVo;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
/**
|
||||
* Bulletin Service
|
||||
*/
|
||||
public interface BulletinService {
|
||||
|
||||
/**
|
||||
* validate Bulletin
|
||||
*/
|
||||
void validate(BulletinDto bulletindto) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Get Bulletin by name
|
||||
*/
|
||||
Bulletin getBulletinByName(String name);
|
||||
|
||||
/**
|
||||
* Get Bulletin by id
|
||||
*/
|
||||
Optional<Bulletin> getBulletinById(Long id);
|
||||
|
||||
/**
|
||||
* Get all names
|
||||
*/
|
||||
List<String> getAllNames();
|
||||
|
||||
|
||||
/**
|
||||
* delete Bulletin by id
|
||||
*/
|
||||
void deleteBulletinByName(List<String> names);
|
||||
|
||||
|
||||
/**
|
||||
* Save Bulletin
|
||||
*/
|
||||
void editBulletin(BulletinDto bulletinDto);
|
||||
|
||||
/**
|
||||
* Add Bulletin
|
||||
*/
|
||||
void addBulletin(BulletinDto bulletinDto);
|
||||
|
||||
/**
|
||||
* Dynamic conditional query
|
||||
* @param specification Query conditions
|
||||
* @param pageRequest Paging parameters
|
||||
* @return The query results
|
||||
*/
|
||||
Page<BulletinVo> getBulletins(Specification<Bulletin> specification, PageRequest pageRequest);
|
||||
|
||||
/**
|
||||
* deal with the bulletin
|
||||
*/
|
||||
BulletinMetricsData buildBulletinMetricsData(BulletinMetricsData.BulletinMetricsDataBuilder contentBuilder, Bulletin bulletin);
|
||||
}
|
||||
+104
-67
@@ -255,6 +255,20 @@ public class AppServiceImpl implements AppService, CommandLineRunner {
|
||||
return i18nMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getI18nApps(String lang) {
|
||||
Map<String, String> i18nMap = new HashMap<>(128);
|
||||
for (var job : appDefines.values()) {
|
||||
var name = job.getName();
|
||||
var i18nName = CommonUtil.getLangMappingValueFromI18nMap(lang, name);
|
||||
if (i18nName != null) {
|
||||
i18nMap.put(job.getApp(), i18nName);
|
||||
}
|
||||
}
|
||||
return i18nMap;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<Hierarchy> getAllAppHierarchy(String lang) {
|
||||
LinkedList<Hierarchy> hierarchies = new LinkedList<>();
|
||||
@@ -263,82 +277,104 @@ public class AppServiceImpl implements AppService, CommandLineRunner {
|
||||
if (DispatchConstants.PROTOCOL_PUSH.equalsIgnoreCase(job.getApp())) {
|
||||
continue;
|
||||
}
|
||||
var hierarchyApp = new Hierarchy();
|
||||
hierarchyApp.setCategory(job.getCategory());
|
||||
hierarchyApp.setValue(job.getApp());
|
||||
hierarchyApp.setHide(job.isHide());
|
||||
var nameMap = job.getName();
|
||||
if (nameMap != null && !nameMap.isEmpty()) {
|
||||
var i18nName = CommonUtil.getLangMappingValueFromI18nMap(lang, nameMap);
|
||||
if (i18nName != null) {
|
||||
hierarchyApp.setLabel(i18nName);
|
||||
}
|
||||
}
|
||||
List<Hierarchy> hierarchyMetricList = new LinkedList<>();
|
||||
if (DispatchConstants.PROTOCOL_PROMETHEUS.equalsIgnoreCase(job.getApp())) {
|
||||
List<Monitor> monitors = monitorDao.findMonitorsByAppEquals(job.getApp());
|
||||
for (Monitor monitor : monitors) {
|
||||
List<CollectRep.MetricsData> metricsDataList = warehouseService.queryMonitorMetricsData(monitor.getId());
|
||||
for (CollectRep.MetricsData metricsData : metricsDataList) {
|
||||
var hierarchyMetric = new Hierarchy();
|
||||
hierarchyMetric.setValue(metricsData.getMetrics());
|
||||
hierarchyMetric.setLabel(metricsData.getMetrics());
|
||||
List<Hierarchy> hierarchyFieldList = metricsData.getFieldsList().stream()
|
||||
.map(item -> {
|
||||
var hierarchyField = new Hierarchy();
|
||||
hierarchyField.setValue(item.getName());
|
||||
hierarchyField.setLabel(item.getName());
|
||||
hierarchyField.setIsLeaf(true);
|
||||
hierarchyField.setType((byte) item.getType());
|
||||
hierarchyField.setUnit(item.getUnit());
|
||||
return hierarchyField;
|
||||
}).collect(Collectors.toList());
|
||||
hierarchyMetric.setChildren(hierarchyFieldList);
|
||||
// combine Hierarchy Metrics
|
||||
combineHierarchyMetrics(hierarchyMetricList, hierarchyMetric);
|
||||
}
|
||||
}
|
||||
hierarchyApp.setChildren(hierarchyMetricList);
|
||||
hierarchies.addFirst(hierarchyApp);
|
||||
} else {
|
||||
if (job.getMetrics() != null) {
|
||||
for (var metrics : job.getMetrics()) {
|
||||
var hierarchyMetric = new Hierarchy();
|
||||
hierarchyMetric.setValue(metrics.getName());
|
||||
var metricsI18nName = CommonUtil.getLangMappingValueFromI18nMap(lang, metrics.getI18n());
|
||||
hierarchyMetric.setLabel(metricsI18nName != null ? metricsI18nName : metrics.getName());
|
||||
List<Hierarchy> hierarchyFieldList = new LinkedList<>();
|
||||
if (metrics.getFields() != null) {
|
||||
for (var field : metrics.getFields()) {
|
||||
var hierarchyField = new Hierarchy();
|
||||
hierarchyField.setValue(field.getField());
|
||||
var metricI18nName = CommonUtil.getLangMappingValueFromI18nMap(lang, field.getI18n());
|
||||
hierarchyField.setLabel(metricI18nName != null ? metricI18nName : field.getField());
|
||||
hierarchyField.setIsLeaf(true);
|
||||
// for metric
|
||||
hierarchyField.setType(field.getType());
|
||||
hierarchyField.setUnit(field.getUnit());
|
||||
hierarchyFieldList.add(hierarchyField);
|
||||
}
|
||||
hierarchyMetric.setChildren(hierarchyFieldList);
|
||||
}
|
||||
hierarchyMetricList.add(hierarchyMetric);
|
||||
}
|
||||
}
|
||||
hierarchyApp.setChildren(hierarchyMetricList);
|
||||
hierarchies.add(hierarchyApp);
|
||||
}
|
||||
queryAppHierarchy(lang, hierarchies, job);
|
||||
}
|
||||
return hierarchies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Hierarchy> getAppHierarchy(String app, String lang) {
|
||||
LinkedList<Hierarchy> hierarchies = new LinkedList<>();
|
||||
Job job = appDefines.get(app.toLowerCase());
|
||||
// TODO temporarily filter out push to solve the front-end problem, and open it after the subsequent design optimization
|
||||
if (DispatchConstants.PROTOCOL_PUSH.equalsIgnoreCase(job.getApp())) {
|
||||
return hierarchies;
|
||||
}
|
||||
queryAppHierarchy(lang, hierarchies, job);
|
||||
return hierarchies;
|
||||
}
|
||||
|
||||
private void queryAppHierarchy(String lang, LinkedList<Hierarchy> hierarchies, Job job) {
|
||||
var hierarchyApp = new Hierarchy();
|
||||
hierarchyApp.setCategory(job.getCategory());
|
||||
hierarchyApp.setValue(job.getApp());
|
||||
hierarchyApp.setHide(job.isHide());
|
||||
var nameMap = job.getName();
|
||||
if (nameMap != null && !nameMap.isEmpty()) {
|
||||
var i18nName = CommonUtil.getLangMappingValueFromI18nMap(lang, nameMap);
|
||||
if (i18nName != null) {
|
||||
hierarchyApp.setLabel(i18nName);
|
||||
}
|
||||
}
|
||||
List<Hierarchy> hierarchyMetricList = new LinkedList<>();
|
||||
if (DispatchConstants.PROTOCOL_PROMETHEUS.equalsIgnoreCase(job.getApp())) {
|
||||
List<Monitor> monitors = monitorDao.findMonitorsByAppEquals(job.getApp());
|
||||
for (Monitor monitor : monitors) {
|
||||
List<CollectRep.MetricsData> metricsDataList = warehouseService.queryMonitorMetricsData(monitor.getId());
|
||||
for (CollectRep.MetricsData metricsData : metricsDataList) {
|
||||
var hierarchyMetric = new Hierarchy();
|
||||
hierarchyMetric.setValue(metricsData.getMetrics());
|
||||
hierarchyMetric.setLabel(metricsData.getMetrics());
|
||||
List<Hierarchy> hierarchyFieldList = metricsData.getFieldsList().stream()
|
||||
.map(item -> {
|
||||
var hierarchyField = new Hierarchy();
|
||||
hierarchyField.setValue(item.getName());
|
||||
hierarchyField.setLabel(item.getName());
|
||||
hierarchyField.setIsLeaf(true);
|
||||
hierarchyField.setType((byte) item.getType());
|
||||
hierarchyField.setUnit(item.getUnit());
|
||||
return hierarchyField;
|
||||
}).collect(Collectors.toList());
|
||||
hierarchyMetric.setChildren(hierarchyFieldList);
|
||||
// combine Hierarchy Metrics
|
||||
combineHierarchyMetrics(hierarchyMetricList, hierarchyMetric);
|
||||
}
|
||||
}
|
||||
hierarchyApp.setChildren(hierarchyMetricList);
|
||||
hierarchies.addFirst(hierarchyApp);
|
||||
} else {
|
||||
if (job.getMetrics() != null) {
|
||||
for (var metrics : job.getMetrics()) {
|
||||
var hierarchyMetric = new Hierarchy();
|
||||
hierarchyMetric.setValue(metrics.getName());
|
||||
var metricsI18nName = CommonUtil.getLangMappingValueFromI18nMap(lang, metrics.getI18n());
|
||||
hierarchyMetric.setLabel(metricsI18nName != null ? metricsI18nName : metrics.getName());
|
||||
List<Hierarchy> hierarchyFieldList = new LinkedList<>();
|
||||
if (metrics.getFields() != null) {
|
||||
for (var field : metrics.getFields()) {
|
||||
var hierarchyField = new Hierarchy();
|
||||
hierarchyField.setValue(field.getField());
|
||||
var metricI18nName = CommonUtil.getLangMappingValueFromI18nMap(lang, field.getI18n());
|
||||
hierarchyField.setLabel(metricI18nName != null ? metricI18nName : field.getField());
|
||||
hierarchyField.setIsLeaf(true);
|
||||
// for metric
|
||||
hierarchyField.setType(field.getType());
|
||||
hierarchyField.setUnit(field.getUnit());
|
||||
hierarchyFieldList.add(hierarchyField);
|
||||
}
|
||||
hierarchyMetric.setChildren(hierarchyFieldList);
|
||||
}
|
||||
hierarchyMetricList.add(hierarchyMetric);
|
||||
}
|
||||
}
|
||||
hierarchyApp.setChildren(hierarchyMetricList);
|
||||
hierarchies.add(hierarchyApp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void combineHierarchyMetrics(List<Hierarchy> hierarchyMetricList, Hierarchy hierarchyMetric) {
|
||||
Optional<Hierarchy> preHierarchyOptional = hierarchyMetricList.stream()
|
||||
.filter(item -> item.getValue().equals(hierarchyMetric.getValue())).findFirst();
|
||||
.filter(item -> item.getValue().equals(hierarchyMetric.getValue()))
|
||||
.findFirst();
|
||||
|
||||
if (preHierarchyOptional.isPresent()) {
|
||||
Hierarchy preHierarchy = preHierarchyOptional.get();
|
||||
List<Hierarchy> children = preHierarchy.getChildren();
|
||||
Set<String> childrenKey = children.stream().map(Hierarchy::getValue).collect(Collectors.toSet());
|
||||
Set<String> childrenKey = children.stream()
|
||||
.map(Hierarchy::getValue)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
for (Hierarchy child : hierarchyMetric.getChildren()) {
|
||||
if (!childrenKey.contains(child.getValue())) {
|
||||
children.add(child);
|
||||
@@ -349,6 +385,7 @@ public class AppServiceImpl implements AppService, CommandLineRunner {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Map<String, Job> getAllAppDefines() {
|
||||
return appDefines;
|
||||
|
||||
+258
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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 org.apache.hertzbeat.manager.service.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.TreeMap;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.common.entity.manager.Monitor;
|
||||
import org.apache.hertzbeat.common.entity.manager.bulletin.Bulletin;
|
||||
import org.apache.hertzbeat.common.entity.manager.bulletin.BulletinDto;
|
||||
import org.apache.hertzbeat.common.entity.manager.bulletin.BulletinMetricsData;
|
||||
import org.apache.hertzbeat.common.entity.manager.bulletin.BulletinVo;
|
||||
import org.apache.hertzbeat.common.entity.message.CollectRep;
|
||||
import org.apache.hertzbeat.common.util.JsonUtil;
|
||||
import org.apache.hertzbeat.common.util.SnowFlakeIdGenerator;
|
||||
import org.apache.hertzbeat.manager.dao.BulletinDao;
|
||||
import org.apache.hertzbeat.manager.service.BulletinService;
|
||||
import org.apache.hertzbeat.manager.service.MonitorService;
|
||||
import org.apache.hertzbeat.warehouse.store.realtime.RealTimeDataReader;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Bulletin Service Implementation
|
||||
*/
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class BulletinServiceImpl implements BulletinService {
|
||||
|
||||
private static final String NO_DATA = "No Data";
|
||||
|
||||
private static final String EMPTY_STRING = "";
|
||||
|
||||
@Autowired
|
||||
private BulletinDao bulletinDao;
|
||||
|
||||
@Autowired
|
||||
private MonitorService monitorService;
|
||||
|
||||
@Autowired
|
||||
private RealTimeDataReader realTimeDataReader;
|
||||
|
||||
|
||||
/**
|
||||
* validate Bulletin
|
||||
*/
|
||||
@Override
|
||||
public void validate(BulletinDto bulletinDto) throws IllegalArgumentException {
|
||||
if (bulletinDto == null) {
|
||||
throw new IllegalArgumentException("Bulletin cannot be null");
|
||||
}
|
||||
if (bulletinDto.getApp() == null || bulletinDto.getApp().isEmpty()) {
|
||||
throw new IllegalArgumentException("Bulletin app cannot be null or empty");
|
||||
}
|
||||
if (bulletinDto.getFields() == null || bulletinDto.getFields().isEmpty()) {
|
||||
throw new IllegalArgumentException("Bulletin fields cannot be null or empty");
|
||||
}
|
||||
if (bulletinDto.getMonitorIds() == null || bulletinDto.getMonitorIds().isEmpty()) {
|
||||
throw new IllegalArgumentException("Bulletin monitorIds cannot be null or empty");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pageable query Bulletin
|
||||
*/
|
||||
@Override
|
||||
public Bulletin getBulletinByName(String name) {
|
||||
return bulletinDao.findByName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all names
|
||||
*/
|
||||
@Override
|
||||
public List<String> getAllNames() {
|
||||
return bulletinDao.findAll().stream().map(Bulletin::getName).distinct().toList();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save Bulletin
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void editBulletin(BulletinDto bulletinDto) {
|
||||
try {
|
||||
//TODO: update bulletin
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Bulletin
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void addBulletin(BulletinDto bulletinDto) {
|
||||
try {
|
||||
Bulletin bulletin = new Bulletin();
|
||||
bulletin.setName(bulletinDto.getName());
|
||||
bulletin.setId(SnowFlakeIdGenerator.generateId());
|
||||
Map<String, List<String>> map = bulletinDto.getFields();
|
||||
Map<String, List<String>> sortedMap = new TreeMap<>(map);
|
||||
String fields = JsonUtil.toJson(sortedMap);
|
||||
bulletin.setFields(fields);
|
||||
bulletin.setMonitorIds(bulletinDto.getMonitorIds());
|
||||
bulletin.setApp(bulletinDto.getApp());
|
||||
bulletinDao.save(bulletin);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamic conditional query
|
||||
*
|
||||
* @param specification Query conditions
|
||||
* @param pageRequest Paging parameters
|
||||
* @return The query results
|
||||
*/
|
||||
@Override
|
||||
public Page<BulletinVo> getBulletins(Specification<Bulletin> specification, PageRequest pageRequest) {
|
||||
List<BulletinVo> voList = new ArrayList<>();
|
||||
Page<Bulletin> bulletinPage = Page.empty(pageRequest);
|
||||
try {
|
||||
bulletinPage = bulletinDao.findAll(specification, pageRequest);
|
||||
voList = bulletinPage.stream().map(bulletin -> {
|
||||
BulletinVo vo = new BulletinVo();
|
||||
vo.setId(bulletin.getId());
|
||||
vo.setName(bulletin.getName());
|
||||
vo.setTags(bulletin.getTags());
|
||||
vo.setMonitorId(bulletin.getMonitorIds());
|
||||
vo.setApp(bulletin.getApp());
|
||||
return vo;
|
||||
}).collect(Collectors.toList());
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to query bulletin: {}", e.getLocalizedMessage(), e);
|
||||
}
|
||||
long total = bulletinPage.getTotalElements();
|
||||
return new PageImpl<>(voList, pageRequest, total);
|
||||
}
|
||||
|
||||
/**
|
||||
* deal with the bulletin
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public BulletinMetricsData buildBulletinMetricsData(BulletinMetricsData.BulletinMetricsDataBuilder contentBuilder, Bulletin bulletin) {
|
||||
List<BulletinMetricsData.Data> dataList = new ArrayList<>();
|
||||
for (Long monitorId : bulletin.getMonitorIds()) {
|
||||
Monitor monitor = monitorService.getMonitor(monitorId);
|
||||
BulletinMetricsData.Data.DataBuilder dataBuilder = BulletinMetricsData.Data.builder()
|
||||
.monitorId(monitorId)
|
||||
.monitorName(monitor.getName())
|
||||
.host(monitor.getHost());
|
||||
|
||||
List<BulletinMetricsData.Metric> metrics = new ArrayList<>();
|
||||
Map<String, List<String>> fieldMap = JsonUtil.fromJson(bulletin.getFields(), new TypeReference<>() {});
|
||||
|
||||
if (fieldMap != null) {
|
||||
for (Map.Entry<String, List<String>> entry : fieldMap.entrySet()) {
|
||||
String metric = entry.getKey();
|
||||
List<String> fields = entry.getValue();
|
||||
BulletinMetricsData.Metric.MetricBuilder metricBuilder = BulletinMetricsData.Metric.builder()
|
||||
.name(metric);
|
||||
CollectRep.MetricsData currentMetricsData = realTimeDataReader.getCurrentMetricsData(monitorId, metric);
|
||||
|
||||
List<List<BulletinMetricsData.Field>> fieldsList;
|
||||
if (currentMetricsData != null) {
|
||||
fieldsList = currentMetricsData.getValuesList().stream()
|
||||
.map(valueRow -> {
|
||||
List<BulletinMetricsData.Field> fieldList = currentMetricsData.getFieldsList().stream()
|
||||
.map(field -> BulletinMetricsData.Field.builder()
|
||||
.key(field.getName())
|
||||
.unit(field.getUnit())
|
||||
.build())
|
||||
.toList();
|
||||
|
||||
for (int i = 0; i < fieldList.size(); i++) {
|
||||
fieldList.get(i).setValue(valueRow.getColumns(i));
|
||||
}
|
||||
return fieldList;
|
||||
})
|
||||
.toList();
|
||||
} else {
|
||||
fieldsList = Collections.singletonList(fields.stream()
|
||||
.map(field -> BulletinMetricsData.Field.builder()
|
||||
.key(field)
|
||||
.unit("")
|
||||
.value("NO_DATA")
|
||||
.build())
|
||||
.toList());
|
||||
}
|
||||
|
||||
metricBuilder.fields(fieldsList);
|
||||
metrics.add(metricBuilder.build());
|
||||
}
|
||||
}
|
||||
dataBuilder.metrics(metrics);
|
||||
dataList.add(dataBuilder.build());
|
||||
}
|
||||
contentBuilder.content(dataList);
|
||||
return contentBuilder.build();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get Bulletin by id
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public Optional<Bulletin> getBulletinById(Long id) {
|
||||
return bulletinDao.findById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* delete Bulletin by names
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteBulletinByName(List<String> names) {
|
||||
try {
|
||||
bulletinDao.deleteByNameIn(names);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,6 +58,10 @@ resourceRole:
|
||||
- /api/status/page/**===post===[admin,user]
|
||||
- /api/status/page/**===put===[admin,user]
|
||||
- /api/status/page/**===delete===[admin]
|
||||
- /api/bulletin/**===get===[admin,user,guest]
|
||||
- /api/bulletin/**===post===[admin,user]
|
||||
- /api/bulletin/**===put===[admin,user]
|
||||
- /api/bulletin/**===delete===[admin]
|
||||
|
||||
# config the resource restful api that need bypass auth protection
|
||||
# rule: api===method
|
||||
|
||||
+5
-1
@@ -58,7 +58,11 @@ resourceRole:
|
||||
- /api/status/page/**===post===[admin,user]
|
||||
- /api/status/page/**===put===[admin,user]
|
||||
- /api/status/page/**===delete===[admin]
|
||||
|
||||
- /api/bulletin/**===get===[admin,user,guest]
|
||||
- /api/bulletin/**===post===[admin,user]
|
||||
- /api/bulletin/**===put===[admin,user]
|
||||
- /api/bulletin/**===delete===[admin]
|
||||
|
||||
# config the resource restful api that need bypass auth protection
|
||||
# rule: api===method
|
||||
# eg: /api/v1/source3===get means /api/v1/source3===get can be access by anyone, no need auth.
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.
|
||||
*/
|
||||
|
||||
import { Fields } from './Fields';
|
||||
|
||||
export class BulletinDefine {
|
||||
id!: number;
|
||||
name!: string;
|
||||
monitorIds!: number[];
|
||||
app!: string;
|
||||
fields: Fields = {};
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.
|
||||
*/
|
||||
|
||||
export interface Fields {
|
||||
[key: string]: string[];
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one
|
||||
~ or more contributor license agreements. See the NOTICE file
|
||||
~ distributed with this work for additional information
|
||||
~ regarding copyright ownership. The ASF licenses this file
|
||||
~ to you 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.
|
||||
-->
|
||||
|
||||
<app-help-message-show
|
||||
[help_message_content]="'bulletin.help.message.content' | i18n"
|
||||
[guild_link]="'bulletin.help.link' | i18n"
|
||||
[module_name]="'menu.alert.setting'"
|
||||
[icon_name]="'calculator'"
|
||||
></app-help-message-show>
|
||||
|
||||
<nz-divider></nz-divider>
|
||||
|
||||
<app-toolbar>
|
||||
<ng-template #left>
|
||||
<button nz-button nzType="primary" (click)="sync()" nz-tooltip [nzTooltipTitle]="'common.refresh' | i18n">
|
||||
<i nz-icon nzType="sync" nzTheme="outline"></i>
|
||||
</button>
|
||||
<button nz-button nzType="primary" (click)="onNewBulletinDefine()">
|
||||
<i nz-icon nzType="appstore-add" nzTheme="outline"></i>
|
||||
{{ 'bulletin.new' | i18n }}
|
||||
</button>
|
||||
<!--TODO: Wait until the backend interface is improved before releasing it.-->
|
||||
<!--<button *ngIf="currentDefine" nz-button nzType="primary" (click)="onEditBulletinDefine()">
|
||||
<i nz-icon nzType="edit" nzTheme="outline"></i>
|
||||
{{ 'bulletin.edit' | i18n }}
|
||||
</button>-->
|
||||
<button *ngIf="currentDefine" nz-button nzType="primary" nzDanger (click)="onDeleteBulletinDefines()">
|
||||
<i nz-icon nzType="delete" nzTheme="outline"></i>
|
||||
{{ 'bulletin.delete' | i18n }}
|
||||
</button>
|
||||
<button *ngIf="currentDefine" nz-button nzType="primary" nzDanger (click)="onBatchDeleteBulletinDefines()">
|
||||
<i nz-icon nzType="delete" nzTheme="outline"></i>
|
||||
{{ 'bulletin.batch.delete' | i18n }}
|
||||
</button>
|
||||
</ng-template>
|
||||
</app-toolbar>
|
||||
|
||||
<nz-tabset nzType="card" (nzSelectedIndexChange)="onTabChange($event)">
|
||||
<nz-tab *ngFor="let tab of tabs" [nzTitle]="tab">
|
||||
<ng-container *ngIf="metricsData">
|
||||
<nz-table
|
||||
#fixedTable
|
||||
[nzData]="metricsData"
|
||||
[nzPageIndex]="pageIndex"
|
||||
[nzPageSize]="pageSize"
|
||||
[nzTotal]="total"
|
||||
nzFrontPagination="false"
|
||||
[nzLoading]="tableLoading"
|
||||
nzShowSizeChanger
|
||||
[nzPageSizeOptions]="[10, 20, 50]"
|
||||
(nzQueryParams)="onTablePageChange($event)"
|
||||
nzShowPagination="true"
|
||||
[nzScroll]="{ x: 'auto' }"
|
||||
nzBordered
|
||||
class="table"
|
||||
>
|
||||
<thead>
|
||||
<tr>
|
||||
<th nzAlign="center" nzWidth="7%" [rowSpan]="2">App</th>
|
||||
<th nzAlign="center" nzWidth="7%" [rowSpan]="2">Host</th>
|
||||
<ng-container *ngFor="let metric of metrics">
|
||||
<th nzAlign="center" [colSpan]="getKeys(metric).length">
|
||||
{{ metric }}
|
||||
</th>
|
||||
</ng-container>
|
||||
</tr>
|
||||
<tr>
|
||||
<ng-container *ngFor="let metric of metrics">
|
||||
<ng-container *ngFor="let field of getKeys(metric)">
|
||||
<th nzAlign="center" [colSpan]="1">
|
||||
{{ field }}
|
||||
</th>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<ng-container *ngFor="let content of fixedTable.data">
|
||||
<tr>
|
||||
<td nzAlign="center" [rowSpan]="1">{{ content.monitorName }}</td>
|
||||
<td nzAlign="center" [rowSpan]="1">{{ content.host }}</td>
|
||||
<ng-container *ngFor="let metric of content.metrics">
|
||||
<ng-container *ngFor="let field of metric.fields">
|
||||
<ng-container *ngFor="let item of field">
|
||||
<td nzAlign="center">
|
||||
<ng-container *ngIf="item.value === 'NO_DATA'; else hasData">
|
||||
<nz-tag nzColor="warning">No Data Available</nz-tag>
|
||||
</ng-container>
|
||||
<ng-template #hasData>
|
||||
{{ item.value }}
|
||||
<nz-tag *ngIf="item.unit !== ''" nzColor="success">{{ item.unit }}</nz-tag>
|
||||
</ng-template>
|
||||
</td>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</tr>
|
||||
</ng-container>
|
||||
</tbody>
|
||||
</nz-table>
|
||||
</ng-container>
|
||||
</nz-tab>
|
||||
</nz-tabset>
|
||||
|
||||
<!-- new bulletin modal -->
|
||||
<nz-modal
|
||||
[(nzVisible)]="isManageModalVisible"
|
||||
[nzTitle]="(isManageModalAdd ? 'bulletin.new' : 'bulletin.edit') | i18n"
|
||||
(nzOnCancel)="onManageModalCancel()"
|
||||
(nzOnOk)="onManageModalOk()"
|
||||
nzMaskClosable="false"
|
||||
nzWidth="70%"
|
||||
[nzOkLoading]="isManageModalOkLoading"
|
||||
>
|
||||
<div *nzModalContent class="-inner-content">
|
||||
<form nz-form #defineForm="ngForm">
|
||||
<nz-form-item>
|
||||
<nz-form-label [nzSpan]="7" nzFor="textInput" nzRequired="true">{{ 'bulletin.name' | i18n }}</nz-form-label>
|
||||
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
|
||||
<input nz-input placeholder="{{ 'bulletin.name.placeholder' | i18n }}" [(ngModel)]="define.name" name="inputText" required />
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
|
||||
<nz-form-item>
|
||||
<nz-form-label [nzSpan]="7" nzFor="dropdown" nzRequired="true">{{ 'bulletin.monitor.type' | i18n }}</nz-form-label>
|
||||
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
|
||||
<nz-select
|
||||
nzAllowClear
|
||||
nzShowSearch
|
||||
name="appDefines"
|
||||
[(ngModel)]="define.app"
|
||||
(nzOnSearch)="onSearchAppDefines()"
|
||||
(ngModelChange)="onAppChange($event)"
|
||||
required
|
||||
>
|
||||
<ng-container *ngFor="let app of appEntries">
|
||||
<nz-option *ngIf="isAppListLoading" [nzValue]="app.key" [nzLabel]="app.key + '/' + app.value"></nz-option>
|
||||
</ng-container>
|
||||
</nz-select>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
|
||||
<nz-form-item>
|
||||
<nz-form-label [nzSpan]="7" nzFor="dropdown" nzRequired="true">{{ 'bulletin.monitor.name' | i18n }}</nz-form-label>
|
||||
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
|
||||
<nz-select
|
||||
nzAllowClear
|
||||
nzShowSearch
|
||||
name="monitors"
|
||||
[(ngModel)]="define.monitorIds"
|
||||
(nzOnSearch)="onSearchMonitorsByApp(define.app)"
|
||||
nzMode="multiple"
|
||||
required
|
||||
>
|
||||
<ng-container *ngFor="let monitor of monitors">
|
||||
<nz-option *ngIf="isMonitorListLoading" [nzValue]="monitor.id" [nzLabel]="monitor.name"></nz-option>
|
||||
</ng-container>
|
||||
</nz-select>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
|
||||
<nz-form-item>
|
||||
<nz-form-label [nzSpan]="7" nzFor="dropdown" nzRequired="true">{{ 'bulletin.monitor.metrics' | i18n }}</nz-form-label>
|
||||
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
|
||||
<nz-transfer [nzDataSource]="hierarchies" [nzRenderList]="[leftRenderList, null]" (nzChange)="transferChange($event)">
|
||||
<ng-template #leftRenderList let-items let-onItemSelect="onItemSelect">
|
||||
<nz-tree
|
||||
[nzData]="treeNodes"
|
||||
nzExpandAll
|
||||
nzBlockNode
|
||||
nzCheckable
|
||||
nzCheckStrictly
|
||||
[(ngModel)]="tempMetrics"
|
||||
name="metrics"
|
||||
(nzCheckBoxChange)="treeCheckBoxChange($event, onItemSelect)"
|
||||
>
|
||||
<ng-template let-node>
|
||||
<span
|
||||
(click)="checkBoxChange(node, onItemSelect)"
|
||||
class="ant-tree-node-content-wrapper ant-tree-node-content-wrapper-open"
|
||||
>
|
||||
{{ node.title }}
|
||||
</span>
|
||||
</ng-template>
|
||||
</nz-tree>
|
||||
</ng-template>
|
||||
</nz-transfer>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
</form>
|
||||
</div>
|
||||
</nz-modal>
|
||||
|
||||
<!-- delete bulletin modal -->
|
||||
<nz-modal
|
||||
[(nzVisible)]="isBatchDeleteModalVisible"
|
||||
[nzTitle]="'bulletin.batch.delete' | i18n"
|
||||
(nzOnCancel)="onBatchDeleteModalCancel()"
|
||||
(nzOnOk)="onBatchDeleteModalOk()"
|
||||
nzMaskClosable="false"
|
||||
nzWidth="70%"
|
||||
>
|
||||
<div *nzModalContent class="-inner-content">
|
||||
<form nz-form #defineForm="ngForm">
|
||||
<nz-form-item>
|
||||
<nz-form-label [nzSpan]="7" nzFor="textInput" nzRequired="true">{{ 'bulletin.name' | i18n }}</nz-form-label>
|
||||
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
|
||||
<nz-select
|
||||
nzMode="multiple"
|
||||
nzPlaceHolder="Please select"
|
||||
[(ngModel)]="this.deleteBulletinNames"
|
||||
[nzShowSearch]="true"
|
||||
name="delete"
|
||||
>
|
||||
<nz-option *ngFor="let tab of tabs" [nzLabel]="tab" [nzValue]="tab"></nz-option>
|
||||
</nz-select>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
</form>
|
||||
</div>
|
||||
</nz-modal>
|
||||
@@ -0,0 +1,17 @@
|
||||
@table-padding: 8px;
|
||||
.table {
|
||||
width: 100%;
|
||||
table-layout: auto;
|
||||
|
||||
th {
|
||||
white-space: nowrap;
|
||||
padding: @table-padding;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
td {
|
||||
white-space: nowrap;
|
||||
padding: @table-padding;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.
|
||||
*/
|
||||
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { BulletinComponent } from './bulletin.component';
|
||||
|
||||
describe('BulletinComponent', () => {
|
||||
let component: BulletinComponent;
|
||||
let fixture: ComponentFixture<BulletinComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [BulletinComponent]
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(BulletinComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,509 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.
|
||||
*/
|
||||
|
||||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import { I18NService } from '@core';
|
||||
import { ALAIN_I18N_TOKEN } from '@delon/theme';
|
||||
import { NzModalService } from 'ng-zorro-antd/modal';
|
||||
import { NzNotificationService } from 'ng-zorro-antd/notification';
|
||||
import { NzTableQueryParams } from 'ng-zorro-antd/table';
|
||||
import { TransferChange } from 'ng-zorro-antd/transfer';
|
||||
import { NzFormatEmitEvent, NzTreeNode, NzTreeNodeOptions } from 'ng-zorro-antd/tree';
|
||||
import { finalize } from 'rxjs/operators';
|
||||
|
||||
import { BulletinDefine } from '../../pojo/BulletinDefine';
|
||||
import { Fields } from '../../pojo/Fields';
|
||||
import { Monitor } from '../../pojo/Monitor';
|
||||
import { AppDefineService } from '../../service/app-define.service';
|
||||
import { BulletinDefineService } from '../../service/bulletin-define.service';
|
||||
import { MonitorService } from '../../service/monitor.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-bulletin',
|
||||
templateUrl: './bulletin.component.html',
|
||||
styleUrls: ['./bulletin.component.less']
|
||||
})
|
||||
export class BulletinComponent implements OnInit {
|
||||
constructor(
|
||||
private modal: NzModalService,
|
||||
private notifySvc: NzNotificationService,
|
||||
private appDefineSvc: AppDefineService,
|
||||
private monitorSvc: MonitorService,
|
||||
private bulletinDefineSvc: BulletinDefineService,
|
||||
@Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService
|
||||
) {}
|
||||
search!: string;
|
||||
tabs!: string[];
|
||||
metricsData!: any;
|
||||
tableLoading: boolean = true;
|
||||
bulletinName!: string;
|
||||
deleteBulletinNames: string[] = [];
|
||||
isAppListLoading = false;
|
||||
isMonitorListLoading = false;
|
||||
treeNodes!: NzTreeNodeOptions[];
|
||||
hierarchies: NzTreeNodeOptions[] = [];
|
||||
appMap = new Map<string, string>();
|
||||
appEntries: Array<{ value: any; key: string }> = [];
|
||||
checkedNodeList: NzTreeNode[] = [];
|
||||
monitors: Monitor[] = [];
|
||||
metrics = new Set<string>();
|
||||
tempMetrics = new Set<string>();
|
||||
fields: Fields = {};
|
||||
pageIndex: number = 1;
|
||||
pageSize: number = 8;
|
||||
total: number = 0;
|
||||
|
||||
ngOnInit() {
|
||||
this.loadTabs();
|
||||
}
|
||||
|
||||
sync() {
|
||||
this.loadData(this.pageIndex - 1, this.pageSize);
|
||||
}
|
||||
|
||||
onNewBulletinDefine() {
|
||||
this.resetManageModalData();
|
||||
this.isManageModalAdd = true;
|
||||
this.isManageModalVisible = true;
|
||||
this.isManageModalOkLoading = false;
|
||||
}
|
||||
|
||||
onEditBulletinDefine() {
|
||||
if (this.currentDefine) {
|
||||
this.define = this.currentDefine;
|
||||
this.onAppChange(this.define.app);
|
||||
// this.tempMetrics.add(...this.define.fields.keys());
|
||||
this.isManageModalAdd = false;
|
||||
this.isManageModalVisible = true;
|
||||
this.isManageModalOkLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
deleteBulletinDefines(defineNames: string[]) {
|
||||
if (defineNames == null || defineNames.length == 0) {
|
||||
this.notifySvc.warning(this.i18nSvc.fanyi('common.notify.no-select-delete'), '');
|
||||
return;
|
||||
}
|
||||
const deleteDefines$ = this.bulletinDefineSvc.deleteBulletinDefines(defineNames).subscribe(
|
||||
message => {
|
||||
deleteDefines$.unsubscribe();
|
||||
if (message.code === 0) {
|
||||
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.delete-success'), '');
|
||||
this.loadTabs();
|
||||
} else {
|
||||
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.delete-fail'), message.msg);
|
||||
}
|
||||
},
|
||||
error => {
|
||||
deleteDefines$.unsubscribe();
|
||||
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.delete-fail'), error.msg);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
isManageModalVisible = false;
|
||||
isManageModalOkLoading = false;
|
||||
isManageModalAdd = true;
|
||||
define: BulletinDefine = new BulletinDefine();
|
||||
currentDefine!: BulletinDefine | null;
|
||||
|
||||
onManageModalCancel() {
|
||||
this.isManageModalVisible = false;
|
||||
}
|
||||
|
||||
resetManageModalData() {
|
||||
this.define = new BulletinDefine();
|
||||
this.define.monitorIds = [];
|
||||
this.hierarchies = [];
|
||||
this.treeNodes = [];
|
||||
}
|
||||
|
||||
onManageModalOk() {
|
||||
this.isManageModalOkLoading = true;
|
||||
this.define.fields = this.fields;
|
||||
if (this.isManageModalAdd) {
|
||||
const modalOk$ = this.bulletinDefineSvc
|
||||
.newBulletinDefine(this.define)
|
||||
.pipe(
|
||||
finalize(() => {
|
||||
modalOk$.unsubscribe();
|
||||
this.isManageModalOkLoading = false;
|
||||
})
|
||||
)
|
||||
.subscribe(
|
||||
message => {
|
||||
if (message.code === 0) {
|
||||
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.new-success'), '');
|
||||
this.isManageModalVisible = false;
|
||||
this.resetManageModalData();
|
||||
this.loadTabs();
|
||||
} else {
|
||||
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.new-fail'), message.msg);
|
||||
}
|
||||
},
|
||||
error => {
|
||||
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.new-fail'), error.msg);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
const modalOk$ = this.bulletinDefineSvc
|
||||
.editBulletinDefine(this.define)
|
||||
.pipe(
|
||||
finalize(() => {
|
||||
modalOk$.unsubscribe();
|
||||
this.isManageModalOkLoading = false;
|
||||
})
|
||||
)
|
||||
.subscribe(
|
||||
message => {
|
||||
if (message.code === 0) {
|
||||
this.isManageModalVisible = false;
|
||||
this.notifySvc.success(this.i18nSvc.fanyi('common.notify.edit-success'), '');
|
||||
this.loadData(this.pageIndex - 1, this.pageSize);
|
||||
} else {
|
||||
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.edit-fail'), message.msg);
|
||||
}
|
||||
},
|
||||
error => {
|
||||
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.edit-fail'), error.msg);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
onSearchAppDefines(): void {
|
||||
this.appDefineSvc
|
||||
.getAppDefines(this.i18nSvc.defaultLang)
|
||||
.pipe()
|
||||
.subscribe(
|
||||
message => {
|
||||
if (message.code === 0) {
|
||||
this.appMap = message.data;
|
||||
this.appEntries = Object.entries(this.appMap).map(([key, value]) => ({ key, value }));
|
||||
if (this.appEntries != null) {
|
||||
this.isAppListLoading = true;
|
||||
}
|
||||
} else {
|
||||
console.warn(message.msg);
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.warn(error.msg);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
onSearchMonitorsByApp(app: string): void {
|
||||
this.monitorSvc
|
||||
.getMonitorsByApp(app)
|
||||
.pipe()
|
||||
.subscribe(
|
||||
message => {
|
||||
if (message.code === 0) {
|
||||
this.monitors = message.data;
|
||||
if (this.monitors != null) {
|
||||
this.isMonitorListLoading = true;
|
||||
}
|
||||
} else {
|
||||
console.warn(message.msg);
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.warn(error.msg);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
onAppChange(app: string): void {
|
||||
if (app) {
|
||||
this.onSearchMonitorsByApp(app);
|
||||
this.onSearchTreeNodes(app);
|
||||
} else {
|
||||
this.hierarchies = [];
|
||||
this.treeNodes = [];
|
||||
}
|
||||
}
|
||||
|
||||
onSearchTreeNodes(app: string): void {
|
||||
this.appDefineSvc
|
||||
.getAppHierarchyByName(this.i18nSvc.defaultLang, app)
|
||||
.pipe()
|
||||
.subscribe(
|
||||
message => {
|
||||
if (message.code === 0) {
|
||||
this.hierarchies = this.transformToTransferItems(message.data);
|
||||
this.treeNodes = this.generateTree(this.hierarchies);
|
||||
} else {
|
||||
console.warn(message.msg);
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.warn(error.msg);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
transformToTransferItems(data: any[]): NzTreeNodeOptions[] {
|
||||
const result: NzTreeNodeOptions[] = [];
|
||||
let currentId = 1;
|
||||
|
||||
const traverse = (nodes: any[], parentKey: string | null = null, parentId: number | null = null) => {
|
||||
nodes.forEach(node => {
|
||||
const key = parentKey ? `${parentKey}` : node.value;
|
||||
const isRootNode = parentId === null;
|
||||
const item: NzTreeNodeOptions = {
|
||||
id: currentId++,
|
||||
key,
|
||||
value: node.value,
|
||||
title: node.label,
|
||||
isLeaf: node.isLeaf,
|
||||
parentId,
|
||||
disabled: isRootNode
|
||||
};
|
||||
result.push(item);
|
||||
|
||||
if (node.children) {
|
||||
traverse(node.children, key, item.id);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (data[0] && data[0].children) {
|
||||
data = data[0].children;
|
||||
traverse(data);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private generateTree(arr: NzTreeNodeOptions[]): NzTreeNodeOptions[] {
|
||||
const tree: NzTreeNodeOptions[] = [];
|
||||
const treeNodes: any = {};
|
||||
let leftElem: NzTreeNodeOptions;
|
||||
let rightElem: NzTreeNodeOptions;
|
||||
|
||||
for (let i = 0, len = arr.length; i < len; i++) {
|
||||
leftElem = arr[i];
|
||||
treeNodes[leftElem.id] = { ...leftElem };
|
||||
treeNodes[leftElem.id].children = [];
|
||||
}
|
||||
|
||||
for (const id in treeNodes) {
|
||||
if (treeNodes.hasOwnProperty(id)) {
|
||||
rightElem = treeNodes[id];
|
||||
if (rightElem.parentId) {
|
||||
treeNodes[rightElem.parentId].children.push(rightElem);
|
||||
} else {
|
||||
tree.push(rightElem);
|
||||
}
|
||||
}
|
||||
}
|
||||
return tree;
|
||||
}
|
||||
|
||||
treeCheckBoxChange(event: NzFormatEmitEvent, onItemSelect: (item: NzTreeNodeOptions) => void): void {
|
||||
this.checkBoxChange(event.node!, onItemSelect);
|
||||
}
|
||||
|
||||
checkBoxChange(node: NzTreeNode, onItemSelect: (item: NzTreeNodeOptions) => void): void {
|
||||
if (node.isDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.isChecked) {
|
||||
this.checkedNodeList.push(node);
|
||||
} else {
|
||||
const idx = this.checkedNodeList.indexOf(node);
|
||||
if (idx !== -1) {
|
||||
this.checkedNodeList.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
const item = this.hierarchies.find(w => w.id === node.origin.id);
|
||||
onItemSelect(item!);
|
||||
}
|
||||
|
||||
transferChange(ret: TransferChange): void {
|
||||
// add
|
||||
if (ret.to === 'right') {
|
||||
this.checkedNodeList.forEach(node => {
|
||||
node.isDisabled = true;
|
||||
node.isChecked = true;
|
||||
this.tempMetrics.add(node.key);
|
||||
|
||||
if (!this.fields[node.key]) {
|
||||
this.fields[node.key] = [];
|
||||
}
|
||||
if (!this.fields[node.key].includes(node.origin.value)) {
|
||||
this.fields[node.key].push(node.origin.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
// delete
|
||||
else if (ret.to === 'left') {
|
||||
this.checkedNodeList.forEach(node => {
|
||||
node.isDisabled = false;
|
||||
node.isChecked = false;
|
||||
this.tempMetrics.delete(node.key);
|
||||
|
||||
if (this.fields[node.key]) {
|
||||
const index = this.fields[node.key].indexOf(node.origin.value);
|
||||
if (index > -1) {
|
||||
this.fields[node.key].splice(index, 1);
|
||||
}
|
||||
// 如果该 key 下的数组为空,则删除该 key
|
||||
if (this.fields[node.key].length === 0) {
|
||||
delete this.fields[node.key];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
loadTabs() {
|
||||
const allNames$ = this.bulletinDefineSvc.getAllNames().subscribe(
|
||||
message => {
|
||||
allNames$.unsubscribe();
|
||||
if (message.code === 0) {
|
||||
this.tabs = message.data;
|
||||
if (this.tabs != null) {
|
||||
this.bulletinName = this.tabs[0];
|
||||
}
|
||||
this.loadData(this.pageIndex - 1, this.pageSize);
|
||||
} else {
|
||||
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.get-fail'), message.msg);
|
||||
}
|
||||
},
|
||||
error => {
|
||||
allNames$.unsubscribe();
|
||||
this.notifySvc.error(this.i18nSvc.fanyi('common.notify.get-fail'), error.msg);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
loadData(page: number, size: number) {
|
||||
this.tableLoading = true;
|
||||
this.metricsData = [];
|
||||
this.currentDefine = null;
|
||||
this.metrics = new Set<string>();
|
||||
if (this.bulletinName != null) {
|
||||
const defineData$ = this.bulletinDefineSvc.getBulletinDefine(this.bulletinName).subscribe(
|
||||
message => {
|
||||
if (message.code === 0) {
|
||||
this.currentDefine = message.data;
|
||||
|
||||
const metricData$ = this.bulletinDefineSvc.getMonitorMetricsData(this.bulletinName, page, size).subscribe(
|
||||
message => {
|
||||
metricData$.unsubscribe();
|
||||
if (message.code === 0 && message.data) {
|
||||
(this.metricsData = message.data.content).forEach((item: any) => {
|
||||
item.metrics.forEach((metric: any) => {
|
||||
this.metrics.add(metric.name);
|
||||
});
|
||||
});
|
||||
} else if (message.code !== 0) {
|
||||
this.notifySvc.warning(`${message.msg}`, '');
|
||||
console.info(`${message.msg}`);
|
||||
}
|
||||
this.tableLoading = false;
|
||||
},
|
||||
error => {
|
||||
console.error(error.msg);
|
||||
metricData$.unsubscribe();
|
||||
this.tableLoading = false;
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.notifySvc.warning(`${message.msg}`, '');
|
||||
console.info(`${message.msg}`);
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.error(error.msg);
|
||||
defineData$.unsubscribe();
|
||||
this.tableLoading = false;
|
||||
}
|
||||
);
|
||||
}
|
||||
this.tableLoading = false;
|
||||
}
|
||||
|
||||
getKeys(metricName: string): string[] {
|
||||
const result = new Set<string>();
|
||||
this.metricsData.forEach((item: any) => {
|
||||
item.metrics.forEach((metric: any) => {
|
||||
if (metric.name === metricName) {
|
||||
metric.fields.forEach((fieldGroup: any) => {
|
||||
fieldGroup.forEach((field: any) => {
|
||||
result.add(field.key);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
return Array.from(result);
|
||||
}
|
||||
|
||||
onTablePageChange(params: NzTableQueryParams): void {
|
||||
const { pageSize, pageIndex } = params;
|
||||
|
||||
if (pageIndex !== this.pageIndex || pageSize !== this.pageSize) {
|
||||
this.pageIndex = pageIndex;
|
||||
this.pageSize = pageSize;
|
||||
this.loadData(pageIndex - 1, pageSize);
|
||||
}
|
||||
}
|
||||
|
||||
isBatchDeleteModalVisible: boolean = false;
|
||||
isBatchDeleteModalOkLoading: boolean = false;
|
||||
|
||||
onDeleteBulletinDefines() {
|
||||
this.modal.confirm({
|
||||
nzTitle: this.i18nSvc.fanyi('common.confirm.delete'),
|
||||
nzOkText: this.i18nSvc.fanyi('common.button.ok'),
|
||||
nzCancelText: this.i18nSvc.fanyi('common.button.cancel'),
|
||||
nzOkDanger: true,
|
||||
nzOkType: 'primary',
|
||||
nzClosable: false,
|
||||
nzOnOk: () => this.deleteBulletinDefines([this.bulletinName])
|
||||
});
|
||||
}
|
||||
|
||||
onBatchDeleteBulletinDefines() {
|
||||
this.isBatchDeleteModalVisible = true;
|
||||
}
|
||||
|
||||
onBatchDeleteModalCancel() {
|
||||
this.isBatchDeleteModalVisible = false;
|
||||
}
|
||||
|
||||
onBatchDeleteModalOk() {
|
||||
this.deleteBulletinDefines(this.deleteBulletinNames);
|
||||
this.isBatchDeleteModalOkLoading = false;
|
||||
this.isBatchDeleteModalVisible = false;
|
||||
}
|
||||
|
||||
protected readonly Array = Array;
|
||||
|
||||
onTabChange($event: number) {
|
||||
this.bulletinName = this.tabs[$event];
|
||||
this.metricsData = [];
|
||||
this.loadData(this.pageIndex - 1, this.pageSize);
|
||||
console.log(this.metricsData);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import { DetectAuthGuard } from '../core/guard/detect-auth-guard';
|
||||
import { LayoutBasicComponent } from '../layout/basic/basic.component';
|
||||
import { LayoutBlankComponent } from '../layout/blank/blank.component';
|
||||
import { LayoutPassportComponent } from '../layout/passport/passport.component';
|
||||
import { BulletinComponent } from './bulletin/bulletin.component';
|
||||
import { DashboardComponent } from './dashboard/dashboard.component';
|
||||
import { UserLockComponent } from './passport/lock/lock.component';
|
||||
import { UserLoginComponent } from './passport/login/login.component';
|
||||
@@ -19,6 +20,7 @@ const routes: Routes = [
|
||||
children: [
|
||||
{ path: '', redirectTo: 'dashboard', pathMatch: 'full' },
|
||||
{ path: 'dashboard', component: DashboardComponent, data: { titleI18n: 'menu.dashboard' } },
|
||||
{ path: 'bulletin', component: BulletinComponent, data: { titleI18n: 'menu.dashboard' } },
|
||||
{ path: 'exception', loadChildren: () => import('./exception/exception.module').then(m => m.ExceptionModule) },
|
||||
{ path: 'monitors', loadChildren: () => import('./monitor/monitor.module').then(m => m.MonitorModule) },
|
||||
{ path: 'alert', loadChildren: () => import('./alert/alert.module').then(m => m.AlertModule) },
|
||||
|
||||
@@ -1,24 +1,32 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule, Type } from '@angular/core';
|
||||
// eslint-disable-next-line import/order
|
||||
import { SharedModule } from '@shared';
|
||||
|
||||
import { TagCloudComponent } from 'angular-tag-cloud-module';
|
||||
import { NzCascaderModule } from 'ng-zorro-antd/cascader';
|
||||
import { NzCollapseModule } from 'ng-zorro-antd/collapse';
|
||||
import { NzDividerModule } from 'ng-zorro-antd/divider';
|
||||
import { NzListModule } from 'ng-zorro-antd/list';
|
||||
import { NzRadioModule } from 'ng-zorro-antd/radio';
|
||||
import { NzSwitchComponent } from 'ng-zorro-antd/switch';
|
||||
import { NzTagModule } from 'ng-zorro-antd/tag';
|
||||
import { NzTimelineModule } from 'ng-zorro-antd/timeline';
|
||||
import { NzTransferModule } from 'ng-zorro-antd/transfer';
|
||||
import { NzTreeComponent } from 'ng-zorro-antd/tree';
|
||||
import { NzUploadModule } from 'ng-zorro-antd/upload';
|
||||
import { NgxEchartsModule } from 'ngx-echarts';
|
||||
import { SlickCarouselModule } from 'ngx-slick-carousel';
|
||||
|
||||
import { LayoutModule } from '../layout/layout.module';
|
||||
import { BulletinComponent } from './bulletin/bulletin.component';
|
||||
import { DashboardComponent } from './dashboard/dashboard.component';
|
||||
import { UserLockComponent } from './passport/lock/lock.component';
|
||||
import { UserLoginComponent } from './passport/login/login.component';
|
||||
import { RouteRoutingModule } from './routes-routing.module';
|
||||
import { StatusPublicComponent } from './status-public/status-public.component';
|
||||
|
||||
const COMPONENTS: Array<Type<void>> = [DashboardComponent, UserLoginComponent, UserLockComponent, StatusPublicComponent];
|
||||
const COMPONENTS: Array<Type<void>> = [DashboardComponent, UserLoginComponent, UserLockComponent, StatusPublicComponent, BulletinComponent];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -32,7 +40,14 @@ const COMPONENTS: Array<Type<void>> = [DashboardComponent, UserLoginComponent, U
|
||||
NzDividerModule,
|
||||
LayoutModule,
|
||||
NzCollapseModule,
|
||||
NzListModule
|
||||
NzListModule,
|
||||
CommonModule,
|
||||
NzRadioModule,
|
||||
NzUploadModule,
|
||||
NzCascaderModule,
|
||||
NzTransferModule,
|
||||
NzSwitchComponent,
|
||||
NzTreeComponent
|
||||
],
|
||||
declarations: COMPONENTS
|
||||
})
|
||||
|
||||
@@ -97,4 +97,22 @@ export class AppDefineService {
|
||||
const options = { params: httpParams };
|
||||
return this.http.get<Message<any>>(app_hierarchy, options);
|
||||
}
|
||||
|
||||
public getAppHierarchyByName(lang: string | undefined, app: string): Observable<Message<any>> {
|
||||
if (lang == undefined) {
|
||||
lang = 'en_US';
|
||||
}
|
||||
let httpParams = new HttpParams().append('lang', lang);
|
||||
const options = { params: httpParams };
|
||||
return this.http.get<Message<any>>(`${app_hierarchy}/${app}`, options);
|
||||
}
|
||||
|
||||
public getAppDefines(lang: string | undefined): Observable<Message<any>> {
|
||||
if (lang == undefined) {
|
||||
lang = 'en_US';
|
||||
}
|
||||
let httpParams = new HttpParams().append('lang', lang);
|
||||
const options = { params: httpParams };
|
||||
return this.http.get<Message<any>>(`/apps/defines`, options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.
|
||||
*/
|
||||
|
||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { BulletinDefine } from '../pojo/BulletinDefine';
|
||||
import { Message } from '../pojo/Message';
|
||||
import { Monitor } from '../pojo/Monitor';
|
||||
import { Page } from '../pojo/Page';
|
||||
|
||||
const bulletin_define_uri = '/bulletin';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class BulletinDefineService {
|
||||
constructor(private http: HttpClient) {}
|
||||
|
||||
public newBulletinDefine(body: BulletinDefine) {
|
||||
return this.http.post<Message<any>>(bulletin_define_uri, body);
|
||||
}
|
||||
|
||||
public editBulletinDefine(body: BulletinDefine) {
|
||||
return this.http.put<Message<any>>(bulletin_define_uri, body);
|
||||
}
|
||||
|
||||
public getBulletinDefine(name: string) {
|
||||
return this.http.get<Message<any>>(`${bulletin_define_uri}/${name}`);
|
||||
}
|
||||
|
||||
public deleteBulletinDefines(names: string[]): Observable<Message<any>> {
|
||||
let params = new HttpParams();
|
||||
names.forEach(name => {
|
||||
params = params.append('names', name);
|
||||
});
|
||||
|
||||
return this.http.delete<Message<any>>(bulletin_define_uri, { params });
|
||||
}
|
||||
|
||||
public getMonitorMetricsData(
|
||||
name: string,
|
||||
pageIndex: number,
|
||||
pageSize: number,
|
||||
sortField?: string | null,
|
||||
sortOrder?: string | null
|
||||
): Observable<Message<Page<Monitor>>> {
|
||||
pageIndex = pageIndex ? pageIndex : 0;
|
||||
pageSize = pageSize ? pageSize : 8;
|
||||
// 注意HttpParams是不可变对象 需要保存set后返回的对象为最新对象
|
||||
let httpParams = new HttpParams();
|
||||
httpParams = httpParams.appendAll({
|
||||
name: name,
|
||||
pageIndex: pageIndex,
|
||||
pageSize: pageSize
|
||||
});
|
||||
if (sortField != null && sortOrder != null) {
|
||||
httpParams = httpParams.appendAll({
|
||||
sort: sortField,
|
||||
order: sortOrder == 'ascend' ? 'asc' : 'desc'
|
||||
});
|
||||
}
|
||||
const options = { params: httpParams };
|
||||
return this.http.get<Message<any>>(`${bulletin_define_uri}/metrics`, options);
|
||||
}
|
||||
|
||||
public getAllNames(): Observable<Message<string[]>> {
|
||||
return this.http.get<Message<string[]>>(`${bulletin_define_uri}/names`);
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,10 @@ export class MonitorService {
|
||||
return this.http.put<Message<any>>(monitor_uri, body);
|
||||
}
|
||||
|
||||
public getMonitorByApp(app: string): Observable<Message<any>> {
|
||||
return this.http.get<Message<any>>(`${monitor_uri}/metric/${app}`);
|
||||
}
|
||||
|
||||
public deleteMonitor(monitorId: number): Observable<Message<any>> {
|
||||
return this.http.delete<Message<any>>(`${monitor_uri}/${monitorId}`);
|
||||
}
|
||||
|
||||
@@ -36,6 +36,12 @@
|
||||
"icon": "anticon-laptop",
|
||||
"link": "/monitors"
|
||||
},
|
||||
{
|
||||
"text": "Bulletin",
|
||||
"i18n": "menu.monitor.bulletin",
|
||||
"icon": "anticon-book",
|
||||
"link": "/bulletin"
|
||||
},
|
||||
{
|
||||
"text": "Define",
|
||||
"i18n": "menu.advanced.define",
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"monitor": {
|
||||
"": "Monitoring",
|
||||
"center": "Monitor Center",
|
||||
"bulletin": "Bulletin",
|
||||
"service": "Service Monitor",
|
||||
"db": "DB Monitor",
|
||||
"os": "OS Monitor",
|
||||
@@ -43,6 +44,20 @@
|
||||
"silence": "Alarm Silence",
|
||||
"dispatch": "Notification"
|
||||
},
|
||||
"bulletin": {
|
||||
"new": "Add New Bulletin Item",
|
||||
"edit": "Edit Bulletin Item",
|
||||
"delete": "Delete Bulletin Item",
|
||||
"batch.delete": "Batch delete Bulletin Item",
|
||||
"name": "Bulletin Name",
|
||||
"name.placeholder": "Please enter a custom bulletin name",
|
||||
"monitor.type": "Monitor Type",
|
||||
"monitor.name": "Monitor Task Name",
|
||||
"monitor.metrics": "Monitor Metrics",
|
||||
"help.message.content": "Custom Monitoring Bulletin",
|
||||
"help.content": "Custom monitoring bulletin, displaying selected metrics of a specific monitor in table form",
|
||||
"help.link": ""
|
||||
},
|
||||
"advanced": {
|
||||
"": "Advanced",
|
||||
"collector": "Collector Cluster",
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"monitor": {
|
||||
"": "监控",
|
||||
"center": "监控中心",
|
||||
"bulletin": "自定义看板",
|
||||
"service": "应用服务监控",
|
||||
"db": "数据库监控",
|
||||
"os": "操作系统监控",
|
||||
@@ -130,6 +131,20 @@
|
||||
"2": "警告告警"
|
||||
}
|
||||
},
|
||||
"bulletin": {
|
||||
"new": "新增看板项",
|
||||
"edit": "编辑看板项",
|
||||
"delete": "删除看板项",
|
||||
"batch.delete": "批量删除看板项",
|
||||
"name": "看板名称",
|
||||
"name.placeholder": "请输入自定义看板名称",
|
||||
"monitor.type": "监控类型",
|
||||
"monitor.name": "监控任务名称",
|
||||
"monitor.metrics": "监控指标",
|
||||
"help.message.content": "自定义监控看板",
|
||||
"help.content": "自定义监控看板,以表格形式展示某种监控的自选指标",
|
||||
"help.link": ""
|
||||
},
|
||||
"question.link": "https://hertzbeat.apache.org/zh-cn/docs/help/issue",
|
||||
"alert.setting.new": "新增阈值规则",
|
||||
"alert.setting.edit": "编辑阈值规则",
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"monitor": {
|
||||
"": "監控",
|
||||
"center": "監控中心",
|
||||
"bulletin": "自定義看板",
|
||||
"service": "應用服務監控",
|
||||
"db": "數據庫監控",
|
||||
"os": "操作系統監控",
|
||||
@@ -43,6 +44,20 @@
|
||||
"silence": "告警靜默",
|
||||
"dispatch": "消息通知"
|
||||
},
|
||||
"bulletin": {
|
||||
"new": "新增看板項",
|
||||
"edit": "編輯看板項",
|
||||
"delete": "刪除看板項",
|
||||
"batch.delete": "批量刪除看板項",
|
||||
"name": "看板名稱",
|
||||
"name.placeholder": "請輸入自定義看板名稱",
|
||||
"monitor.type": "監控類型",
|
||||
"monitor.name": "監控任務名稱",
|
||||
"monitor.metrics": "監控指標",
|
||||
"help.message.content": "自定義監控看板",
|
||||
"help.content": "自定義監控看板,以表格形式展示某種監控的自選指標",
|
||||
"help.link": ""
|
||||
},
|
||||
"advanced": {
|
||||
"": "高级",
|
||||
"collector": "採集集群",
|
||||
|
||||
Reference in New Issue
Block a user